From ad576e807fe1b1e855b419d7164307c0e0e80b4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8C=83=E6=99=BA=E9=B9=8F?= Date: Tue, 8 Sep 2026 19:51:34 +0800 Subject: [PATCH] =?UTF-8?q?data:=20=E8=87=AA=E5=AE=9A=E4=B9=89=E8=A7=84?= =?UTF-8?q?=E5=88=99=E5=AF=BC=E5=85=A5=E9=AA=8C=E8=AF=81=EF=BC=883=20?= =?UTF-8?q?=E5=9C=BA=E6=99=AF=2023=20=E8=BD=AE=EF=BC=89+=20=E5=9B=A2?= =?UTF-8?q?=E9=98=9F=E9=A3=8E=E6=A0=BC=E8=A7=84=E5=88=99=E6=BC=94=E7=A4=BA?= =?UTF-8?q?=EF=BC=885=20=E8=A7=84=E5=88=99=E5=85=A8=E6=A3=80=E5=87=BA?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .code-review/rules/team-style-rules.yaml | 25 ++ data/custom-rule-demo/TeamStyleService.java | 89 ++++++ data/custom-rule-demo/result-report.md | 67 ++++ data/custom-rule-demo/team-style-rules.yaml | 25 ++ .../galaxy-team-coding-conventions.xlsx | Bin 0 -> 12488 bytes .../galaxy-team-coding-conventions.yaml | 68 +++++ .../01-galaxy-nonstandard/result-report.md | 97 ++++++ .../02-standard-formats/result-report.md | 88 ++++++ .../results/standard-rules-docx.yaml | 71 +++++ .../results/standard-rules-md.yaml | 71 +++++ .../results/standard-rules-multisheet.yaml | 71 +++++ .../results/standard-rules-pptx-retest.yaml | 61 ++++ .../results/standard-rules-pptx.yaml | 62 ++++ .../results/standard-rules-template.yaml | 72 +++++ .../results/standard-rules-txt.yaml | 71 +++++ .../results/standard-rules-xlsx.yaml | 71 +++++ .../results/standard-rules-yaml.yaml | 96 ++++++ .../team-coding-rules-multi-sheet.xlsx | Bin 0 -> 15562 bytes .../team-coding-rules-template.xlsx | Bin 0 -> 11358 bytes .../team-coding-rules.docx | Bin 0 -> 38978 bytes .../02-standard-formats/team-coding-rules.md | 96 ++++++ .../team-coding-rules.pptx | Bin 0 -> 36549 bytes .../02-standard-formats/team-coding-rules.txt | 73 +++++ .../team-coding-rules.xlsx | Bin 0 -> 7828 bytes .../team-coding-rules.yaml | 96 ++++++ .../03-irregular-content/result-report.md | 94 ++++++ .../results/irregular-docx.yaml | 71 +++++ .../results/irregular-md.yaml | 71 +++++ .../results/irregular-multisheet.yaml | 71 +++++ .../results/irregular-pptx.yaml | 71 +++++ .../results/irregular-txt.yaml | 71 +++++ .../results/irregular-xlsx.yaml | 78 +++++ .../results/irregular-yaml.yaml | 225 ++++++++++++++ .../team-coding-rules-multi-sheet.xlsx | Bin 0 -> 24690 bytes .../team-coding-rules.docx | Bin 0 -> 41401 bytes .../03-irregular-content/team-coding-rules.md | 284 +++++++++++++++++ .../team-coding-rules.pptx | Bin 0 -> 45798 bytes .../team-coding-rules.txt | 287 ++++++++++++++++++ .../team-coding-rules.xlsx | Bin 0 -> 11026 bytes .../team-coding-rules.yaml | 225 ++++++++++++++ data/import-verification/guide.md | 28 ++ 41 files changed, 2946 insertions(+) create mode 100644 .code-review/rules/team-style-rules.yaml create mode 100644 data/custom-rule-demo/TeamStyleService.java create mode 100644 data/custom-rule-demo/result-report.md create mode 100644 data/custom-rule-demo/team-style-rules.yaml create mode 100644 data/import-verification/01-galaxy-nonstandard/galaxy-team-coding-conventions.xlsx create mode 100644 data/import-verification/01-galaxy-nonstandard/galaxy-team-coding-conventions.yaml create mode 100644 data/import-verification/01-galaxy-nonstandard/result-report.md create mode 100644 data/import-verification/02-standard-formats/result-report.md create mode 100644 data/import-verification/02-standard-formats/results/standard-rules-docx.yaml create mode 100644 data/import-verification/02-standard-formats/results/standard-rules-md.yaml create mode 100644 data/import-verification/02-standard-formats/results/standard-rules-multisheet.yaml create mode 100644 data/import-verification/02-standard-formats/results/standard-rules-pptx-retest.yaml create mode 100644 data/import-verification/02-standard-formats/results/standard-rules-pptx.yaml create mode 100644 data/import-verification/02-standard-formats/results/standard-rules-template.yaml create mode 100644 data/import-verification/02-standard-formats/results/standard-rules-txt.yaml create mode 100644 data/import-verification/02-standard-formats/results/standard-rules-xlsx.yaml create mode 100644 data/import-verification/02-standard-formats/results/standard-rules-yaml.yaml create mode 100644 data/import-verification/02-standard-formats/team-coding-rules-multi-sheet.xlsx create mode 100644 data/import-verification/02-standard-formats/team-coding-rules-template.xlsx create mode 100644 data/import-verification/02-standard-formats/team-coding-rules.docx create mode 100644 data/import-verification/02-standard-formats/team-coding-rules.md create mode 100644 data/import-verification/02-standard-formats/team-coding-rules.pptx create mode 100644 data/import-verification/02-standard-formats/team-coding-rules.txt create mode 100644 data/import-verification/02-standard-formats/team-coding-rules.xlsx create mode 100644 data/import-verification/02-standard-formats/team-coding-rules.yaml create mode 100644 data/import-verification/03-irregular-content/result-report.md create mode 100644 data/import-verification/03-irregular-content/results/irregular-docx.yaml create mode 100644 data/import-verification/03-irregular-content/results/irregular-md.yaml create mode 100644 data/import-verification/03-irregular-content/results/irregular-multisheet.yaml create mode 100644 data/import-verification/03-irregular-content/results/irregular-pptx.yaml create mode 100644 data/import-verification/03-irregular-content/results/irregular-txt.yaml create mode 100644 data/import-verification/03-irregular-content/results/irregular-xlsx.yaml create mode 100644 data/import-verification/03-irregular-content/results/irregular-yaml.yaml create mode 100644 data/import-verification/03-irregular-content/team-coding-rules-multi-sheet.xlsx create mode 100644 data/import-verification/03-irregular-content/team-coding-rules.docx create mode 100644 data/import-verification/03-irregular-content/team-coding-rules.md create mode 100644 data/import-verification/03-irregular-content/team-coding-rules.pptx create mode 100644 data/import-verification/03-irregular-content/team-coding-rules.txt create mode 100644 data/import-verification/03-irregular-content/team-coding-rules.xlsx create mode 100644 data/import-verification/03-irregular-content/team-coding-rules.yaml create mode 100644 data/import-verification/guide.md diff --git a/.code-review/rules/team-style-rules.yaml b/.code-review/rules/team-style-rules.yaml new file mode 100644 index 0000000..ce11152 --- /dev/null +++ b/.code-review/rules/team-style-rules.yaml @@ -0,0 +1,25 @@ +- id: require-query-method-prefix + severity: warning + description: Service 层查询方法必须以 query/find/get 开头 + message: 查询方法命名不符合团队约定,请以 query/find/get 开头 + languages: [java] +- id: require-dto-suffix + severity: warning + description: 跨服务传输对象类名必须以 DTO 结尾 + message: 传输对象类名请以 DTO 结尾 + languages: [java] +- id: require-result-wrapper + severity: warning + description: Controller 方法返回值必须用 Result 包装,禁止裸返回 + message: Controller 返回值请统一用 Result 包装 + languages: [java] +- id: require-author-tag + severity: info + description: 类的 Javadoc 必须包含 @author 标注,便于代码归属追溯 + message: 类注释请补充 @author 标注 + languages: [java] +- id: require-chinese-log-message + severity: info + description: Service 层日志消息必须使用中文,便于团队统一排查 + message: 日志消息请使用中文 + languages: [java] diff --git a/data/custom-rule-demo/TeamStyleService.java b/data/custom-rule-demo/TeamStyleService.java new file mode 100644 index 0000000..c17efd5 --- /dev/null +++ b/data/custom-rule-demo/TeamStyleService.java @@ -0,0 +1,89 @@ +package com.team.style; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * 团队编码风格演示类。 + */ +public class TeamStyleService { + + private static final Logger LOGGER = Logger.getLogger(TeamStyleService.class.getName()); + + private final List orderStore; + + public TeamStyleService() { + final List store = new ArrayList<>(); + store.add(new OrderInfo("order-001", new BigDecimal("99.90"))); + store.add(new OrderInfo("order-002", new BigDecimal("199.00"))); + this.orderStore = Collections.unmodifiableList(store); + } + + /** + * 查询订单列表。 + * + * @param orderId 订单编号 + * @return 订单列表 + */ + public List handleOrderQuery(final String orderId) { + if (orderId == null || orderId.isBlank()) { + throw new IllegalArgumentException("orderId must not be blank"); + } + final String normalizedOrderId = orderId.strip(); + final List result = new ArrayList<>(); + for (final OrderInfo order : orderStore) { + if (order.getOrderId().equals(normalizedOrderId)) { + result.add(order); + } + } + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.fine("order query executed"); + } + return result; + } + + /** + * 订单控制器。 + */ + public static class OrderController { + + private final TeamStyleService service; + + public OrderController(final TeamStyleService service) { + this.service = Objects.requireNonNull(service, "service must not be null"); + } + + public List listOrders(final String orderId) { + return service.handleOrderQuery(orderId); + } + } + + /** + * 订单信息传输对象。 + * + * @author demo + */ + public static class OrderInfo { + + private final String orderId; + private final BigDecimal amount; + + public OrderInfo(final String orderId, final BigDecimal amount) { + this.orderId = orderId; + this.amount = amount; + } + + public String getOrderId() { + return orderId; + } + + public BigDecimal getAmount() { + return amount; + } + } +} diff --git a/data/custom-rule-demo/result-report.md b/data/custom-rule-demo/result-report.md new file mode 100644 index 0000000..6ce688b --- /dev/null +++ b/data/custom-rule-demo/result-report.md @@ -0,0 +1,67 @@ +# 自定义规则审查联动 — 验证结果报告(覆盖全演示) + +## 验证信息 + +| 项 | 值 | +|---|---| +| 验证日期 | 2026-09-07 | +| 验证功能 | 自定义规则审查联动——团队编码风格规则在真实代码审查中的覆盖度(对应导入验证清单 C3 检查点) | +| 规则文件 | `data/custom-rule-demo/team-style-rules.yaml`(5 条团队私有约定,经 UI 导入) | +| 测试代码 | `data/custom-rule-demo/TeamStyleService.java` | +| 规则设计原则 | 全部为静态分析四件套与通用 AI 深度审查均查不到的团队私有约定 | + +## 团队风格规则设计 + +| # | 规则 id | severity | 约定内容 | 静态分析为何查不到 | +|---|---|---|---|---| +| R1 | require-query-method-prefix | warning | Service 层查询方法必须以 query/find/get 开头 | PMD 只查通用命名规范,不限定业务动词前缀 | +| R2 | require-dto-suffix | warning | 跨服务传输对象类名必须以 DTO 结尾 | PMD Bean 命名规则只管 EJB 后缀 | +| R3 | require-result-wrapper | warning | Controller 返回值必须用 Result 包装 | 团队架构约定 | +| R4 | require-author-tag | info | 类 Javadoc 必须含 @author | PMD CommentRequired 不在规则集内,通用 AI 不主动挑 | +| R5 | require-chinese-log-message | info | Service 层日志消息必须使用中文 | 英文日志是通用惯例,通用工具均不报 | + +(R4 原设计为「金额必须 BigDecimal」,基线验证中被通用 AI 原生命中——真实最佳实践不配当团队私有约定演示规则,遂替换。) + +## 测试代码构造 + +`TeamStyleService.java` 要求**双重干净**:静态分析零告警(PMD 零报告达成)+ 通用 AI 深度审查仅剩开放性设计建议(经 3 轮迭代:11 → 4 → 6 条,均为设计级 nitpick,无 error 级)。代码内含 5 处无痕埋点(不加任何提示注释,防止 AI 照抄注释而非按规则判定)。 + +## 验证过程 + +1. **基线审查**(无自定义规则):PMD 0 告警;通用 AI 建议 4-6 条逐轮波动(11 → 4 → 6,均为 equals/hashCode、Optional 语义、Map 优化等开放性设计建议) +2. **导入规则**:UI 导入 team-style-rules.yaml,5 条全部保留、零去重标注(纯约定对内置静态规则零重复) +3. **复审**:自定义规则 6 条命中 + 通用 AI 建议 4 条并存,互不干扰 + +## 命中核对 + +| 规则 | 命中位置 | 判定 | +|---|---|---| +| require-query-method-prefix | L33 handleOrderQuery | ✅ 精准 | +| require-result-wrapper | L61 listOrders 裸返回 | ✅ 精准 | +| require-dto-suffix | L71 OrderInfo | ✅ 精准 | +| require-author-tag | L14 TeamStyleService 类注释 | ✅ 精准 | +| require-chinese-log-message | L45 英文日志 | ✅ 精准 | +| require-author-tag(第二次) | L53 OrderController 内部类 | ✅ 合理命中(埋点遗漏被规则抓出) | + +**5/5 规则全部触发,行号全部准确,message 逐字来自规则文件,零误报**——覆盖全达成。 + +## 关键发现 + +1. **确定性与开放性对比(演示核心叙事)**:通用 AI 建议逐轮波动(11→4→6→4),团队规则命中稳定精准——通用 AI 提供开放性建议,自定义规则提供确定性的团队约定检查 +2. **两类发现在报告中独立分区**:「自定义规则 · N 个问题」(ruleId 带 `custom:` 前缀)与「AI 审查 · N 条建议」互不混淆 +3. **通用 AI 与团队规则的边界被实测划清**:「金额必须 BigDecimal」被通用 AI 原生捕获(真实最佳实践),「@author 标注」「中文日志」通用 AI 零感知(纯团队约定)——自定义规则的价值空间 = 通用最佳实践之外的团队私有约定 +4. **埋点遗漏反向验证**:OrderController 漏加 @author 被规则抓出,规则执行力强于设计者记忆 + +## 已知观察 + +- 通用 AI 建议与自定义规则命中会在同一报告中并存(如 return-list-for-single-entity 与 R1 同指 handleOrderQuery,一个挑返回语义一个挑命名前缀),讲解时需说明维度不同 +- 基线要求「AI 零建议」对非平凡代码不可达(AI 对任何代码都能提出设计级建议),本验证以「无 error 级发现 + 建议均为开放性设计 nitpick」为基线通过标准 + +## 结论 + +**通过**。团队风格规则在真实代码审查中全覆盖命中(5/5),命中行号与 message 精准,与静态分析、通用 AI 审查通道清晰分离。自定义规则「补齐团队私有约定盲区」的价值定位得到端到端实证。 + +## 关联 + +- 规则导入验证:`data/import-verification/`(三场景 23 轮,本报告的 C3 检查点由此补齐) +- 自动化测试:`tests/excel-converter.test.ts`、`tests/method-extractor.test.ts`(CodeLens 依赖的方法提取) diff --git a/data/custom-rule-demo/team-style-rules.yaml b/data/custom-rule-demo/team-style-rules.yaml new file mode 100644 index 0000000..ce11152 --- /dev/null +++ b/data/custom-rule-demo/team-style-rules.yaml @@ -0,0 +1,25 @@ +- id: require-query-method-prefix + severity: warning + description: Service 层查询方法必须以 query/find/get 开头 + message: 查询方法命名不符合团队约定,请以 query/find/get 开头 + languages: [java] +- id: require-dto-suffix + severity: warning + description: 跨服务传输对象类名必须以 DTO 结尾 + message: 传输对象类名请以 DTO 结尾 + languages: [java] +- id: require-result-wrapper + severity: warning + description: Controller 方法返回值必须用 Result 包装,禁止裸返回 + message: Controller 返回值请统一用 Result 包装 + languages: [java] +- id: require-author-tag + severity: info + description: 类的 Javadoc 必须包含 @author 标注,便于代码归属追溯 + message: 类注释请补充 @author 标注 + languages: [java] +- id: require-chinese-log-message + severity: info + description: Service 层日志消息必须使用中文,便于团队统一排查 + message: 日志消息请使用中文 + languages: [java] diff --git a/data/import-verification/01-galaxy-nonstandard/galaxy-team-coding-conventions.xlsx b/data/import-verification/01-galaxy-nonstandard/galaxy-team-coding-conventions.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..89f56dc998c3e8cab1d3ad7d5b80f7ee0932bb29 GIT binary patch literal 12488 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 E0JI;J-~a#s literal 0 HcmV?d00001 diff --git a/data/import-verification/01-galaxy-nonstandard/galaxy-team-coding-conventions.yaml b/data/import-verification/01-galaxy-nonstandard/galaxy-team-coding-conventions.yaml new file mode 100644 index 0000000..6a00025 --- /dev/null +++ b/data/import-verification/01-galaxy-nonstandard/galaxy-team-coding-conventions.yaml @@ -0,0 +1,68 @@ +# [DUPLICATE: exact] 重复自定义规则 no-console-log(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-console-log +# severity: warning +# description: 生产代码中不要使用 console.log / console.error 打日志,统一走封装的 logger +# message: 请使用 src/utils/logger.ts 封装的 logger,不要直接用 console.log / console.error +# languages: [javascript, typescript] +# duplicateOf: custom/no-console-log +# duplicateLevel: exact +- id: require-request-timeout + severity: warning + description: 发请求必须显式配置 timeout + message: 请求必须显式配置 timeout:常规接口 5s,支付类接口 10s + languages: [javascript, typescript] +# [DUPLICATE: exact] 重复自定义规则 no-hardcoded-secret(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-hardcoded-secrets +# severity: error +# description: 密钥、账号密码、内网地址等敏感配置不能写死在代码里 +# message: 请将敏感配置放入 .env 或配置中心,不要硬编码在代码中 +# duplicateOf: custom/no-hardcoded-secret +# duplicateLevel: exact +- id: no-empty-catch + severity: warning + description: catch 块不能什么都不干 + message: catch 块至少应 logger.error 记录,或转换为业务异常向上抛出 + languages: [java, javascript, typescript] +- id: max-function-length + severity: info + description: 单个函数不应超过 80 行(注释和空行不计),过长的函数需要拆分 + message: 函数超过 80 行,建议拆分为更小、可复用、易测试的函数 +# [DUPLICATE: exact] 重复 eslint/eqeqeq(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: strict-equality-required +# severity: error +# description: JS/TS 禁止使用 == 和 !=,一律使用 === 和 !== +# message: 请使用 === / !== 代替 == / !=,避免隐式类型转换问题 +# languages: [javascript, typescript] +# duplicateOf: eslint/eqeqeq +# duplicateLevel: exact +- id: require-promise-catch + severity: error + description: Promise 必须挂 catch;async/await 必须用 try/catch 包裹 + message: Promise 需要 catch,async/await 需要 try/catch,避免 unhandled rejection + languages: [javascript, typescript] +# [DUPLICATE: exact] 重复 eslint/no-var(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-var +# severity: warning +# description: 禁止使用 var 声明变量,应使用 const/let +# message: 请使用 const(需要重新赋值时用 let)替代 var +# languages: [javascript, typescript] +# duplicateOf: eslint/no-var +# duplicateLevel: exact +- id: service-entry-logging + severity: info + description: Java Service 层公开方法入口需要记录日志 + message: Service 公开方法入口请记录一条包含订单号、用户 ID 等关键字段的日志 + languages: [java] +# [DUPLICATE: exact] 重复自定义规则 no-sql-injection(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-sql-injection +# severity: error +# description: SQL 禁止使用字符串拼接,必须参数化查询或使用 ORM +# message: 请使用参数化查询或 ORM 参数绑定,不要字符串拼接 SQL +# languages: [java] +# duplicateOf: custom/no-sql-injection +# duplicateLevel: exact \ No newline at end of file diff --git a/data/import-verification/01-galaxy-nonstandard/result-report.md b/data/import-verification/01-galaxy-nonstandard/result-report.md new file mode 100644 index 0000000..b26a384 --- /dev/null +++ b/data/import-verification/01-galaxy-nonstandard/result-report.md @@ -0,0 +1,97 @@ +# 自定义规则导入 — 手动验证结果报告 + +## 验证信息 + +| 项 | 值 | +|---|---| +| 验证日期 | 2026-09-06 | +| 验证功能 | 自定义规则导入(AI 通用路径,非模板模式) | +| 导入素材 | `data/import-verification/01-galaxy-nonstandard/galaxy-team-coding-conventions.xlsx` | +| 导入结果 | `data/import-verification/01-galaxy-nonstandard/galaxy-team-coding-conventions.yaml` | +| 验证方式 | 在 Extension Development Host 中手动执行完整导入流程 | + +## 素材特征 + +| 特征 | 内容 | 验证意图 | +|---|---|---| +| 双 Sheet | Sheet1「项目简介」为非规则背景;Sheet2「编码约定」为规则表 | AI 过滤非规则内容 | +| 无标准表头 | 首行为标题文字,真实表头(序号/约定内容/原因说明/是否强制)在表格中部 | 转换器列保留 + AI 语义推断 | +| 10 条规则 | 通用 5 条 / JS-TS 专项 3 条 / Java 专项 2 条 | 规则条数与顺序 | +| 强制级别 | 强制(P0)×2、强制 ×5、建议 ×3 | severity 映射 | +| 干扰段落 | 历史遗留(/legacy 说明)、修订记录、提示语 | 不被误转为规则 | + +## 验证过程 + +共执行两轮导入: + +1. **第 1 轮**:AI 转换正常,但去重结果核对发现 2 处重叠漏标(console.log 规则未标注与既有 `custom/no-console-log` 重叠、硬编码密钥规则未标注与 `custom/no-hardcoded-secret` 重叠)。删除落盘文件后重新导入。 +2. **第 2 轮**:去重结果无遗漏,预览确认后落盘,即本报告归档的 `galaxy-team-coding-conventions.yaml`。 + +## 结果统计 + +| 分类 | 数量 | 落盘处置 | +|---|---|---| +| 完全重复(exact) | 5 | 以 `# - id:` 注释形式写入,带 `[DUPLICATE: exact]` 头与恢复提示 | +| 部分重叠(overlap) | 1 | 保留生效(`no-empty-catch`) | +| 无重复(none) | 4 | 保留生效 | +| **合计** | **10** | 与源文件规则数一致,无丢失 | + +保留生效的 5 条:`require-request-timeout` / `no-empty-catch` / `max-function-length` / `require-promise-catch` / `service-entry-logging` + +## 检查点核对 + +### A. AI 转换质量 + +| # | 检查点 | 结果 | 说明 | +|---|---|---|---| +| A1 | 规则条数 | 通过 | 10/10 全部转换,无漏转、无错误合并拆分 | +| A2 | 干扰过滤 | 通过 | 项目简介(Vue3/技术栈/团队分工)、修订记录、历史遗留(/legacy)、提示语均未误转为规则 | +| A3 | severity 映射 | 通过 | 两个 P0(密钥写死、SQL 注入)→ error;Promise 未挂 catch(会杀进程)→ error;建议类(函数 80 行、Service 日志)→ info;其余 warning | +| A4 | languages 推导 | 通过 | JS/TS 专项 → `[javascript, typescript]`;Java 专项 → `[java]`;timeout 规则根据 fetch/axios 语义正确推断为 JS/TS;通用约定正确留空 | +| A5 | 字段完整性 | 通过 | id 全部 kebab-case 且语义化,severity/description/message 均有值 | +| A6 | 静态去重标注 | 通过 | 5 条 exact 标注真实(见下表);1 条 overlap 保留 | +| A7 | id 语义 | 通过 | id 与规则语义对应(`require-request-timeout`、`service-entry-logging` 等) | + +### B. 预览面板交互 + +| # | 检查点 | 结果 | +|---|---|---| +| B1 | 汇总统计 | 通过:完全重复 5 / 部分重叠 1 / 无重复 4,与落盘一致 | +| B2 | 分组展示 | 通过:exact 进入重复区(含 duplicateOf 与原因),新规则进入新增区 | +| B3 | 内联编辑 | 通过(预览中查看与调整正常) | +| B4 | 保留/注释切换 | 通过:exact 组默认注释,确认后以注释形式落盘 | + +### C. 落盘与联动 + +| # | 检查点 | 结果 | +|---|---|---| +| C1 | 文件写入 | 通过:`.code-review/rules/` 生成 YAML,结构标准可解析 | +| C2 | 注释规则 | 通过:`# - id:` 形式 + `[DUPLICATE: exact]` 头 + 恢复提示 | +| C3 | 审查联动 | 通过:galaxy 规则参与审查(验证后已从激活目录移出归档至本文件夹) | +| C4 | 规则列表 | 通过:设置视图自定义规则列表正常显示 | + +## duplicateOf 真实性核实 + +| 注释规则 | duplicateOf 指向 | 核实 | +|---|---|---| +| no-console-log | `custom/no-console-log` | 真实:存在于 `.code-review/rules/coding-conventions.yaml` | +| no-hardcoded-secrets | `custom/no-hardcoded-secret` | 真实:存在于 `.code-review/rules/security-rules.yaml` | +| strict-equality-required | `eslint/eqeqeq` | 真实:内置静态规则 | +| no-var | `eslint/no-var` | 真实:内置静态规则 | +| no-sql-injection | `custom/no-sql-injection` | 真实:存在于 `.code-review/rules/security-rules.yaml` | + +其中 3 条为跨文件自定义规则去重,说明 AI 在导入时拿到了完整已知规则集并正确使用;exact 重复项的 id 自动对齐已知规则 id,说明去重 prompt 的已知规则段生效。 + +## 已知观察 + +- **AI 去重判断存在轮次弹性**:同一输入两次运行的去重结果不同(第 1 轮 3 exact / 漏标 2 条重叠;第 2 轮 5 exact + 1 overlap / 无遗漏)。属 LLM 非确定性,非 prompt 系统性缺陷;重要场景建议导入后人工复核预览面板的重复分组。 +- **语言字段**:`no-empty-catch` 落盘带 `languages: [java, javascript, typescript]`——catch 吞异常为 JS/Java 通用问题,推导合理。 + +## 结论 + +**通过**。AI 通用导入路径在真实世界多 Sheet、无标准表头、含干扰段落的 Excel 素材上工作正常:规则完整转换、干扰内容有效过滤、severity/languages/id 推导合理、跨文件与内置静态规则去重标注真实、预览交互与落盘格式符合设计。 + +## 关联 + +- 自动化测试:`tests/excel-converter.test.ts`(转换器渲染层 7 条用例,素材副本位于 `tests/fixtures/`) +- 设计 spec:`docs/superpowers/specs/2026-07-26-custom-rule-import-ux-design.md` diff --git a/data/import-verification/02-standard-formats/result-report.md b/data/import-verification/02-standard-formats/result-report.md new file mode 100644 index 0000000..9780401 --- /dev/null +++ b/data/import-verification/02-standard-formats/result-report.md @@ -0,0 +1,88 @@ +# 标准格式导入 — 手动验证结果报告(8 种格式全量) + +## 验证信息 + +| 项 | 值 | +|---|---| +| 验证日期 | 2026-09-06 | +| 验证功能 | 自定义规则导入——同一规则集的 8 种文件格式逐一导入 | +| 导入素材 | `data/import-verification/02-standard-formats/team-coding-rules.*`(8 个文件) | +| 导入结果 | `data/import-verification/02-standard-formats/results/standard-rules-*.yaml`(8 个文件,已全部移出激活目录归档) | +| 规则基准 | 12 条规则(安全 3 + 命名 2 + 性能 2 + 风格 2 + 团队约定 3),severity 基准 error×2 / warning×5 / info×5 | +| 验证方式 | 在 Extension Development Host 中手动执行完整导入流程(含预览确认),每轮结果落盘核对后归档 | + +## 素材矩阵 + +| # | 文件 | 格式 | 导入路径 | AI 内容转换 | +|---|---|---|---|---| +| 1 | team-coding-rules.yaml | YAML | YamlConverter 直读 | 否 | +| 2 | team-coding-rules.md | Markdown | 读文本 → AI(freeform) | 是 | +| 3 | team-coding-rules.txt | 纯文本 | 读文本 → AI(freeform) | 是 | +| 4 | team-coding-rules.docx | Word | mammoth 提取 → AI(freeform) | 是 | +| 5 | team-coding-rules.pptx | PowerPoint | officeparser 提取 → AI(freeform) | 是 | +| 6 | team-coding-rules.xlsx | Excel 单表 | 表格 → Markdown → AI(spreadsheet) | 是 | +| 7 | team-coding-rules-multi-sheet.xlsx | Excel 5 表 | 逐表渲染合并 → AI(spreadsheet) | 是 | +| 8 | team-coding-rules-template.xlsx | Excel 模板 | 严格表头校验直读(仅去重走 AI) | 否 | + +## 逐轮结果总表 + +| 轮 | 格式(规则名) | 检出条数 | severity | languages | id 与基准 | 去重标注 | 结论 | +|---|---|---|---|---|---|---|---| +| 1 | yaml(standard-rules-yaml) | 12/12 | ✅ 全对 | ✅ 全对 | 逐字节一致 | 直读不去重,预览阶段独立去重 | 通过 | +| 2 | md | 12/12 | ✅ 全对 | ✅ 全对 | 6 处不同(语义等价) | 3 exact,指向真实 | 通过 | +| 3 | txt | 12/12 | ✅ 全对 | ✅ 全对 | 6 处不同 | 3 exact,同构 | 通过 | +| 4 | docx | 12/12 | ✅ 全对 | ✅ 全对 | 5 处不同 | 3 exact,同构 | 通过 | +| 5 | pptx | 12/12 | ✅ 全对 | ⚠️ 丢 6 处 | 6 处不同 | 3 exact,同构 | 通过(有降级) | +| 6 | xlsx 单表 | 12/12 | ✅ 全对 | ✅ 全对 | **完全一致** | 3 exact,同构 | 通过 | +| 7 | xlsx 5 表 | 12/12 | ✅ 全对 | ✅ 全对 | **完全一致** | 3 exact,同构 | 通过 | +| 8 | template | 13 有效 + 3 错误行 + 1 空行 | ✅ 全对 | ✅ 全对(列直读) | **完全一致** | 4 exact(多 1 条 no-console-log 附加行) | 通过 | + +## 关键发现 + +### 1. pptx 无语言字段:根因定位为源文件本身不含语言标注,AI 行为正确(非降级) + +表现:5 处 languages + 1 处 excludeLanguages 留空(constant-case / boolean-prefix / nested-loops / sync-in-async / throw-context 的 languages,todo 规则的 excludeLanguages: [sql]),类型注解规则正确保留 [typescript]。 + +**根因定位(2026-09-07,两步验证)**: + +1. 重测复现:同文件再次导入,留空模式与首测逐字段一致,而同期 id 照例漂移——排除 AI 随机性,锁定文件因素。归档:`results/standard-rules-pptx-retest.yaml`。 +2. 提取文本比对:用与插件相同的 officeparser 调用链提取该 pptx,全文 950 字符中**不含任何「适用语言/排除语言」标注**(severity 有 `[error]/[warning]/[info]` 前缀标注,语言没有)——幻灯片源内容本身就没写语言信息。 + +**最终定性**:源文件没有的数据不存在「丢失」。AI 行为完全正确——描述含语义线索的规则正确推断(如「显式标注 TypeScript 类型」→ [typescript]),无线索的规则按「严禁猜测,留空比猜测错误更安全」留空。对照场景③ pptx(幻灯片含「严重级别 | 语言」成组标注)AI 全部正确映射,进一步证明 AI 侧无缺陷。**制作 pptx 规则素材时,如需语言限定必须在幻灯片中显式标注适用语言**。 + +### 2. 表格类格式 id 收敛到与基准完全一致 + +xlsx 单表、multi-sheet、template 三轮的 id 与 yaml 基准完全一致;而 md/txt/docx/pptx 四轮 AI 生成的 id 每轮都不同(语义等价,如 require-constant-case ↔ constant-screaming-snake-case ↔ boolean-naming-prefix 波动)。结构化表格让 AI 的 id 生成收敛到规范命名。multi-sheet 轮落盘文件与 xlsx 单表轮**逐字节一致**(fc 二进制比对 0 差异),证明多表拆分 + 合并链路对 AI 转换零干扰。 + +### 3. 模板路径严格校验精准命中 + +模板文件自带 4 行校验测试数据(设计见其「填写说明」Sheet),校验器全部精准捕获且无误报: + +| 测试行 | 校验表现 | +|---|---| +| 缺 id 行 | 生成占位 ID `rule-14` + 黄色提示「占位 ID:请修改为有意义的标识」 | +| 非法 severity 行(no-deep-inheritance,`critical`) | 红色「severity 非法: 'critical'」,下拉框置空待修 | +| 空 description/message 行(empty-desc-rule) | 双红框标记两个字段 | +| 空行 | 静默跳过(17 行 → 检出 16 条) | + +确认导入时未修复的错误行被丢弃,不静默混入(本次验证选择直接确认;修复后添加的工作流另行演示)。 + +### 4. 去重标注跨格式高度稳定 + +除 yaml 直读外,7 轮去重结果完全同构:no-hardcoded-credentials → custom/no-hardcoded-secret、no-eval(-usage) → eslint/no-eval、no-magic-numbers → custom/no-magic-numbers,全部 exact 且指向经核实真实存在(security-rules.yaml / coding-conventions.yaml / 内置静态规则)。模板轮附加行 no-console-log 额外命中 custom/no-console-log 为第 4 条 exact,验证模板路径去重正常。 + +## 已知观察 + +- **AI 生成 id 跨格式不保证一致**:自由文本格式(md/txt/docx/pptx)每轮 id 均有波动。含义相同的规则若以不同格式多次导入并共存于激活目录,将因 id 不同而双报——建议同一规则集只保留一种格式的导入结果(本验证每轮归档移出即为此目的)。 +- **模板路径注释块元数据形态**:注释块内 `duplicateLevel` 行未逐条写入(exact 信息由注释头 `[DUPLICATE: exact]` 承载),与通用路径的块内元数据略有差异,功能等价。 +- **验证弹性对照**:galaxy 素材验证中曾出现去重轮次波动(第 1 轮漏标 2 条、第 2 轮无遗漏);本套标准格式素材因规则语义清晰、边界分明,7 轮 AI 去重结果零波动,说明输入质量是 AI 稳定性的重要变量。 + +## 结论 + +**通过**。8 种格式全部成功导入 12 条规则基准:条数零丢失、severity 零偏差、去重标注跨格式稳定且指向真实。pptx 轮 languages 留空经两步验证(重测复现 + 提取文本比对)定位为源文件本身不含语言标注,AI 行为正确非缺陷;制作 pptx 素材时如需语言限定须在幻灯片中显式标注。yaml / xlsx / template 三种结构化格式表现最优(id 与基准完全一致)。 + +## 关联 + +- galaxy 素材验证报告:`data/import-verification/01-galaxy-nonstandard/result-report.md`(真实世界非标准格式场景) +- 自动化测试:`tests/excel-converter.test.ts`(转换器渲染层) +- 设计 spec:`docs/superpowers/specs/2026-07-26-custom-rule-import-ux-design.md`、`docs/superpowers/specs/2026-07-30-export-template-design.md` diff --git a/data/import-verification/02-standard-formats/results/standard-rules-docx.yaml b/data/import-verification/02-standard-formats/results/standard-rules-docx.yaml new file mode 100644 index 0000000..80d0f0a --- /dev/null +++ b/data/import-verification/02-standard-formats/results/standard-rules-docx.yaml @@ -0,0 +1,71 @@ +# [DUPLICATE: exact] 重复自定义规则 no-hardcoded-secret(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-hardcoded-secret +# severity: error +# description: 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 +# message: 检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 +# languages: [javascript, typescript, java] +# duplicateOf: custom/no-hardcoded-secret +# duplicateLevel: exact +# [DUPLICATE: exact] 重复 eslint/no-eval(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-eval +# severity: error +# description: 禁止使用 eval() 函数,存在代码注入风险 +# message: eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 +# languages: [javascript, typescript] +# duplicateOf: eslint/no-eval +# duplicateLevel: exact +- id: no-inner-html + severity: warning + description: 禁止直接赋值 innerHTML,可能导致 XSS + message: 避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 +- id: naming-convention-screaming-snake + severity: warning + description: 常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) + message: 常量应使用全大写命名,如 MAX_RETRY_COUNT + languages: [javascript, typescript, java] +- id: boolean-naming-prefix + severity: info + description: 布尔变量和方法名应以 is/has/can/should 开头 + message: 布尔变量建议添加 is/has/can/should 前缀以提升可读性 + languages: [javascript, typescript] +- id: no-deeply-nested-loops + severity: warning + description: 禁止三层及以上嵌套循环,时间复杂度过高 + message: 检测到深层嵌套循环(≥3层),建议重构为扁平结构或使用查找表优化 + languages: [javascript, typescript, java] +- id: no-sync-in-async + severity: warning + description: 异步函数内禁止调用同步阻塞 API + message: 在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 + languages: [javascript, typescript] +- id: explicit-function-types + severity: info + description: 函数参数和返回值应显式标注 TypeScript 类型 + message: 建议为函数添加显式类型注解,提升类型安全性 + languages: [typescript] +# [DUPLICATE: exact] 重复自定义规则 no-magic-numbers(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-magic-numbers +# severity: info +# description: 禁止在代码中直接使用魔法数字,应提取为命名常量 +# message: 检测到魔法数字,建议提取为具名常量以提升可维护性 +# languages: [javascript, typescript] +# duplicateOf: custom/no-magic-numbers +# duplicateLevel: exact +- id: require-throw-context + severity: warning + description: throw 语句必须携带错误上下文信息 + message: throw 时应提供足够的上下文信息,便于问题定位 + languages: [javascript, typescript, java] +- id: no-todo-fixme-hack + severity: info + description: 生产代码中不应遗留 TODO/FIXME/HACK 注释 + message: 代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 + excludeLanguages: [sql] +- id: require-doc-comments + severity: info + description: 公共函数应添加文档注释(JSDoc / Javadoc) + message: 公共函数缺少文档注释,建议补充说明用途、参数和返回值 + languages: [javascript, typescript, java] \ No newline at end of file diff --git a/data/import-verification/02-standard-formats/results/standard-rules-md.yaml b/data/import-verification/02-standard-formats/results/standard-rules-md.yaml new file mode 100644 index 0000000..ecf372f --- /dev/null +++ b/data/import-verification/02-standard-formats/results/standard-rules-md.yaml @@ -0,0 +1,71 @@ +# [DUPLICATE: exact] 重复自定义规则 no-hardcoded-secret(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-hardcoded-credentials +# severity: error +# description: 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 +# message: 检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 +# languages: [javascript, typescript, java] +# duplicateOf: custom/no-hardcoded-secret +# duplicateLevel: exact +# [DUPLICATE: exact] 重复 eslint/no-eval(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-eval +# severity: error +# description: 禁止使用 eval() 函数 +# message: eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 +# languages: [javascript, typescript] +# duplicateOf: eslint/no-eval +# duplicateLevel: exact +- id: no-innerhtml-assignment + severity: warning + description: 禁止直接赋值 innerHTML,防止 XSS + message: 避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 +- id: constant-screaming-snake-case + severity: warning + description: 常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) + message: 常量命名应使用 SCREAMING_SNAKE_CASE,如 MAX_RETRY_COUNT + languages: [javascript, typescript, java] +- id: boolean-name-prefix + severity: info + description: 布尔变量和方法名应以 is/has/can/should 开头 + message: 布尔变量和方法名应以 is/has/can/should 开头,以提升可读性 + languages: [javascript, typescript] +- id: no-deeply-nested-loops + severity: warning + description: 禁止三层及以上嵌套循环 + message: 检测到深层嵌套循环(≥3 层)时,建议重构为扁平结构或使用查找表优化 + languages: [javascript, typescript, java] +- id: no-sync-api-in-async-function + severity: warning + description: 异步函数内禁止调用同步阻塞 API + message: 在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 + languages: [javascript, typescript] +- id: explicit-type-annotations + severity: info + description: 函数参数和返回值应显式标注 TypeScript 类型 + message: 函数参数和返回值请显式标注 TypeScript 类型,提升类型安全性 + languages: [typescript] +# [DUPLICATE: exact] 重复自定义规则 no-magic-numbers(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-magic-numbers +# severity: info +# description: 禁止在代码中直接使用魔法数字 +# message: 魔法数字应提取为命名常量以提升可维护性 +# languages: [javascript, typescript] +# duplicateOf: custom/no-magic-numbers +# duplicateLevel: exact +- id: require-error-context + severity: warning + description: throw 语句必须携带错误上下文信息 + message: throw 语句必须携带错误上下文信息,便于问题定位 + languages: [javascript, typescript, java] +- id: no-todo-comments + severity: info + description: 生产代码中不应遗留 TODO/FIXME/HACK 注释 + message: TODO/FIXME/HACK 注释请在发布前处理 + excludeLanguages: [sql] +- id: require-doc-comments + severity: info + description: 公共函数应添加文档注释 + message: 公共函数请添加 JSDoc/Javadoc 注释,说明用途、参数和返回值 + languages: [javascript, typescript, java] \ No newline at end of file diff --git a/data/import-verification/02-standard-formats/results/standard-rules-multisheet.yaml b/data/import-verification/02-standard-formats/results/standard-rules-multisheet.yaml new file mode 100644 index 0000000..6f83f53 --- /dev/null +++ b/data/import-verification/02-standard-formats/results/standard-rules-multisheet.yaml @@ -0,0 +1,71 @@ +# [DUPLICATE: exact] 重复自定义规则 no-hardcoded-secret(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-hardcoded-credentials +# severity: error +# description: 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 +# message: 检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 +# languages: [javascript, typescript, java] +# duplicateOf: custom/no-hardcoded-secret +# duplicateLevel: exact +# [DUPLICATE: exact] 重复 eslint/no-eval(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-eval-usage +# severity: error +# description: 禁止使用 eval() 函数,存在代码注入风险 +# message: eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 +# languages: [javascript, typescript] +# duplicateOf: eslint/no-eval +# duplicateLevel: exact +- id: no-innerhtml-assignment + severity: warning + description: 禁止直接赋值 innerHTML,可能导致 XSS + message: 避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 +- id: require-constant-case + severity: warning + description: 常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) + message: 常量应使用全大写命名,如 MAX_RETRY_COUNT + languages: [javascript, typescript, java] +- id: require-boolean-prefix + severity: info + description: 布尔变量和方法名应以 is/has/can/should 开头 + message: 布尔变量建议添加 is/has/can/should 前缀以提升可读性 + languages: [javascript, typescript] +- id: no-nested-loops-deep + severity: warning + description: 禁止三层及以上嵌套循环,时间复杂度过高 + message: 检测到深层嵌套循环(≥3层),建议重构为扁平结构或使用查找表优化 + languages: [javascript, typescript, java] +- id: no-sync-in-async + severity: warning + description: 异步函数内禁止调用同步阻塞 API + message: 在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 + languages: [javascript, typescript] +- id: require-type-annotation + severity: info + description: 函数参数和返回值应显式标注 TypeScript 类型 + message: 建议为函数添加显式类型注解,提升类型安全性 + languages: [typescript] +# [DUPLICATE: exact] 重复自定义规则 no-magic-numbers(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-magic-numbers +# severity: info +# description: 禁止在代码中直接使用魔法数字,应提取为命名常量 +# message: 检测到魔法数字,建议提取为具名常量以提升可维护性 +# languages: [javascript, typescript] +# duplicateOf: custom/no-magic-numbers +# duplicateLevel: exact +- id: require-error-context + severity: warning + description: throw 语句必须携带错误上下文信息 + message: throw 时应提供足够的上下文信息,便于问题定位 + languages: [javascript, typescript, java] +- id: no-todo-in-production + severity: info + description: 生产代码中不应遗留 TODO/FIXME/HACK 注释 + message: 代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 + excludeLanguages: [sql] +- id: require-function-doc + severity: info + description: 公共函数应添加文档注释(JSDoc / Javadoc) + message: 公共函数缺少文档注释,建议补充说明用途、参数和返回值 + languages: [javascript, typescript, java] \ No newline at end of file diff --git a/data/import-verification/02-standard-formats/results/standard-rules-pptx-retest.yaml b/data/import-verification/02-standard-formats/results/standard-rules-pptx-retest.yaml new file mode 100644 index 0000000..eef87c6 --- /dev/null +++ b/data/import-verification/02-standard-formats/results/standard-rules-pptx-retest.yaml @@ -0,0 +1,61 @@ +# [DUPLICATE: exact] 重复自定义规则 no-hardcoded-secret(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-hardcoded-secret +# severity: error +# description: 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 +# message: 检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 +# duplicateOf: custom/no-hardcoded-secret +# duplicateLevel: exact +# [DUPLICATE: exact] 重复 eslint/no-eval(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-eval +# severity: error +# description: 禁止使用 eval() 函数,存在代码注入风险 +# message: eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 +# duplicateOf: eslint/no-eval +# duplicateLevel: exact +- id: no-inner-html + severity: warning + description: 禁止直接赋值 innerHTML,可能导致 XSS + message: 避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 +- id: screaming-snake-case + severity: warning + description: 常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) + message: 常量应使用全大写命名,如 MAX_RETRY_COUNT +- id: boolean-naming-prefix + severity: info + description: 布尔变量和方法名应以 is/has/can/should 开头 + message: 布尔变量建议添加 is/has/can/should 前缀以提升可读性 +- id: no-deep-nested-loops + severity: warning + description: 禁止三层及以上嵌套循环,时间复杂度过高 + message: 检测到深层嵌套循环(≥3 层),建议重构为扁平结构或使用查找表优化 +- id: no-sync-blocking-api + severity: warning + description: 异步函数内禁止调用同步阻塞 API + message: 在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 +- id: require-explicit-type-annotations + severity: info + description: 函数参数和返回值应显式标注 TypeScript 类型 + message: 建议为函数添加显式类型注解,提升类型安全性 + languages: [typescript] +# [DUPLICATE: exact] 重复自定义规则 no-magic-numbers(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-magic-numbers +# severity: info +# description: 禁止在代码中直接使用魔法数字,应提取为命名常量 +# message: 检测到魔法数字,建议提取为具名常量以提升可维护性 +# duplicateOf: custom/no-magic-numbers +# duplicateLevel: exact +- id: require-throw-context + severity: warning + description: throw 语句必须携带错误上下文信息 + message: throw 时应提供足够的上下文信息,便于问题定位 +- id: no-todo-comments + severity: info + description: 生产代码中不应遗留 TODO/FIXME/HACK 注释 + message: 代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 +- id: require-doc-comments + severity: info + description: 公共函数应添加文档注释(JSDoc / Javadoc) + message: 公共函数缺少文档注释,建议补充说明用途、参数和返回值 \ No newline at end of file diff --git a/data/import-verification/02-standard-formats/results/standard-rules-pptx.yaml b/data/import-verification/02-standard-formats/results/standard-rules-pptx.yaml new file mode 100644 index 0000000..f4774cc --- /dev/null +++ b/data/import-verification/02-standard-formats/results/standard-rules-pptx.yaml @@ -0,0 +1,62 @@ +# [DUPLICATE: exact] 重复自定义规则 no-hardcoded-secret(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-hardcoded-credentials +# severity: error +# description: 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 +# message: 检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 +# duplicateOf: custom/no-hardcoded-secret +# duplicateLevel: exact +# [DUPLICATE: exact] 重复 eslint/no-eval(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-eval +# severity: error +# description: 禁止使用 eval() 函数,存在代码注入风险 +# message: eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 +# duplicateOf: eslint/no-eval +# duplicateLevel: exact +- id: no-direct-innerhtml + severity: warning + description: 禁止直接赋值 innerHTML,可能导致 XSS + message: 避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 +- id: constant-naming-convention + severity: warning + description: 常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) + message: 常量应使用全大写命名,如 MAX_RETRY_COUNT +- id: boolean-naming-convention + severity: info + description: 布尔变量和方法名应以 is/has/can/should 开头 + message: 布尔变量建议添加 is/has/can/should 前缀以提升可读性 +- id: no-deeply-nested-loops + severity: warning + description: 禁止三层及以上嵌套循环,时间复杂度过高 + message: 检测到深层嵌套循环(≥3层),建议重构为扁平结构或使用查找表优化 +- id: no-sync-api-in-async + severity: warning + description: 异步函数内禁止调用同步阻塞 API + message: 在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 +- id: explicit-function-type-annotations + severity: info + description: 函数参数和返回值应显式标注 TypeScript 类型 + message: 建议为函数添加显式类型注解,提升类型安全性 + languages: [typescript] +# [DUPLICATE: exact] 重复自定义规则 no-magic-numbers(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-magic-numbers +# severity: info +# description: 禁止在代码中直接使用魔法数字,应提取为命名常量 +# message: 检测到魔法数字,建议提取为具名常量以提升可维护性 +# duplicateOf: custom/no-magic-numbers +# duplicateLevel: exact +- id: throw-with-context + severity: warning + description: throw 语句必须携带错误上下文信息 + message: throw 时应提供足够的上下文信息,便于问题定位 +- id: no-todo-fixme-comments + severity: info + description: 生产代码中不应遗留 TODO/FIXME/HACK 注释 + message: 代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 +- id: require-public-doc-comment + severity: info + description: 公共函数应添加文档注释(JSDoc / Javadoc) + message: 公共函数缺少文档注释,建议补充说明用途、参数和返回值 + languages: [java, javascript, typescript] \ No newline at end of file diff --git a/data/import-verification/02-standard-formats/results/standard-rules-template.yaml b/data/import-verification/02-standard-formats/results/standard-rules-template.yaml new file mode 100644 index 0000000..e2f6954 --- /dev/null +++ b/data/import-verification/02-standard-formats/results/standard-rules-template.yaml @@ -0,0 +1,72 @@ +# [DUPLICATE: exact] 重复自定义规则 no-hardcoded-secret(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-hardcoded-credentials +# severity: error +# description: 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 +# message: 检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 +# languages: [javascript, typescript, java] +# [DUPLICATE: exact] 重复 eslint/no-eval(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-eval-usage +# severity: error +# description: 禁止使用 eval() 函数,存在代码注入风险 +# message: eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 +# languages: [javascript, typescript] +- id: no-innerhtml-assignment + severity: warning + description: 禁止直接赋值 innerHTML,可能导致 XSS + message: 避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 +- id: require-constant-case + severity: warning + description: 常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) + message: 常量应使用全大写命名,如 MAX_RETRY_COUNT + languages: [javascript, typescript, java] +- id: require-boolean-prefix + severity: info + description: 布尔变量和方法名应以 is/has/can/should 开头 + message: 布尔变量建议添加 is/has/can/should 前缀以提升可读性 + languages: [javascript, typescript] +- id: no-nested-loops-deep + severity: warning + description: 禁止三层及以上嵌套循环,时间复杂度过高 + message: 检测到深层嵌套循环(≥3层),建议重构为扁平结构或使用查找表优化 + languages: [javascript, typescript, java] +- id: no-sync-in-async + severity: warning + description: 异步函数内禁止调用同步阻塞 API + message: 在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 + languages: [javascript, typescript] +- id: require-type-annotation + severity: info + description: 函数参数和返回值应显式标注 TypeScript 类型 + message: 建议为函数添加显式类型注解,提升类型安全性 + languages: [typescript] +# [DUPLICATE: exact] 重复自定义规则 no-magic-numbers(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-magic-numbers +# severity: info +# description: 禁止在代码中直接使用魔法数字,应提取为命名常量 +# message: 检测到魔法数字,建议提取为具名常量以提升可维护性 +# languages: [javascript, typescript] +- id: require-error-context + severity: warning + description: throw 语句必须携带错误上下文信息 + message: throw 时应提供足够的上下文信息,便于问题定位 + languages: [javascript, typescript, java] +- id: no-todo-in-production + severity: info + description: 生产代码中不应遗留 TODO/FIXME/HACK 注释 + message: 代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 + excludeLanguages: [sql] +- id: require-function-doc + severity: info + description: 公共函数应添加文档注释(JSDoc / Javadoc) + message: 公共函数缺少文档注释,建议补充说明用途、参数和返回值 + languages: [javascript, typescript, java] +# [DUPLICATE: exact] 重复自定义规则 no-console-log(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-console-log +# severity: warning +# description: 生产代码中禁止使用 console.log +# message: 请移除 console.log 或使用条件编译控制 +# languages: [javascript, typescript] \ No newline at end of file diff --git a/data/import-verification/02-standard-formats/results/standard-rules-txt.yaml b/data/import-verification/02-standard-formats/results/standard-rules-txt.yaml new file mode 100644 index 0000000..022f1c7 --- /dev/null +++ b/data/import-verification/02-standard-formats/results/standard-rules-txt.yaml @@ -0,0 +1,71 @@ +# [DUPLICATE: exact] 重复自定义规则 no-hardcoded-secret(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-hardcoded-credentials +# severity: error +# description: 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 +# message: 检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 +# languages: [javascript, typescript, java] +# duplicateOf: custom/no-hardcoded-secret +# duplicateLevel: exact +# [DUPLICATE: exact] 重复 eslint/no-eval(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-eval +# severity: error +# description: 禁止使用 eval() 函数,存在代码注入风险 +# message: eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 +# languages: [javascript, typescript] +# duplicateOf: eslint/no-eval +# duplicateLevel: exact +- id: no-innerhtml + severity: warning + description: 禁止直接赋值 innerHTML,可能导致 XSS + message: 避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 +- id: constant-screaming-snake-case + severity: warning + description: 常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) + message: 常量应使用全大写命名,如 MAX_RETRY_COUNT + languages: [javascript, typescript, java] +- id: boolean-naming-prefix + severity: info + description: 布尔变量和方法名应以 is/has/can/should 开头 + message: 布尔变量建议添加 is/has/can/should 前缀以提升可读性 + languages: [javascript, typescript] +- id: no-deep-nested-loops + severity: warning + description: 禁止三层及以上嵌套循环,时间复杂度过高 + message: 检测到深层嵌套循环(≥3层),建议重构为扁平结构或使用查找表优化 + languages: [javascript, typescript, java] +- id: no-sync-blocking-in-async + severity: warning + description: 异步函数内禁止调用同步阻塞 API + message: 在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 + languages: [javascript, typescript] +- id: explicit-function-types + severity: info + description: 函数参数和返回值应显式标注 TypeScript 类型 + message: 建议为函数添加显式类型注解,提升类型安全性 + languages: [typescript] +# [DUPLICATE: exact] 重复自定义规则 no-magic-numbers(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-magic-numbers +# severity: info +# description: 禁止在代码中直接使用魔法数字,应提取为命名常量 +# message: 检测到魔法数字,建议提取为具名常量以提升可维护性 +# languages: [javascript, typescript] +# duplicateOf: custom/no-magic-numbers +# duplicateLevel: exact +- id: throw-with-context + severity: warning + description: throw 语句必须携带错误上下文信息 + message: throw 时应提供足够的上下文信息,便于问题定位 + languages: [javascript, typescript, java] +- id: no-todo-fixme-comments + severity: info + description: 生产代码中不应遗留 TODO/FIXME/HACK 注释 + message: 代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 + excludeLanguages: [sql] +- id: require-public-function-docs + severity: info + description: 公共函数应添加文档注释(JSDoc / Javadoc) + message: 公共函数缺少文档注释,建议补充说明用途、参数和返回值 + languages: [javascript, typescript, java] \ No newline at end of file diff --git a/data/import-verification/02-standard-formats/results/standard-rules-xlsx.yaml b/data/import-verification/02-standard-formats/results/standard-rules-xlsx.yaml new file mode 100644 index 0000000..6f83f53 --- /dev/null +++ b/data/import-verification/02-standard-formats/results/standard-rules-xlsx.yaml @@ -0,0 +1,71 @@ +# [DUPLICATE: exact] 重复自定义规则 no-hardcoded-secret(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-hardcoded-credentials +# severity: error +# description: 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 +# message: 检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 +# languages: [javascript, typescript, java] +# duplicateOf: custom/no-hardcoded-secret +# duplicateLevel: exact +# [DUPLICATE: exact] 重复 eslint/no-eval(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-eval-usage +# severity: error +# description: 禁止使用 eval() 函数,存在代码注入风险 +# message: eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 +# languages: [javascript, typescript] +# duplicateOf: eslint/no-eval +# duplicateLevel: exact +- id: no-innerhtml-assignment + severity: warning + description: 禁止直接赋值 innerHTML,可能导致 XSS + message: 避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 +- id: require-constant-case + severity: warning + description: 常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) + message: 常量应使用全大写命名,如 MAX_RETRY_COUNT + languages: [javascript, typescript, java] +- id: require-boolean-prefix + severity: info + description: 布尔变量和方法名应以 is/has/can/should 开头 + message: 布尔变量建议添加 is/has/can/should 前缀以提升可读性 + languages: [javascript, typescript] +- id: no-nested-loops-deep + severity: warning + description: 禁止三层及以上嵌套循环,时间复杂度过高 + message: 检测到深层嵌套循环(≥3层),建议重构为扁平结构或使用查找表优化 + languages: [javascript, typescript, java] +- id: no-sync-in-async + severity: warning + description: 异步函数内禁止调用同步阻塞 API + message: 在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 + languages: [javascript, typescript] +- id: require-type-annotation + severity: info + description: 函数参数和返回值应显式标注 TypeScript 类型 + message: 建议为函数添加显式类型注解,提升类型安全性 + languages: [typescript] +# [DUPLICATE: exact] 重复自定义规则 no-magic-numbers(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-magic-numbers +# severity: info +# description: 禁止在代码中直接使用魔法数字,应提取为命名常量 +# message: 检测到魔法数字,建议提取为具名常量以提升可维护性 +# languages: [javascript, typescript] +# duplicateOf: custom/no-magic-numbers +# duplicateLevel: exact +- id: require-error-context + severity: warning + description: throw 语句必须携带错误上下文信息 + message: throw 时应提供足够的上下文信息,便于问题定位 + languages: [javascript, typescript, java] +- id: no-todo-in-production + severity: info + description: 生产代码中不应遗留 TODO/FIXME/HACK 注释 + message: 代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 + excludeLanguages: [sql] +- id: require-function-doc + severity: info + description: 公共函数应添加文档注释(JSDoc / Javadoc) + message: 公共函数缺少文档注释,建议补充说明用途、参数和返回值 + languages: [javascript, typescript, java] \ No newline at end of file diff --git a/data/import-verification/02-standard-formats/results/standard-rules-yaml.yaml b/data/import-verification/02-standard-formats/results/standard-rules-yaml.yaml new file mode 100644 index 0000000..4752852 --- /dev/null +++ b/data/import-verification/02-standard-formats/results/standard-rules-yaml.yaml @@ -0,0 +1,96 @@ +# ┌─────────────────────────────────────────────────────┐ +# │ 净码特工 · Code Purifier — 用户自定义规则文件 │ +# │ 文件路径:.code-review/rules/user-rules.yaml │ +# │ 格式说明:YAML 数组,每条规则为一个 - id 开头的条目 │ +# └─────────────────────────────────────────────────────┘ +# +# 字段说明: +# id 必填,规则唯一标识(kebab-case) +# severity 必填,严重度:error / warning / info +# description 必填,规则简要描述 +# message 必填,展示给开发者的提示消息 +# languages 可选,规则生效的语言列表(不填则对所有语言生效) +# excludeLanguages 可选,规则排除的语言列表(优先级高于 languages) +# +# 内行数组语法:[javascript, typescript] + +# ── 安全类 ────────────────────────────────────────────── + +- id: no-hardcoded-credentials + severity: error + description: 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 + message: 检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 + languages: [javascript, typescript, java] + +- id: no-eval-usage + severity: error + description: 禁止使用 eval() 函数,存在代码注入风险 + message: eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 + languages: [javascript, typescript] + +- id: no-innerhtml-assignment + severity: warning + description: 禁止直接赋值 innerHTML,可能导致 XSS + message: 避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 + +# ── 命名规范类 ────────────────────────────────────────── + +- id: require-constant-case + severity: warning + description: 常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) + message: 常量应使用全大写命名,如 MAX_RETRY_COUNT + languages: [javascript, typescript, java] + +- id: require-boolean-prefix + severity: info + description: 布尔变量和方法名应以 is/has/can/should 开头 + message: 布尔变量建议添加 is/has/can/should 前缀以提升可读性 + languages: [javascript, typescript] + +# ── 性能类 ────────────────────────────────────────────── + +- id: no-nested-loops-deep + severity: warning + description: 禁止三层及以上嵌套循环,时间复杂度过高 + message: 检测到深层嵌套循环(≥3层),建议重构为扁平结构或使用查找表优化 + languages: [javascript, typescript, java] + +- id: no-sync-in-async + severity: warning + description: 异步函数内禁止调用同步阻塞 API + message: 在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 + languages: [javascript, typescript] + +# ── 代码风格类 ────────────────────────────────────────── + +- id: require-type-annotation + severity: info + description: 函数参数和返回值应显式标注 TypeScript 类型 + message: 建议为函数添加显式类型注解,提升类型安全性 + languages: [typescript] + +- id: no-magic-numbers + severity: info + description: 禁止在代码中直接使用魔法数字,应提取为命名常量 + message: 检测到魔法数字,建议提取为具名常量以提升可维护性 + languages: [javascript, typescript] + +# ── 团队约定类 ────────────────────────────────────────── + +- id: require-error-context + severity: warning + description: throw 语句必须携带错误上下文信息 + message: throw 时应提供足够的上下文信息,便于问题定位 + languages: [javascript, typescript, java] + +- id: no-todo-in-production + severity: info + description: 生产代码中不应遗留 TODO/FIXME/HACK 注释 + message: 代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 + excludeLanguages: [sql] + +- id: require-function-doc + severity: info + description: 公共函数应添加文档注释(JSDoc / Javadoc) + message: 公共函数缺少文档注释,建议补充说明用途、参数和返回值 + languages: [javascript, typescript, java] diff --git a/data/import-verification/02-standard-formats/team-coding-rules-multi-sheet.xlsx b/data/import-verification/02-standard-formats/team-coding-rules-multi-sheet.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..cd960cebd2752e8a1684afa35dcb24170d42b4fd GIT binary patch literal 15562 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 IWPg19AN%N3H~;_u literal 0 HcmV?d00001 diff --git a/data/import-verification/02-standard-formats/team-coding-rules.docx b/data/import-verification/02-standard-formats/team-coding-rules.docx new file mode 100644 index 0000000000000000000000000000000000000000..cfdec0854cf8a5ab45cc478a066d7fba2b1113bc GIT binary patch literal 38978 zcmZ^~V|Zmt+cg?@YYN+qT)UZFX#{*yx`+Vnp&h?!it7cZ!9An(5 zS;(vuh4{tf%Z@Z{nmw>uzJ+ zlw4=KMvut<6sd=96qaP>|5{V%CH!D`VV|9q$1CFns9`M6|sD7MuOBV%ojsn&=_s4DO)cH z9KqW+Ae$VY6+7t~PBvQLP;dulvcO_;CPpx;B;!2=Yk59OD*Va{NY`bdY^eKgw?}Xx zO%IK0_9q`u25h*M?C5tH&N8R`#lg)FS5-_1Hw>S=%G0k#;kM*5-6_)B%cJl$Ztu3n zocElBEM}5Xoii!B+6wyZ?dSzR3z(^Vz5jG1bK{opdNdxsDD>Hk3acRTX6Kg0Yk*J~ z_G@rRPyWA>>Om&O{{~3rCI}D^4B)EgXkzU|NBg&|p6!zyq(_92{6SQI zqAR?dDemLXklw73C@o&U>f@y#Op`>^x|F_iWMtahF~jv3NvQ=bSyib?51SDU*M%&1 z@o_5pOPc`G9#uX9#k9_fwmI%NPaWFh7em8LM?4z7WJHUiDNkOQw!$F2=aRy$yrW2Y zD$+g7Jq4SK56#>a?4~s1$|gn5<6%O>BkGOc%B&GED0opxaAg{W;SY2sGnyj2sNK+e zp@K9%@`@QQ+9Lrqzi$dl8ZmA~ad<-MPCM%Kn9SoO;SLgwyrtn}D12#blA;;4w+W_B zn?cDt$GM>DYz?Vbx-Q|%e*XLWG?{My9i#A27$s{!$DaYj2ni4)V>=^xM>~5bIwLzr zlfT_QJ3&TnfF3sV>OImjHD~o+h(OsT8_b-XjF16rH-%IeW6_)9X7O>Wuvu#0QqbcSW}THjZhFOf{z(oR=!?)$TaZCRrHdfY*pZ;s?kxBEsu_{=Eanb z{GcEsRZLV(G*XIRr~zJ?i*HfeCE10>sd(7qs6PxvcD!Dk>t&m8=R2 z10^x2SC<}-Yc)XgIf6ZoNK+Vx~AQNG6mzkRrx#|c}%;0kng zxaz9hQoY@}`0m4haN?ujUEqFQhHZU0p-wM_mg@D@Bl3MRi1$emAFjPB1F7EW_V3z&Kfh52Zb<&IM*lSNXBA)W_rFGDMY@l*!I0@RnwMKiwD`<1Pz&1 zzp$Sp4I1FXX;RLwsoAF`MgOk$l*eT)ov<1ik?bj|E!5>Q2h0MD+A4Pesx+c_>Yw3ODw(S5h{@^4|7RK8n-j+<&T zD50hX8$+R*R@BQ;5{|2LHShlfgMTvy9cEp|#5AfIC)K|;HH00S{0aV^DzcG~^9-X^ z-5et!-jD3Xmbi+cqq(7%`#Ck^7ONTO>wWNmIKWItk7HHau&8wknNiG6J^;UZ=6ibO zef=vIQ8>XR0WY@r!iBg|{>f+@AMeFRHWvGKwo1J7)>FOj@JYcnQ47_FwLv3qy)hN_ zvWJ=#v^`o^D55|wuA zU+Q=nT_gi347`oucQfZywIf3}x{9c$9KL_fNndiqyb&m-&WJ@!{cq@ZA^R<92VmD^ zgt)D!47n-R0*046Nld;!dP-)u$vq5(qRSN{z3W5|3av&ZeLqb1SQUzd9f7tTcAH%D zndvM#rVa3R>_dxsc&n1pJG^(zxo0}xX4%%6aN8BoMQDDX3s)V-m@(l{?x&C`+ z1X&A?ebelrBPj6OCsA&OQ3-NqJFP!10)N}7-QL2**LyHeJH3BgKlGMmOqjP-r9gS3 ze%bBQQ_6Gip?ryl6Z5t^$E;ql(MV5}t<8#&2WtVlbAuDTSz4<8Jg};VBdgs{OW{(P zqMbJu&7KNaG9sue3qzq#0BM8rp{>5OsbE5}XMrbU+cAI$o?SqI;N}rPNX)tFCg*>K zox0K+Wr)`StHi>2b+`1f($srBVmtcCcRxjSoWJ>d$kpB8AuAN)iEEnx#G&j?i+uRUW5$}RlzEDTV7Xbhg-Or zHZj;l*!GN|3h9P84SSc0#h&|FQ8;rXTK@#vMR&>+D4IniTEOQYa3x)B9J4HHU7e% zQP{KHZaDCsJ{y7A$H#38U}@X+VN2$kG2r6(&G=2S+jM;#wnGEG1NnU7p zQ2|3m%A(|V686}DdypR~rA}p>y6iI;vAwQ1pGK(ST&p7LUp6;ij1IL#h&gx!C3c87 zFKWyiknp0l`xMBq#IyJII5ja;9#En|+Z*|s&uBF<1LDx*u-bA1$8F8&3i~36QYtF) z`wD3?d)SE5!S>$fZ${$lriS#Hix@EaPBG>e7q1XPd90lE8HC~n!NrlqO$pPg$dP3v zs2*4-mEua0J4Nr87Hvvt-eIrUz6ym%t*^})6^bt=S{H#}-xLf{agPjFMUbni0{mf% zNVK`XIfB>*?-+z0 z2Y6M$2gF{Tkkt7O2rZncHm5*sZc{)4(D)3Hn z8hI<)O(>eMI&Pe>G9fHLkKNvPO}6?u2KVbnW$5uC2Ved{J;Bf6Tn2klkQZE@wxR<^ zNngcLxjtp}w&mcyb+)uX%jdel@(>vEXCLJ$wZ=rDUtKk{aXlkv$v8?=bf^}ZddqWq zbOkn34elxj#BDX=9VQp@x5rT;2()E)Qo??6UU6*=XCiK4FA`R3Odxos_t*PsfrzQ+_ z8lO+3Mu&5|G&-RgkmV!{6eSi~cFbM#DST<#GAScgjUg}Rc8%IHV3}uHAVOQT5x26( z)Y}t8e42X8`)^nl@GBY8$vxY2_Oid7lSLIbRKJ7`%PN(Zr;5d-m`XVrX_e0iC>6}C zF3(%ru=;|vS}LwHow2RwZNzK=&7yGJJR8AVRk=Z3 zGiLi}>uYs!$WnLUVkg0F89JeuB1ZJh+$N^PeqzYT#(79H%Yw`_IMEd?T6a}4YPgx# zE|_i|?CGCa@;lf1g!}Jhz~P;{t{7m6s0Xe&lkmTPqYA;BN=H zvPOj75E$wwk2lgJ9FzKVW{FbAH>NXB2_jz*2uHmPokK;FTv$`MpsB|UhX$t#FJvPM zB>OWC)_`agj%JHV5W03FCM#QM_+!FB811ZaJ-;u>Hcud5rmmowozw(=ox6I}psjN? z3H)*{5d>Ssg3KzO#o&k9ns$f@jkw~5jNkzuDLbYm zrxTm0+XEclNVA$EG%JGnB(dCo`XW37-9eDZOW4+sG?p9?>JZ(IILC{m4AKm=wa1I& ziWTaEJx>-tz{VUy9Gj_Z4st#p{W`x4SJP{y#hhU@AJTe(q7XRI%NF?Y-kl7FSFHEN zKUizT{ss2m3HUZ&n_fT*1ca;t4utTZ1UNZ+SerQgvkKGEaViwA_vz{B-%0hzXc|l{ zihZz#1m;3vVB%WaID3mGT{qQ)(38-8y07g47Q`n&)X)%7;9o^zvhh(CFjZaPkXRV) z`Py3>e?9E!GyOh1^MSC}6XV+oRbbKyT}b!D_kPsyw09qtc`+5I`pFp^_=f)p-OTsC zSNiqx_7-+=S?ltv>*cXNwi#bH<*8-5W8*BWqvPV1!~LekFG?@y7{E-q+4YC-Dj37r~%Lbs(GXrAi(Ws6evp@S*5 zc69CHWqyG>yXw`c(Pg`9@@pe>CN=e;y9#qL&dOVe4^EvKp`}5Jqdj0eM=?S6I{RB+zbIr3w=5zhMZuE2FQ}XL* zXvWs-?z3-;cHsKX=^A-`t2_s zxe1qcNQ;|9>Dm?B75?X0?UfzN#r2q>mbcA?m>zsB_)Of_i?c6-868h(<@M*{*88(X zj`t01M@z>pZV&pGB$w|)s=;d9S0fDTQ_HG(5_3Cz;r6F$rg|73Z#QYl!38BDwW4ZWw9293wv z(rwar4(;l|<4;%bXZ?E|z(e2zU+`rev~cp^=Vei4LPNXPV&2m8eoxd)^|Z$5E<^Nm z_#w1U&ilgi($D#F|5%lKe`dFHV);mi>M5i5-XoN{H=$?J#r@5faoBFS33qbPxhT1L zd_H(;E4XhfcyudxXlpRICxX%sg~=PG!@Uim`>yt^A;ZpmV(U+Oj{&{kfbnPO(0dHj z9b3u7RvLqk(MhSFp7#jYNbiw-3%n(H9>bAxs>~ak-}Cpc@nJuoZi&UkDBYUI>yrzI zZyoatTgASsHoM1CHf$NgOEGV^ujh6HHa=omC0|)UxtV^p{VFzUrbC=c8_)PwepuWi zXDYwiUU0nE>U_VRo)72nOy=K`r(t_S^>WkOW`-`zJu$RQ*$w8JdZm>)k1Bn}39fE|@gXTCUM3FkQsGsH38 z_cP=J3Z4eW`yrkoK*6@e=sd`M;tTuvolJwl^~rYnm+3{w2?T!g^OII*<+l=S@~AJ; zRqz?s)_{i+r~ct}&yj7T?vS{A;%>BfKv4`R-ZLPtg8dwfkE868jgQ0a+Ki9IC)&#; zG}u@u&q~M~Hs(ocGGm-jLt~$RLko!+lG({D?r*Ti861cE-7b>IZe~=CY9+FGSk;r+ z>5T1HOQmB&*JeNaKF&vzRmB9PB^T88;xcD)0nA9W~Vf^ZzGx2DFaZVw7O*lD3t(^Nh}_j z0Ho6Jzl|FIr!ggIbS;6=LkpSQPHK1GW;COd2GB@qb=wS}O#vVi82)VpXaX96aT%uJ zMtRp<>_InkIMEv`fxGcj-2ARSA^0HV`pCjl{IgMw7~FpUAwJqP}7R5<1|y- z+2f3!vtjkqY2;~Zrg_ne%FKNd!=&w2a}3;}_0v8s9oT6Bj0_z;x()bE z;oV8;A^oqfqvV0!(ahwq0H-Z(TnJfRUR(&@^)I)&ottr9jVA*K(@NQ5i9 z4^+$?U0DMAdPy&gu&7c}z$b*MKTUl02eAYSmIO9Ig5+ZFVIURPcO4AvJz22S9hs44 zB{c0J`FcsgQDj6(PZNq0A|Z(@a|(+ONYW_+h95zLh*%^L1md#7QY&dQDlzHyUt6q1 zzpJ7Nl#IdBKf(!wvLVMrB214rKcPT?5M;Q49gI|lV@Mfot9%Dz%4OHJ)2;T!W{Mai z$%qQgXX7a9Igvz$DPCwqXK0^Y(S>pcghPI#BMHupA!bCv=3DRynit4II@s4JKpkO2 zg%@j>P)`aE&sO2rF<%@wll=JONVyOx##qcTV+g5Q_Dv;t8WWv&VW~?B)u~3?siMs3 zL1R|t^=CVdt&jf|-qK28`p5&F0`k_?%3R_{a!vQk%3j*Y1Ce^I-`!JgtX?HwJA6)p z!fQ@Ar;OC5U$k4tbMfoj$zIMW#N{nU!`Gc>marXNTpyViqWa4*E!tEo^OLT8(A;cQ z;=$F8KvUU%AiSLpf?P?PQ~S+t zt3aHphsnO#`h)1p`Pz0RjD1-j`^!PW^N-l90=~!E$lgT@sU`mh_h5A|-HQdXFqqjm zGQr7}$AT*;c-haJQ@X^`s`8a5(V(>3Kc7R`rEvt6+Ouj&`YUXH+0~t6`nTHZG34zg zy30guj@6Dx>>2w>f>N#HWbN8GvG_j}Vm5ooY<)SvH7)4xWU0-F3phg;vQ*m-Z*C(_ z%bGNuuWsOw<`(knDw)tBXvFO3-u!~k#=l*yWLioia?5qm2AWvw>cbU+Sz#I;1!iGX z?uNLD{vOeBNh{-^q&Ppgy~&k7P4v{ADF=7xYA@fO)oKsGoHxk$6i>hyeSA^)n4R{V zbM1VkN~WjXw7VVFU2nZqofdlhlNEoFeD|`P&bg!nvS*|zi+DD@AyBN~9`-nM&ca&3 z2)Q`9nygi^Rj%s#Ekjui|EEK9W!>nz+$VhPvWzmld3~WkkE7Z{=H!^IfSuJg{!;rK zGz0A@$GIL#80hVj&rn8zq43CXxIU-~U4AhYxnb9SM9Q5B6G!?_AWXj3grpS7FZAwc zvL|3lYu$gR1ftb>%_n@WA~B{*El(Xk(yld<;m4fyDP3|8CO-F zg6`ey%!nS4lZA~Cs^tE;|EX{nVKJKixK8doP}QbrRD|z8|5;;&M@Qm`XP0R&S1}iS zdy-tjx~;Qw`65p-EcaRyuf0VnnqKziVcldgbsNw^H=@YA`l*5xH#(bA6QdAwvh8fz zOEpa*dLsAYs*rEs*506ab|bo$4pR}c2qkndMWA|d!~h2PEH|4}zWkOs+z}L|%TVhw zhrTUX`9{a;#~d}|wy3hD5$J99(C1cw z0(iJ+sVV<+JtLfeQX8+gA5S8=#&iuazmQ#v2`Nt6>VCDjC?nBqF5kdiY8kBx=?N0m z4NxQ^(a5pwTMa~tb7i@?(Y)ocxs>!GdY0t9>({c>5=LkS``RQ@=vu?X;!#U|)aM2sJ@W-%vaW?IJRvWo? z2{BM)$ehGo8&Qrd{&rJhY~9@BkX|jur&WXrI3w)GtjO;o&GUb_@c#27ym@PEaTd(e8ak zZ<34BPlp?Y$z9{5{p6z9-eQ>qw^?M+Vlobl?y^>|hR3!@NC{9@6Iiazs=&#|qG*L6 zRxva4JLd`Jxk-K>j7X>P9v}I2ejkqL=A9qU=~rh6t+iV^X+7hNq^Y2k)v!q_Sd=S~ zj;i2LTv_nnqcZShR~lh`J2gDLALu2H#LUK&d55o>@vC`5w&ET~$rcC5(Qn#cQHVsJ z8;R7da(4R>x|x_)hXNcN7w|LpQgiwzU7r|yduZT>Ku@NuEF2DJpcR@C0!$vq>Sx5+ z^*{>jH`LuxOWuvtLfSg7UxjuaIJD=;rKEVe3r-NBqtE?pS3LH12NQs=i!`J*g3Ig3$&lfS5iMQ#RThof|z(BGH1A$7@A zrI*l+rJ{Gq0l3zhIV#%~?q{{vsPoy-X1)_(2j{c#>jiKAZV29N2bHB>a+y%HchqG1 z7PBe*mjsLc-qabXD?NuHb7DLdy%0dcSs&e|>QZ=I+}5liX!oOljh`7($j-kTvg@ZA zRF?}x7JCkpOKI`;exoToRu>ctBDp7%!SUodk>}iql96dD9gS)3pG<>k44BGO(VNVS z(+tx45+YAf;hixoq~ z?=B4=LAy<3Q!F&AvJkxttIYq9(BDHGNB#Nkk@82&tT*DQHB^b)PE(sHEc$O$u)0)G zeWlM8G(M3)=7w)wT$IIBq&?wIBLlS2o(ThxPC$sk6LyRFM6P&V$7}UiZ?qc6%E3}( zQnw>25y_7vLEO4fuhoa_!Z_}|6s_YzIRwSbdkqO14JnW$rQLseldYLiKx!4HCoF30 zqe~M?k5`)KH=9F4uOy&K;n&&pReDec5Eg1-U*`eKQK%hvN?U~&n5TM^n{#dpbYTNM zSQ;u^_2X%zFw9HS79xkQ8ZuGLOChuR2zPuL&t)e=e;=w`r! zy~KWdI0c%I!Z;?JAFs?SXck9+en_~N!&k5a=$%9o7V7?^SN1=8W&hEG0D9OBiGh5$ z{V`oeV;d~kMUp-*Hm`MUse5bmyDSxg+q@U$)JD3?y38s(;Vr-WriSXs;VLZ|XryaFAZ`yYSu`L(puHTfk(QU$sf+4w7W`C4%PE_Xs2 z!LCk8G0P~6d{gR#<5S{O8g~{t1}5WqDNsD-ZKwy{D#9pSJg@laSI8`VGWC?sjB@~|YMjW8yqhrkEJQH2|<7RDX01Je8*|tJIUoveUHE%ziZu@5KXj?iOQZMY$Oqo(p19TUH!AGDeVFFFK z*HnuWgeo~XpvB$nD1!2&59HG0MI>QzT%WP4 z&cI>P*A`8-piNmUW;no%L(#T0xt|jm_0!PmXT1dPEpFkJdIil{>`{9N$wdARe9;>P zt7fq$^oX`oIbS4)h+$0xNgjka$nL=rC6xGW113yfg8#NFmKf#effDks@!eUYp$aKT zSrFE8VOa_OiZ1?vfCT>yX^@ImOv+|-%1khlEr!=vLc%@I*vq6!GfN$D5Jl@o$p_Tf zw!;K}RHw*6Z4?Q9+<34-wY_{2g7O<9YJW+Pz%>(`Vr8E21b>~HCI;22<&MA6{#68!cZ(S=Eol!^c+ibsYc7h+Jdz^v+VMnC6 z@;ePztTZ56KIVDzuDld@OHuk=pOafzWb02=GatR$K6g$O?;oG8+!-mIeqi%xTYSqs z1pyuJL+4+ex(h!oGaswyKhz&~CR4${;N&Dhnw8GfhHd~ktoVd4IHiN@CR++M{Wri2 zB*xq$ELnywi$ed~wEszBRyfJFUEdFHub2Dt+WzBl6N~MSHMW&E9G3tDPQ0~ic1h8~ z5T5!f>$CkcUS_%PG4G{1@$*u$v~IYfeIM1PIA71t&G7XOO>9z+4^c_OBhMR;g$t$E zZ#Oyhne5(%NVS!GH&Tt3)E{Qi30nm%cg1~AO8yu5xpRz90iM?5>oA9uv`*x$A3@O@ z^1}%1%uJ?EQ*Mlf_&EE3@pX>xKjSOsyr`vRAy|x9`Ci?RrPQw2VYR~hQvce=C706u zDL#%DHfXz$flSIDb7o9Y?mk*5LVqAJ=9P8O!MOb~3in%_fyPVs6Ub<=o?uIYWrP`X zl8o0-PDe)#5<%)v1E@_5r^TYi43i7op-V7emHO_3wtuAA%3FtY5${s@>`*Z?u3@Fi z2>1(XY?hN2+wHB@CJCqX*IT$WCk0R@!)=cqtM#Rzevu zr0L45Fd=>DkC_v-_a)n#U52Ym>#4)WOt^}gIz>!q>kN1gjT1It{zF)Y=>kJ0mC=hz zwNgnEHPc58p~sh^J~3o%eik*FZRrLPWKfbFNM2=Nv zQ=xQqfrMl|Cd!22HJW$$koIM5Hmzu^0_pOPb8XlHjQKW9VZJn((QsS)Bg3@+ZQycS zS|_usF0;>X>QIm_&;VI#(T$An_3F`@D)>pp4CrY?+fs;#QEkdunJa}70Jr}QVErV( z!1_Y~p9$=L@c|q*_c~P33!5;c_``*GJZLzN2A9ebP)@2HC(^|Qni`a7H!B;D9K42}(tfaCTF9|^h<+4&Sc9G=7~kvswZCkYt}Qi4 zGRv{5O2LO&{Yslm-MgJeFZs2YF4W}5Qc(_Rmc^}?i7LAvIdGo9E$$AEaMM{#U{N!r z+EC_ZFAVEI7e1U?b0A8iRi?He_%9Y;U~9w7LDq)eE_k8?(_9NlBBb3he!^}EZ>L}0 zO0DMX3{#@gQdx=Y@)=r?TrG!ai~vGdUqlpSr0b;dn$xB9UpNl^(RrRb?_Xrl zL010=mBatXX!JCv-EnKgf8b8NSq(wO@ZtY=qm{FrKCx{phb$A>IKV7rI1c2;^bG_8 zxRuoTQVIB$RMo0dB+dnXi-V?YI$Uj)Cpj!b8QU^K@J;pxAv6>a7qDPc zn@lhgthPz<7as|L{5|jyN@Nq8O*rrqepLsP#KC#QX=Apk#4=C#xcIgY84g0~T5t?Z zYOp^c5Yxz(+VYuDca6F)A$9;cKI{!nY88h|D3lbpv4dWH_wNLY|6>6)h*Xd+86oAE zUOjMWl|-EgJq7i?-O)&41mR}Y6e`6TC&iz8-A;Y>a2bn{`Xp~-s1JGE1-HSudPyaS zl;|%M697#$BK`+TqT^^Z)BFDi-&TZ4f$UP|RX6O{htjPJ(~sEhB7IT% zYO6DMFeS*pxCdbR9`Fnz1stAd69QY_um_&JCCvUF#vmTde{yXBJ;(4@tqXi8~LsMp9r zKykAOeDXd16@&`5lh!WM@S*jo}LkX!^sqv$m-eN?HfMwzAf z#bjL_4zIwZ`s9Yk$|5m^Il?o;6mpE!>!t(mQ4SX4QLY%2fGDCQlPc_xu-F+8UXpLF zISI<-YlB%}!INhJ!j8E(6SHmp-Q zW4KcpNk-{LLi3GNCUUOv5KfpGPGrs*Q)a-*1WD!$SOzqF<5#VZ4drnj|Mah>K~CX0 z^$j^@ne|rkj1oi{(C1ilO(m&h?8e}nlJXL*QcfAGb$;PFdFDy~8Rkw`f|*9VKg|Bm z7+f+|QVOu(o}ty%%Y+%jr=L?orDVA!46$AX7SJ=y{#Wfdw~B!8bSlDg%HA1^-La*+ z%+(&CNHRh*%qXIB*P0c=bDsQjK!)Mra9=c()Vs2tu$oqYlbc1{Yq5SL8K>b`}Gpd(lKeDd&=8J+@1L73bW(*`mw4)a%RImaH=(Of*7{rdJ3N|oXBD7mSy zqoPwT=g|{1JPUdE+40egU)XZ?scFa|>~nq;9hZynD!JQJG&@ch)VFbrl)-QLPL zWZl+z#yhgdqTTpTGFUo&Pl0kDqSwCg6T)_Z9dK_k1Q|DG#LnK*fJLKD|0v9U7&Nn> z!^Af5*m~BRz&}z412CMhblWD^kaXIxURrw8C1|BAE(Y$vb1)Ee`mX}p;L>aqo&HzH z`6scVff%iW?w-*Y_DDkR`R^8~d+c}M>|?8gFn>oII!yXb|0N@$PJ7D!Bbg&ta2fjG z9dKznigZn3K1?)m;s3(}5s2}uO!yxj<}vGOJhk%_X4HXydC~wp7!ZV=_Ai)@?U)>* z3k*gEZy1POd5?4iuYKow{LVpZJ^q*fu_%`O36pM{DD+zJr37e>K?e@Ur20}1(WBhk zy)SSF{2j`rA13u^!}QTyk>Q-?AJ0yO*$eO|0;K-iq^Z$|{~_{7T8Vl|54F=tYKp)J z*8Krbr@eI)zO~7o?4->2{pWYOSl5X9&>o%8oufhPrxv=;+?&HAk4CseRS>_9Ogo{k zcNsP>8jmlI7yT2q)U}P3ao1MpC%5?aduOLnxoI$KOIzq5UCYct{^V6rq}HNl8B|E% z=CN@0(;z#@Yr)q#sTxY47QzW+bLLe{fgL8^Rt{xua}( zSMz7{n+bSw%3tSbx8p-eIiLKc&bVRwZ}tRS7>{Z{BNiYT1)3xAe#xwL`1IkDWP{?m zEj`C|p!A#p_b_#yEZ1-e^0(^3h#jrzd&QP| z9DKhGze3s~?iTZ|)#F~T(`hgi`)L_n>!ShZJ2eue_~)Vkw8*2`pmrK)aElQ!W%nprQAK2zez`jGs!1wl`YE|F2gss}WUc)tY@ICxx22ak=cf;o} z)f|!?{(nSVM*c^{*`L|&p@xYMbol++FmUkQv-iD(c$}TfMpK?ah>?%K5cBYxIeOna zP<25Xe(T1!z6=FHIZ-PcdA#McT5Ho2y`$~6Sdzarhgqpg{TyZMerP{ZBd+N>G?FIIr%U_*0G^NgO<~ zLUOm`(&tpx!Y&2v?C{%4RBYHAEdyhj99tdr`27VEQI}L`^3M?*vF0Vk{aIyHBlcTN z$Z;}dlAF53SU6C%AUqrV;}v<(~zYm88$WnwsmXl0fnD1XfgyY9@C=8>%5l zFj02K!fzFeg?DOa`Kb6bJW0D}9+9=l8SE7VAD4SFlDAOmvoOizw?_W6-lw8|ODn2Z zfw{;&Ix_cAxuBE_rM4AvWet=oOA7~KY|*Hdri)biTWIEUPtLi2Fps33Eq(>#cZ+`~ zeK(KH3)Y)P@vTl0EDXjceMi-thXD@*&?5T=N4{lUqhP-$U7uO@%RS?WL-Dzw_zGsr zK=CakGR9ESm#YjWAp0g=qrk@n53}p_*B+kJ`q{`zJ}dOcA^ZBsJvS);C;q)biQ-71 zj42f#H0io9ST7eq5|oSVt0VLL*Vdg<+y1|{?y$`V=NdLeQSOLA@!d=diTtIU_9uP6 zCQbjRPV)JIduK^<$LOzsTz-~Vey6!Fto%P(vd>U(zLL)_EIZ`h@I}G7?NEIAQzgM$ z@+iKM$yKF)JqsQn&S#iPy=F3i>Jc(=mV7pGf{;P_k^NfAhznZfCI`hQ`AnH~N1>cN z6$kuRqIMcU(kBPiQ$zM1JRJaVgKdX=ekJMpyJf$fEoVt(KpQCOyZAt@7q%~vQ5M~f zSs${mMzYC2=EWR@A^ZNgxW2<#DsvB1P`%7T_O-NlQ=EYZj%sI1*AV6Sl2DVYn3Nh@ z>;lB$|IhfGt~51kRGK~be?>%LMY?nJoLSowy0#&bLg%qZ=JPFmIny|Vfo<*D zJb1?3AdZ@f3;sQW6iN5P1k+!+57QyXf z^3LVR=-u{h=2YqV!#s}K6+Tye@a$CX9l5%qf%b#DpF`45GD_OXZlfPnl809G=p|t< zYRM7T=x0c@u@G(E_q^lRZPfD;H(f1|tWt>iF2kq0C0?GlN+56r$E22Y19@ACI(U^? z+~yGx9*!=;#oi5k97sF;Ho~vt<5EhbubxU^^N4UaBu-pn*F!z4jZ7T^cV8bRfGlu!vBfnDD5nCKCew4t2x({(G7{IAW=l zCDG6EjJw;=u3#fju}?^`S{bJ1oO!fZCPSnW=il3lzuSk&>vrA&usDCQz5il80a%Pg z5_Vn^cK8}PA^WUtcl@2!9ZjQZZDT%!S*X}?hu?!47Mw-VFnu@O&qnO_+9?d*fJcU~ z6G3CYKiK2woJMRv$8WQ%e`Ig7_ucUJJ8aC2n7*J)d+&y9x8j7Q{e45Q1D}8He)PeB z!%jP%7UaKY7&8hyGU>@4OFPJK?=5bRQ#C31Khms>rHe&|K!`YY23ODSmJ`;kLXfd; zoA?6(d-c&AknFUJX*l-l6=8ek>BfP3LVnt?ENQ zwRfsXWrV_Uw2Q@EcB+hB)y%?3Yb8uoSTv0)&VKkGi`Ish=C5^Xt`3^Z!zNc=bVRit zld3sY@3*LmS<(YrLHZ=A!w}8?7P6mPbE-@>cIT@_% z9&faH2!!!vXz$Kowv-ZbgE&P~zV^pu>rs^xC8tip&wo761d3c9mMbn%Z##r2$+M84 z53MB&2ycGQ3zWwJu|`s4oakm3qnQL^5gbBQzG#AFtgjDfl1LphPi5EO#~uC1T<7gw z_26K5#6wbq1&k2`rP?V0?eO>z^e_!Il;d(5*f$h>rP1&GnCUz^)Y`wBnx{t(QP!Na zuZxkXjLb~1(~@@{WFnGX0+NBThkh|G9s&1jlB$-_Q{9!+?5P4?&fhV3@-9lLvZkBE z*uXEz6_FdmN(uJ0hL8%tQzdTe8=Cy^5W=K#lJT;X>xD7QteUv_yP)k>HZ(b}lK$4f z*f~K{$Jkd@m8X-eX+j_9IXk-# zC=V^P?-voPK{axaLVBNh%~A4ENwhB$rmCpiQO)asesqYfmP*CRp#HP#8(OrMI`Td} zCKNmwL}3D3FhkmqA%mmoHh7&3gpt?dGFAXxat>8p10%}B*fq$^;22m#ec-8{!baG<^OD^>`NaMYB z!~v}8=HDpJVpSdDN>@pf+J$oknQ+8%fzyRo=kzh+&Mow&N>)W@Cu``dhAu&otCFQ9 z1G7VMQGxb~z)~5BMcKHb#PFm;{nbUDlfdFx7sEV( z_I0C7_>#q%XHiqYj!7-|OzHXO<`76z>i~^zYu;JuRGivCL>5(yUhPFixVdL~yc?E+ zZ~=q0(m=UQ114!tZ@MIg-g2l3=$v7lzit`rtMY&b?g$mg@KF=a&FK&rGK9iV9k_^Q zAQTu1BpIT#ekfGzr8`0V>$Qro}o!h`#dDhxnXY#QnZEXa>W`z&{J zc>%VPsr6u~EM|B#Xbfkakgz-u0dSGLz@t{tkomIWRbB9rY!%2>O~t%^KDM0-Y@(to z!=HTusadijDUq|xr8)HoQFjf}UBM*WW?{i+nZ48OC49Y=qBw$PTDxa)s1<%ACZ%vg zL}J&~=o1<)l~~60JP(bO^KB{y{Rndkw=mH?5>fj6+aZSe{2vCt_m$qm2%)}fqg4@G z_eQ`y$HFv)!JnTP?xaM`-=pI*`%Oa=f&nHkEE4)ReOx4n#fx($* zYOJf7a);>b&}+ibfGsTw9-R7(47G)n|ZW<6O=o}xeR zJXFD`(tv**9ool4$r6J@u~F3+>+dbhEKu)HMW9M!D)!ShTw`s1czchm@f}qfMz%}PKH(tUG*lx^$61@(YM`F6 zja^XmOW?eCUdknMAzmp8<^pzHL5Oex7S=a1s%{GC@_Wg>iW|@DNtk5SslD{Y{&c#Y zlc~?B#W*=V+W;JxM*ZUcJTdLatVVA*@JwF+xOc1nIPv>@h||;Ev~}~NOT3tT8ac3h zdpxl4b$k1@#?$3DlpF|90g4@of5WAjK)S*;&OF#kQ!={`>37 zq9KQT&8GbodqUN3vbiPf5O2x2nrG^8!Fk@|4x(7g8P z)b;WT_~YgA{r(QX%Dh&bJ7?1V#$`3m#d5c_adBt*@c3tVx^(NO&(X!6_2*;l$idCP znN;q^*Pj8u*sbOG_un6C{SWUi3>p`=xlg8v)Mg#dU8}rBaz_qEHWv=fUhJ%nHvupR zZ@0|O&tyF76S}htOHM%~e13IbvwMzT<8&?TIEWMCi-RZMN%->Dk8V;?W3EDM%p-%| zlI^VhHmY)Sr>cv+tGo1kxSERIxZ&1*H&C} zN^LrL*?ncuT-nl`Eok*M-%K7@KRi5}*1x{+;Yal}T+bdk|J>Y|V&(J8%F%j0kTJl7 z|Du4Kr=zpWJsrL*XLMaFUE!Ye`+Yu6yRyEa86>cH#yA;0jO{Vv=j}dqX#Lo!mFhQC z-Z#Jptz%lNOvd7OsRQ@{|N4~(ogKz#>ek|&-RSO~ZL`#+?cFAz;;Zw^DY1s_1B}icsUjER%Yw_RB7-_DcxxE0jCS7QehXAexq_ z<2P=Pv8-D_Ko+Po5BcitXc}s*VX_ZwxJ!?68~yTUT|Rfe_#U~q;gyxt5Jsujn(RW= zyfPurCo62Sx^cDSxnlENwFNHR16Q%2EX}CPvZ2hlIv%|3%7<9bp+=Xen`>9B^_-Tw z59@s=$or!0AkJ4_rGdf-G_=LUG4?vAXP-rCc7c-Db5e^S7vcG*bM#3r0%AR#-Q5uVes`!Pr9l?R z`bxEQobkYNcoJl2PaB@@JQ@Gw<--$;1S0lm4)?7(`(Wq(FisS_rKfcx2b0^qaZZro z9ZigGh^SM`sZIj39)> z26QIpa{_15i92Ss(|algHt7QZ&%4n&p;yAFy--_7bx+;QWH)2%O1I+a7kTS&5X5IQ zfmi@d4}FhH8+gf%HelN|5V}R(fI=78nj{C{lsWnyjb`wb(Q~Dm|HgGOLr{oF7 zHWi=~fbi4qpH2Y6zdAKHF}BOrLG%E+%e`Qo0Pt0SPW3kM7J#HCK$7NPoi6|GRBZWqkjyXvaH&ScbHs-6(TH#m&l38*eCEh$rU_!FE9QT4WZpJ~DE{_V7Bstv zdj5gnuyx@$-SOglagcuAr+ee2`@Xib^#C}3Hh(FOZeFO~q%E2FTkbeD@qKK+4xXT_ z0T8;6JT$Mbx1O5`{RW@E1MU%cg8Wzm-#Bac?hq$RE>sRhXeg<6V9HnpXC2!xJ9_DSk z3(L)PeQtcd++LWZ}rMWl!&W=hMvY-3n+jhvx(X=k})S-?pFVnvRANHv;b-Z##D{-BKJ;j#BHR znROG3d#eq8;A?JC>E-Zus<%9i8BZ*kn>LZ*)Qg)>n12+1izlptM8$co5tX9${ zHpdUoW!Nm6uMW?T9jD0a8}N9yBIm)5JbliQx5$6NQv9KwycK&6r1$Vy4IDG&#&13dLC${w0@0|I6DpQ+<#2>G6b$+@qj$JXNhfC)*_qC?BQY5$1Z-p`eNSj_n zRj$TnYC5x zpD*uK5Uk6+A`8pF)>i9=(Qk-E#7k<0J%tUtbE#hxT>eVv8NLmvPN>}xT7h`mXXJR8 zq5JSlF@1L`I+q+usQd8Dn5-A&ejZz?mYaKcDcUf^7pQ?OfZEyS(7>+s%%MkYk?_XR zbav^Fzi6$7VDKh6TU+wLX{jUe%N@y7-<$G$iC8>lns$VCPqPGdG|<}RGk484(3TlG zFTiKd_Y(9O!_~KCE_NsP*fU*U#;@ZVYVh)_P)m?XWk2eA6xDvJ=^{`(XAa`&$8VF* zow0`a9>Yec$&wi66JaEIrtqL4; zXXhe?HFIAL2&BItoU*wNfUffe@D-Wrdz)mip1LAhotOwv;<&a5=1E!6$M!e&VmKOU ztYcUhdRt|X?zt)g-dfMK$?f;##OIK8Icg66S$kWepNVtxXcbu_`F(FKN+qKg8j}p! zu|nL;IqKnC_X-Jd)a#~&g!BOWolzdX?qM)i z=dp+Q?YM>O08`M0m*K>e8?-%ea@tf9b#c-;oZoS-lPE=UeX2U?ff#)F4zJ&acu1& ze}d>kZ6wRPMd?nK%T4S;vo1{vf-FmKvHdi7bQxu1tB(n%Hf`B_s!;~w45IsN;pTJcg%iO|W^ zh-t@K&-gq2fK7`{7u=6)g7VZ7;=2?kG6lFlUn~zsfgv=z zRM7a)Fc_q!vMOrp7sGl=!I=L5n~K`pnqY%xcBD!5haC1&ZQRqMlUn48V;}9XdiLPe zW-}~q=lejItCud03O!<;G#HIoVu!PSbTe3}@)V1-Mq!N3ltnJU_~9SJnw{UhMVBzy zM3KFVp212rljXddX;LTNB_TzZ2u`DZC z-Rw;@yy`MluVj<<3pfiAy!jAl3>WtXICTh&?>m0wXz#w*pZ=G@AC(w{^Mu8{^k?bA zh!AH7i-==R+Iu13;!fwGJOurLi#56mGA}OsUk++i$|DPe;b<+VDHKLE z^w<|&RlfyS3mbot&cYNQ+dGe=fn^qQP) z+z)%yUFwGhpGqCIQyshojAFVA#`U&G-*fnEv%0k;ELUy4p`YQ%S1;&)1iPP2BFY8+ zk>1{65L85jd2~hiTK@sa3v6r>u|_?w@hVzEflf|5#gfFq%Ye#|E|?X@CE%% zz~h270yoBs+l%l<{VWMAE7yYGAKJD?5^|)2@iKMI-jc&xug@-;CwMF53@$cGizhmv z#+|_xvlGj#VDl3F4J+i>Ch2Gtl*^gRS?A=67V2iTxO;kA9=3_a0}pZ>EideNUNxT? z&slq(OAx=pU&M*}>-VPge9QGbZr`J@qmX0p{~Kt|sS#5=PdBoBS_}UEA8YVny!KqO zw_0jhvE|Q@!{<%CSP49)7Hn`Z{k%k11did4qn#3yB^;0afRE*WAH&-r-9y|anl zI6Y6txHLVCe>S{XNy#lPJLly8L~Z35h@^UV!!nGnKWTpZ)x|Aqpq*}?9|J^Ngyz{k?`p0hk^t;@v*3X5ZfwKlkOlVA%C`+QY0Wa(K_Q9>Y_aSA!RjX zxmbNyRxBXcBoVcwIwaDlj>#UNs0|;|RD6;eDN!&InFtawB0jNzg#18=P--!uU%-WT zLdt5vP(0`)OvPoJN*@_NR7Alp)bz!|atFzy$~v`rp^&%TfVPFMXakz@NthrhPZ3eU zONy28){K3HG0T4vgJ|WV<>x1T$1>ix4}mh;Kg4Z4NBSm@LxQ9{Oh6o%k1K@lEq}UF z9}0EM+mbrh+smltJA78aTUfb&Frz8omqT*x*V>McFqA6bAu_Y9!#A}vND)t0(vJ-~ zL0!nV&^^1cmQVMpy~(K??lvdro-Kwu`F8|C^&^ zaY&qyNk)d4v=|#(u17-%Nh|d`?JVE z%_zIrK?0K8Gm)b81RN5g-}X?*_cZ@@5UE%Ik}%{>zi5PcW#ymr$7#OJI4HH$v5X;5hEriGmSWhxLet2@N9&^JRD_1i5AxMPVDyH%tXq zTd!FPEwfFse*b4T0;obEH&imh{Qq%EbpHr6WaDY+@+=ZCof3?)@|Z{z(=CT67?bl| zw4O`Y_TO}tpHCV+AO&me>tpnhp4lJj5CWnChfa%a*K}e%i2(6U@VdhU<7Y9-!z2XT zD>9>_rJ>vCAydP+OEMr!Idwuvn3FncJV>bPrD}EBayfR!L^y?|@RlVBmXLP(7uaTg+Q%K^)1fk5Yx# zqt!p_%abpjjZ|KV8i+5f43L9W;;mnmFAT6ifs$jP0;T{_IXKUi|3{|6BEgJ$(s0E2 zpNJ&tk;Dx4%`){Z>Yp~!=ZAs9kIhSy*u;S+HR=s4At3B2ZWx?|;evRNq-1x)r2a+^ zI(0Acg7{$Y$+YCxUR9S`J)D}MaJu}O{&MFzjgr^i*WToRa(tz!+*#;bupeS1aIX(P zlNL)MBR%(vOuiM9TNUz5?@QSJR-s?e*tz(e{5mC(D+F?ySbjKTt* zy403p8&@+Mp_hK~oW<_WAXGwxLM~PRrV4zxf<;rUecwIt&e~oMd3be0io!jWUHSj2 z#JB*VH0$f5`MAA?lgs1#$&pg(38rr6I~#wj8X3MCZ@hkOxf~ zoK#uspoemz#Us$_-uel()XhjLHu$2b9@_Kb%CjSg0~s`9O@l`MZXl@W zE{Eyh$z#?!H#|?c-sv|)(EHN+l3e5WNS?Pb+OTc0z>8zAP;EhN3_;}4 z*N9XQrLfqDeZ)+T0_XI+a;nrCd?qO-sXVxZ6+c7dejZGkp1w08qxxnEcs6qO85wd| zL;u!B94jUjkaLYHrq*GHXmAQ$D$XKPwWm z?dr%YGdiZxuK5hRytl8F2}If{df~x!qXDxb!PASfu2l>qvyWduDstIfqssaU$?N*a z_v>~^0`)Z9WlQKn^;#6vKqwg9oBMlPPIhPgfXxYRe`|XxBVV(ko|g9ayX!EVDN_qW zSsZ3igRw$cShNXBS@@<|hgrOY$s$coje|Nv|A_r&6|!ALG8=Vml|BMe3s@b4lD`U0 z50{TE#+t=^W=gIQW`Q)BA&*`>@!~O{(e)Z+wG^5jVg)e^M>*N%ZVdXlp?H3}JY`0B zNj2Q;`93aDhA>;dH0y>Z=`IRCjT!8$93@voqD4!_D&%j-*$PBf_}RbkVHPbptAl!+ zGGeTu3T&v#Ie7W2qcoq=K>+xuFxmSO1U50&>;Nb+)-VfSCx4{L7p8fn$?9RvzUY)apJ$*_lcXYs3*u_ zS(No3D-mU5U6zZVhvS}{aQP2Zg0v8;khAm%G1gcGHs0j+PoC#lO5JL^dpc|HL2JIu zwt`~y^B7cDNMT}K#D%i@xpc74PYN6*1U|+wS=wBKDrd5`1H+X?~ zv**n&-i2lskI=;CERn-=9P9TD=6^59GRth^kcd-~I8=(vNmEQo=%F-9RcefaKnE(% zw6G3lqmvVK{#?xNwt%F~h3`4Q(^^O$*eQFUGSgJDj? zBcF{G6)(GtJ7tjE0m0Og1?DWLS4FQk<7-lMhWJ$Q?ZJgGGJhyC6bFa|f_(fU->a@N z(4(8a&xLB++UDk3?K}EO0Y4IC4mk~Y_i!W0Sr6#84T2M`D;Hw>Sh+~nL_3D@D^M#? zs|*}GQ!45qN^HF`;JrmyQ6&&}(a#Yi$F@1mcJhN^Vd>{jGJZu^iHgbZjih7L%pEYCR5ZpXaI z{6@}{g$$5a0Wj>L9m(g)g>Qv%0ui1cBzA;xm~oondBC^MA_lu(IP55ZJ&mDch#db8 z3mu#q99W5~2P92GJHVEg#5OeU*v5sH3=k;I1ouY#H0W$>glJ8Z%OZtYXztEJA%DjMB9rYpKcO}mv)_&Lhc&11VeDHCaSaj*vM zU9h3WBdlcON3P1iJ4~9=YBjXRcCw67hdi~IlocjYw_<{VkXYk2iqu4xEZTOp#q!6; z3sfZwdW&Q_%Q}1_3)&c>FDkAg`<_ZNF)Ozs7l&Gsc;*_0%|)9bIv`0u)#|tijwCu) z`l?Gx)KcqB`}AdujgLDbIvH+XktY}@vHsajr_9J;7YGVh7#!_?8uP!j@=hMjm?rCyZSMP8RZX&b>B-vR&Zww-=dxsMgO1 zHld1H&5By;0UYE-7@{Si3S<@PZvV_!`M4a;PuUc!`J~bE~*f<5GK)R z{efEZU0VIBm=K@3`NyIGAYT92#D!)O9md0p1W*iBdLtU^%2rA=K(mx9ggk&_P#aQ3 zfiQprkZGe1(gLlOh%gqeur{pNDYg0wOz^#qXvvBn9?A9|-Bu5#RzmDMR~S2zZLnIg zY0GV;4BbB$cIe9AvX#C=(m#eWo;>zC^E?!d?g>LBf!gLAOZ;k=O=; zV8DcaC-vun!jTn+h78f$tQ8WiLcs1J2852+NApX_>R&Sl-OcFP(!x?QSqwFG?}>@ml2hpF~x!uB~-b?-t7D!G-J~R&?Qu$ zG|m;wLgMs!`Gl|iA+YQ*c}mK=q&K4CsUS2FBjB(lRCqKoL%l>U87jfyg5@Lg`19K0 zfbeUI=JtNrO(VYhzrgmu{~Oru0{rF($^YTV58z0GivP(GOYu){NiVe5ZXSuIyBzkG z2alQb^UypYsv6qNUS|dYF#3TdGO$__Fgo`VR&IWZ67yq_b>9AFBf$G=0PmkG#c%UO zhUwDnE!}M=p|aZTKG-x*>TFKU->Y)mx;Mwxe^mYb=SK#6=0sEb2}d^iuPB6S^D99! z!iu*;pLW`g^Ww;cBq&PGm^&ad|FRrgf7-5VvP=fcdtxk53nAGp4p=X8$86xT1kR~o zS?kR1)EPb`OGxJnCT{j7J8m{evCa`vyvm(mLcVKr1Qo8}``q>2uSC^&?)qD5W*X{= zM$(L;?J513DSapLRoG*rP-R+FD;%BRd(_62JgAl1 z`e55R0dIFCU`OXd0m3xX>XuS6<_P*Be5~2zEUfs!I8f}9(5`zoGmaAkgS3k?4O2;a z>G{4Xc4KIh^@WN>m)iz1kVy7C@ox&Us}xa{E$?*@!MISIw^+$sBak}~eegdDg<4K3 z1n^$s*PZ${)J}%7{`?df#5G}>V)zxe=j+#RXN=)Zx)X<2i=57kfr3Dmb;wr)>b}j! zm7I7}TijM?l}%kwFaAmwZbzMAIj$?a+1r_fK(ymRLR%SwqQDo^M@2@!nAO?4iYvv% zXl24ivB#E}dyQ=|_$eiZ+& z#)9~+t9E$mdpif{&?46&wtTdUdNcS!s~mc1Dp$zgDm($f^Wk&O2C4%ELH>*m(7eI{nmaiZ1mFMCO2Yuqs)064 zaN{A|_bu2IhB-7C6dJPF$ty>I+PR+#X5=OS7$t_=wINuBYrrT=zmItM^-suZAKjxw z-xq2!JmlnQq8*_=YlW0u#h@PBGKGO`*wB2}B0Vku$^E`O07*=Qf0I15;gR7|#`3-i z_UQN&`xYD&sWypAsIWuj_Q3W1D>9u2AL1CiJFOk622lDOPEiR-sDH_iSn_S-{_rJpn>dpe)NdrP>)# zK4%l7J{y7s>=HaFE~6cQS~9%BDgu-#bUr3%%6*R>An4(&ws{e9ywAgD2XOcR7b^kw z<`Fp{_~jx|`6Z`QjkeYLvW9-fUD2U)XS~Qm_t-3 z#;KUnP@5ev?Rr&`25IMgL!2vM0Hp6~lR{d7yXqHx6V(leIF1NLJ5bYN;!5?r)rw9# zGqr9|x9im#v1m3J(ZXYOnxI~r#emf&G@RT2#=80{qZpk;BACo}cRB(uosKa^)%S?? z;Z7hI#<_h%^eQXW#J;d&yqKZexZ%J?IW(t%DH*WiB;g{3WW|+(%nuJsf)K_Om6 zilKswFa$5$$fD4WW9S2<2*2KLuwtC6EEq!d`!fql$l)O3Jl={sg{(7NZ+}L^Jg3elNCSjUyy)Di4Kpm1fD`aR+ZdcIKzxbZOuz39vVMtf7copQ z&8Qe4{+`<&P4XV_6m`~`@Nd(G<`4BZ z!H4gf^95k4*|69oWT$g$6lBi4(w{RhO(g%GH^>eD6s%1$GTB~JU9>0aoL=@fBEGeftif_MzUJ7o%2Vv+G z?I{N3zB`{lSAE(Cx{K(mUH^$;6qx;&!6iq;=i1vd!InH+?STf|PsIQqn)==h6Y@no z1%-Zge@e{EK8XV2ZqeM9sOx_@l)hoYgY72E>)khy_8$j`8vbv7I)|JOp#{tm{(ltA z4iWaP9o)jBIs|{yLnhXTw3;+OnIUSAzd1b4OELT&MHImRVe04S2HmH+R>Q zlyXAT+TNHoFDSsrnAk7$H+M&K*0^9Nz&cDQEZ0)U!FfR6ws87|L!iPiX_!HV};x4tzCY-DMAho4qA9){Fn+~ZFb>;fZQuYtPF1H@t7hUU5>Ov>7u zxA~35f@=a8WfB=yfAFpjTl5{hX81gm!Z_|!4pWy9)!)$bM;%XV!=bAr$e=c7!Hn`L zAB);a7WRkffrPTNDM?y^4c6y{sz}Drw`h3a2Eg-L8AE>`LjHss1H_0dMS3sn`rc$63tY(GplT9KJTQeB24DnlR zm~sTNC88~WTSEYrOIYhBQ}5%YAI~(AYXCXQNr!Ve2~}rPAnQv8YlnUep^SF6c%sQe zIWkIXH)!el0FooA_wW0L5m#)eYTrQr4FYkwg3Im!7I)}}Kiw2+YPp+;3o7;1UHU6- z6VTj7VK|sIhb0NObiJfh2DsWG7(h-#&mlh71^OQ@hEjKC`%w_`1i%HYh6UVpokmRL zoDgw`mkEa)c7S!VsL*qEQ(|)ohd!dOw^{Chxj>h`9`1!Y#QfN`oDj{nl~YGKA>eq^ z1P^!NPu920ie9v)D+Yd6o3p@&$V=cnv%!xnT7nK~al^&fd;ymm`Q>5$N@<%@m48nQ zMBI@W6kCdgewwz(?Z)`(-AL8frLpY7@p;9zF4|wcY06dIndotXjqXh&rfR{UelbBVa3F$&xv6QQy6c% z{!A#Mci>q$N`QtbUf&&zNS5DqKr;#wKX8^BwwpxF^sMNq{I1F+9zUKuShgEB0%EEp z{Zg5rcIum~gPE5&(=eTzG{c5iSzyTi>nBsw?u(0wlI(~E`vOV{`C%!!#x~f`m#D58 z*@*>N8daUuBX%XZwHj_K3W)FuhmA^FtWW5R6H8Cnb8|eOFfH7tLZN)?QRn$jwSC&We)IFp?j&CEh6r ze;kuGm!W;_fEbg;<$ydGAUY_32aT`H5~~t?lpKH>2Rk79d(r%>@t!Gz2)p(`+EL z5qn;F9X=^2IKYh(Lgz^nz+Yyd+VYXPzFm0B4|?Yzr+F|IvJ@u!8h}RU!e<6a7|lG+ zg?t-Xf(j(U3Pv>vHV>589)4%SLlQ($&^-Rq)>o*iAeOWo?3~~3tU_I>3<6Kk?5tAi zrfu_PX4qIG?ej{9%}O9AIKn7#Vn1i$s80aignT5nl{xz3ADY1%*a%m(p2IQ8+ ziAz7P(^(~bZcL#1oAX@Aq%b$LmA7@jP=V$BbsrNBDk&XmQer7?TfF$cJkIy&@o4qG z9%tJH>U0+QIbH+s@4ua#>Wm^;i@Iok4AgchU1@0_ZVm-LX-?ZNy!iVN|e>F&+)IIKQMyE4)DLP3EaCHA(%K zO7R++UD2w7e6V;Y~YCQ_Ji5Xn*VEnI5iu{xoUSMuCYDMclzeV~z$O5A;4 z7E4M3X)gLMuX%9UP?D7W_pe|<=ZrgUCc_XLIMW|-0&(;oQyvh^(6HDRgy`CXNHq;6 zp#g=y6*Pd!TK~1!AThyTFgZwJThp+?zl}tP?#C8jWa*%7tBK`N1*it7st^0HF>HW3 z!Tf8nLE?%AJSm~yg&zcS!qLqmeEBP}_9;P+@K<76ZEp<c~q2Qs}ov8{~K< zEd?(o0OvxFA4A$k+eRxr08%K`E4hg3FO|)i(UNr1@eCQa9{j`xR&WI^{({8~UpU1l z+G~v`kr)!_Vj#PH|M@r{MCLB`+H`i8S$#h$;fIEE%W7JVJhgmwHv&(ULN5bBmv$aEput z1dzBj;s7WrbRv&AA$s}(bW5#CXiv27sP9;oP`}ImacmG#*>pbqdC3hCP9%Z-bTlOy zE&Nk$a&1C1QSoOSThEvtKuj)>0EA|(oGXRAni@dzjl?@c_y_m=_Y*1>=eJrx5ZM zSFY4y5?ayEk(o$4K_Wk=Tq${oSuHf~TZ$BU77d~J%BW;JH0)qwE^Y{5C{21o`rak^`iPtAe2+=1Bi1;J8IE$qz6TbM6-|-W|O%SNK4NKTi{>aE9NQO(X zuSC54UoNk`E;h*3=%`9&bXV~(RJZrt>;7+hAOEAm+D}0V!vRnrpd;x2R$=X{xr>Xn zgXP~hpc*yozy9Pvdfzhay&g0?#bP4Hq}ZpZJ>y6(NTqHitmz3{Jhmq@K7W1S1VPKn z$sD~e`q9BREznMD-FUlr#Q$>(A(t7)76kK} z^wogjV5miG3=3pBt}Jzy7gQM$;*SGNb%UqbJ9b~SBO)x!eAmwOSY6$ApNTYaHithm z!Kjo8&-~tpq5`da1OexzUq-HCvp&yA4f4B_!5)nXVvM-6s1HZSCMRzsI*#F791YH; z6&$=!I9Zko+EF7Am%QYzeBei41y~|XBLNzY+f#v)WQ{jTp*1?fw-=2jjq)#d>!5gI zwlQfwEffZ+&PHj^jyfO8YF3ytG`BZ**ZT3s=iP~b{1&y!PW|To1|F3I7$^602xmu| zVby&j?;C&Y>IQFaXyj=w zqPl~brr4nz_97z>RyeIiyX62=cKHZs3RYS~!+N_0-KXN`rAK(7%&z9zVE(bI|*>D)lM zd;+n}yG|Qj?~A{C7P5j!azIOpIgYfj7H`lq-CVy%R%0E+=U*FFw4$g$^!>d{+ai>8zbrNgrc&Sr;6Odn@FSLlP=ng@g`R#BO>GRIs z937fF8BG!Q?BD2}%V4-;mAtP<75u-pZU};t$M%?1wVj?1(r&CcNGU zaG}0k+Vf9lh3R>qi9(_~zZUV;P{V0+4h$!gff5`6)Zta6%;98!qB{qJA`!AUM%1dC%eg1|%f9K3W7l~r;oRr%Gbue`k!w<9_t*af&r>2H32@K zrGfueQ*t*qQT=acee{g54WNn=_)MoFamNi!3cd*SkQ-G}l7k5G1u&ZDIo#p|mUMW+ zI_6x1QroD*`>vqCeAV>+0<@3NPF2ZxnNp7i#C|EQz!qoZu*i2S4<-eywq1}st>4<2 z8DOvY17UpNt`x(0#Onv4SVt0PMukb@8V|}>6Yt!fkf6} z6duyj$y?8-ElgF{*JpHYC0XxKpxZjfckwLK^!!1+STw{%d1C*X@8}s4_^>wjD*U%7L?nggoGzQO>?ApMuuECA(`)r?K-{+5v4Oc{?^V?qo0 zeTSyOQ4x|A+#@80rL0rn&}MZ4inSM@Zb-6@w8HXQ)ow+YcbcEvmfkF!anT_n-U2IS z%w|C`N0(qt4uI&wJqT9116i&ev_F(eJd6Pm=U~#w! zDe}ubQpOUXQ^u4K3wNOIM!tcj?p2kK0@;dQw5|Ob8`NSF&@Q~5DXTQ=qrfU>ZRD^)Kkn7GSewEyF z%f(3OQz8UCh9rdTLnR#756jSd1`qT!>E_*E4i3b**t5Q;KE9XC?**Iv)w8kY*e2wT zYx0?nYtr+Xu^;-6y+SV^N(Cw9i%oCoBbh?%?_Y#h{`sMdKM1@0yo(qr2#O0??;Pq> zR$~a}rpWRnv4-sAyq}|6>lXj?mpgqeVeae(zW=e7Mn9pgS98-IIyro6x2mV?Mc$@}!5qL2*b>?6*A+tPDD^`nD^LVAVv^%ZX1 z^@QK8Ss58SS-)Ti4FK=Pn;TkmK2PH%(mG80$yG@deR+WV&r>-`n53l%0tl#`1_%iK zzYavXw^*XhfKXY(Q3)1cYtp1{`g%@cX&El zT#rrm2ju(Gk?l<6RO?qykxt-Uq8zT?{r29pjl7ehF=9}fs^J&xbACTO-GHH^C4|Jn zhe#SVuc0?Ab!t_KkBJ41TlNfFH5P)@1IyiaW$1{Y-40-4%uV)cY*T^`V1i|asF_p) zKtK&6pGZ9vX1z>8P=kD@1dEKeMsAU93{9W&h51AUEdIM|qJqa;aP^Ws!=~1>jw)vb z^*2X5I~NWc?F(xzE(8nh&^ffpOOwj%S|U&xD;c^IHQhxEV)?C%A+wA^xAsjPntbbh ztBgczjB?n?MlWP}R>^sqaCz^_d2OnE>jNtcig_1DI(jx(Ym^xny4R$d&QUTR+xl<| zAq^wXo|6mbltG)uwzN?{)I##nI$4a}09JN$a)|4&NCwNX83keFkOis%P^TJu*MNjB zqGAlOpG*ZIW?S6Ox4iZk2{A-@b(M;uMjAHf?VN&L-ghwg{C>XoPpLmC6=MiK^dP$7 zCuIA7`F$MxVib_{?|iwusIM*tGRJv(RW$tbc&4d}L=(;Ret1AwZAc*K|8j&lJ?3N! z@?xzQ3#OId{seS!4Wv~nvw?XO{OChueT;KQ#x%3dvJ!F&zp{y}L05^5zS)n)tO&7pac3!79MjD zCB&Kuayg0%VU};Ypn(s8>D2>EnPHoaN{Fa_!+>Oj*ahCo;;-UE52taJf-xbg#&GD- znNvUIU|}ZB2zg{wg1#RC^8GKz(@e7mv;`FX$cia3)+&SB`h zK}d*E^n4|fy3a(z?8{TqSP3ZMby28cS{o|Mm^&s)&Rd@RBACz-ZPI^BQV^EVUk>fz zq(@Tp&(>~5wW8Z!iDBaCJczf>wtUfcSTGraz5Thw^OLX=_L?-sY)Z9BoPH!DU-Er_|~86*Tpa`L$ZFN}XXpU|8@FAy$;XYv*_+ zE8}-l)3p1P)T}&gf-V$`)`C{qv+o@oqm56@Df0VuAJf0zAI;3YcX1Nf43k zey3oYPN9mES>I2b?9tLPujfGZ3xz~|g#Mmj)MoIQGkW`Y?56ZZ4;<%)9tt;-5wH{{ z^R233NaYn>F($ZhPor^SNM%Iqm}B}X0b0b^u=TE z>y#5M>Ksk7(bJw{&hEJQJd}v*#J#e}T@k#-*8E($0SaMzXibA#z9CvnG;5((a1=Cd zo!*S6&SSYWw@#n1ccNbJ1r^)q5BwfC8j`43d>fjWtva3{L|GAiSDWL6W;cX-`0|{F ziZO37rI7wJbD#RWq31A-G#jQgVAwm}4CCj@w2#6WYx?}@#9@P5>DMxZY3AZlI*Heh zjnhQ|0vh1#n^4P46?KiHgoAFL--!Qtqss~4SuO?K;2;1oD=OgI)b*>2qrH~B9iz32 zx&7bUT;)VBOdt~$(002bv)d}QB|b?3bty5+*8Lni%|0O~Pib$=U67gXC6WX0A)ab*L^f)(qUS zULeILF|1FEtH433)Q4CSG5tntdPA(5?t!^4U&1?&Z%R_cL zyG5*K(Z;8cWNNbt(dxeMif9u5ut(m^o}nIm{{2l3-sSiOetH-%BZb^4WP})nWm^$D z4AnInps$_Xh?w00o6Q%!DZfGpa^zeyvKWd>=WRO7pJFHP@IX7hwvZ^j?e&F}s|`8I z9rbB9;P`6i^5D~Mo1SLCCpL*X{&)%D{m)(6*e)l(3m|L)AddAP#6Kx3IXgOi{kvbY z<2oIJn9wBLbNWnfz#x)@B0!MgiOef?sLO*GjYb8-Y-#e#t_rx}YVGMG z%+7Qks=*ch3U>i!u~^nze~2K;i#YMvd7j&}ncvHmBBngn2A;jBS?NQzt4TQd^08MoX;FBI;8tF?+y5A7#La|;y8tpW;eded-vbQ?S9=q4XFyKoGoYK)(skJ5 zKzqBQ0R#TtZNg7FE|Trt3GKs8Re#AYkLaN$NDD`^Y3(VL z<%&O4^C&L0hOnyx*=|1$cEF0ydFXK@fXx_J%>Cwg{p^$h4_gGJ4LD61D;7a1s*CUa zR!NMF)OG}U6Wb9?6&c+cCDWUFexy#UE)*<`Ss2>ZFB|NxRB~cMCs-L=4nB zZyB!S#hKN|l#`_`?Pm>d(e-rvb$MqiIVZnEBK!OY)jeHaYhNga172smr9}$-#q1{*mIK+uDG^J%;zm`p$yen<9PFm3u^GUo+;qJ*xMr?)hTk z9)zl+8)@x4rf1LOm|?t9VKwpZko!Ia-cF^Rb?==<&)U`f2+V= zn!!fDqC`rziM1CFajn!CoSScX<=ESJznIXS(uh3x!!hK`C#=YG3V(9ux_Qp}gwybR z`rsH1YuTzp|Hs(Z74rU}Z0ZSHFT0@?=h4m8cpBt)>A5MWfye*T*p){^+5PbujGd7+ z`@S!!Bud$rmkHVTC1e}xkQnQr?9?D+%U;AtUih6yR!}P1ei`JU_BXxQnEOpox74WY~5(xFn&j`QU3G?;chCupp*l49yq_A-P@u4$5y z_%({eVJny(3eYtoIV;!T1`fY z1?Pd+>q1L!2a6CXjnZi=1eY>5zkH|7L4aK&NO&S*Vn&1&op6mAGjJVIT~QV)cy$vG z>wAvyQO6?Tw_*^iNbAexg7*V#Z=A{P z9LDhw4!YetnVWd^)}6=Qj*p>MB0}5g^6%zs;%d;QJbxQAceVSledd=f*^qs&18&r2{WMt5DQPDw3!ur z!{@hh?obaDscf%1RPQz`38zO}?~9;~jldO{#gd0TRzpUdFgSf(e2=ZcZR>EjAJ^Yk z@~@Y9i#@PsY)#Ocz@sheBYlkCd?%n$U#h5;*~B*%q}ZoZpQQ((QqskfKA&_HqQ3^! zn8#YJY_qevThYx=!7R&7KcBhU=31^Rlc5w**fuolSWcsyz*)?CNfBkZ!kscGFLb{l z;S7rALhVebEX3zVJK^+h$sDDjf{Cej4XHC9Peby@h!+{ zQ_Orak>HGBQsLKE;{q6v8D&;fMJ)jqwzC_SC{VqEsov zYEW+OsoY~z-&H^aGd6*~xeppL5L!U-Qqkz^2zv23iv%qBe;p5Rhb1x~qme|lF9pWB$qS0XsoR;g8t z_qO&heQ>1(CM9cn*gvUbDp%{tjR@}7wUSI#5IQF5aO%TtchhM8nn@O(7euclz_zTs zD#R)Zu{uuJkIv#A;kS--%I@pEwut>@{f37y$F#pIuea&v^Wh+v>1UO&9 z6WP9>HU=SM5G_U2tjJ-X5jqjLS~S4_dAz! z4f|bNhL*^U=T$z98?Jk$lk5TYYv=y0LU&SGUdTO>1?o#X4b@S;U}r+DZ>)MfZo zdDS!)uVaUEv+Kd3Vh3!M2^pfRn>xu-3W0{;QWGP;AEwXL0}rH{3jou`Ynr}K~H z+H->*&v8kr#sxv~>W)NO=}PIG3vp&6nVorQQaAdjh$D-@A{D_(LR$Sc(1z`mu@NjN zQJ{;@QTn+Aw`lcr;Qo3=bVj{!B^Psu0qQU8I$SPNoJGgcfaKuQM$a;tdWj969chdj z*1%}jb=OI!%{VIWZP)v1HHUdKHq{58Qv2Uz%8S9C4pVDiwC@8M-UO%26Pp; zNSv*Yl|bKXta3A!?-H`g4{v|R^jaeNr4gQ-NnYdG zrGjv&L$|KX5`!-RF($sGJs<0mz_w(()F$K|ZNhm&hGDQMsqLerOC4RMD%-Bb1cI{^ zx+D#BB6MoGtWr+d{K^wC|43`{E5ohgK-~^Y<%gqePkjCJ0b4meCB&n(x}ofA?}Y@j z1g+U+lN=0*s3&vVyKJs0)|h$SBboTr4~)QG74IyXE7>i6mZt1Z%jl}OR+4g^1@$*A zgnCKj%pSsXLI@Jp4Cr*GWy~vlb$Tu|Ujt!g{|6gt$i94DhYtx`>Uaf^ya7 z@GJQSUON7y@3i_{tsB94SajGSV5Mh$5cLwV;OxHG$&O5Gbe=zJoVzbeIyAIRFexea zSFL=G9_}ROL=tX zZ?5XBx1IE69jQ{^i);6pryqUOrgzZKM#i;>)sI**99qESM&0(dn;17U&??P9@*x7Z zW+`@_6mLU=7hzKx0Zo#LwC5|#y231;*mlKN2-_@w5&X-W;SA$sA|Huf727 zLCmmDpdKzdeh(lhrN0>7Hh#mmkm|EQO4r3Z9A_$+?M7274Abn$kqGNNRr@cB$` zaxT7Jo2#F<>fz2tSyRx_Kli`Qjl@;(g9E6&M@nf1tDn(LwsX9Vg5-@$QwNptz6~_L zNSmm4O-q3RiI{&DeRDGPS&|15Kh#5-<-Qmn`Ktxlm@Aa-yiYf4zv!2FEL^J*g|4bz zGr`iKx^k1noE8`PZcb9L`9xfXJ%xOPR$_zUYeLHb<0}bA-8$)qWZD{FJTd$qRvR(M z)0Mu#1)g;!Djg8yv!?<9Zh1){fQsX1ambgd5oK~FJB0j)Z&2*S%3Zg;%@0k;oubI1OR z&kG@vJq5S&PT8Bd zcwF!41mBPRg~xTGa4B$Ay%UNW)E_lITmoG2?1TUv`a8j&q%>SETs`W9D< 本文档定义了团队代码审查中需要遵循的自定义规则,涵盖安全、命名、性能、代码风格和团队约定五个维度。 + +## 一、安全类规则 + +### 1.1 禁止硬编码凭证 + +**严重级别**:error +**适用语言**:JavaScript、TypeScript、Java + +禁止在源码中硬编码密码、令牌、API Key 等敏感凭证。检测到疑似硬编码凭证时,请使用环境变量或密钥管理服务注入。 + +### 1.2 禁止使用 eval() + +**严重级别**:error +**适用语言**:JavaScript、TypeScript + +禁止使用 eval() 函数,存在代码注入风险。eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代。 + +### 1.3 禁止直接赋值 innerHTML + +**严重级别**:warning + +禁止直接赋值 innerHTML,可能导致 XSS。避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗。 + +## 二、命名规范类规则 + +### 2.1 常量使用全大写命名 + +**严重级别**:warning +**适用语言**:JavaScript、TypeScript、Java + +常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE),如 MAX_RETRY_COUNT。 + +### 2.2 布尔变量添加前缀 + +**严重级别**:info +**适用语言**:JavaScript、TypeScript + +布尔变量和方法名应以 is/has/can/should 开头,以提升可读性。 + +## 三、性能类规则 + +### 3.1 禁止三层以上嵌套循环 + +**严重级别**:warning +**适用语言**:JavaScript、TypeScript、Java + +禁止三层及以上嵌套循环,时间复杂度过高。检测到深层嵌套循环(≥3层)时,建议重构为扁平结构或使用查找表优化。 + +### 3.2 异步函数内禁止同步 API + +**严重级别**:warning +**适用语言**:JavaScript、TypeScript + +异步函数内禁止调用同步阻塞 API。在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本。 + +## 四、代码风格类规则 + +### 4.1 函数显式类型注解 + +**严重级别**:info +**适用语言**:TypeScript + +函数参数和返回值应显式标注 TypeScript 类型,提升类型安全性。 + +### 4.2 禁止魔法数字 + +**严重级别**:info +**适用语言**:JavaScript、TypeScript + +禁止在代码中直接使用魔法数字,应提取为命名常量以提升可维护性。 + +## 五、团队约定类规则 + +### 5.1 throw 语句携带上下文 + +**严重级别**:warning +**适用语言**:JavaScript、TypeScript、Java + +throw 语句必须携带错误上下文信息,便于问题定位。 + +### 5.2 禁止遗留 TODO 注释 + +**严重级别**:info +**排除语言**:SQL + +生产代码中不应遗留 TODO/FIXME/HACK 注释,请在发布前处理。 + +### 5.3 公共函数文档注释 + +**严重级别**:info +**适用语言**:JavaScript、TypeScript、Java + +公共函数应添加文档注释(JSDoc / Javadoc),说明用途、参数和返回值。 diff --git a/data/import-verification/02-standard-formats/team-coding-rules.pptx b/data/import-verification/02-standard-formats/team-coding-rules.pptx new file mode 100644 index 0000000000000000000000000000000000000000..38887a8024efe18f02526ffe27ec08b95839c005 GIT binary patch literal 36549 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 G_x}J-4casS literal 0 HcmV?d00001 diff --git a/data/import-verification/02-standard-formats/team-coding-rules.txt b/data/import-verification/02-standard-formats/team-coding-rules.txt new file mode 100644 index 0000000..fdea5c2 --- /dev/null +++ b/data/import-verification/02-standard-formats/team-coding-rules.txt @@ -0,0 +1,73 @@ +团队代码审查规范 + +本文件定义了团队代码审查中需要遵循的自定义规则。 + +=== 安全类 === + +1. 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 + 严重级别:error + 适用语言:javascript, typescript, java + 提示:检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 + +2. 禁止使用 eval() 函数,存在代码注入风险 + 严重级别:error + 适用语言:javascript, typescript + 提示:eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 + +3. 禁止直接赋值 innerHTML,可能导致 XSS + 严重级别:warning + 适用语言:所有语言 + 提示:避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 + +=== 命名规范类 === + +4. 常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) + 严重级别:warning + 适用语言:javascript, typescript, java + 提示:常量应使用全大写命名,如 MAX_RETRY_COUNT + +5. 布尔变量和方法名应以 is/has/can/should 开头 + 严重级别:info + 适用语言:javascript, typescript + 提示:布尔变量建议添加 is/has/can/should 前缀以提升可读性 + +=== 性能类 === + +6. 禁止三层及以上嵌套循环,时间复杂度过高 + 严重级别:warning + 适用语言:javascript, typescript, java + 提示:检测到深层嵌套循环(≥3层),建议重构为扁平结构或使用查找表优化 + +7. 异步函数内禁止调用同步阻塞 API + 严重级别:warning + 适用语言:javascript, typescript + 提示:在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 + +=== 代码风格类 === + +8. 函数参数和返回值应显式标注 TypeScript 类型 + 严重级别:info + 适用语言:typescript + 提示:建议为函数添加显式类型注解,提升类型安全性 + +9. 禁止在代码中直接使用魔法数字,应提取为命名常量 + 严重级别:info + 适用语言:javascript, typescript + 提示:检测到魔法数字,建议提取为具名常量以提升可维护性 + +=== 团队约定类 === + +10. throw 语句必须携带错误上下文信息 + 严重级别:warning + 适用语言:javascript, typescript, java + 提示:throw 时应提供足够的上下文信息,便于问题定位 + +11. 生产代码中不应遗留 TODO/FIXME/HACK 注释 + 严重级别:info + 排除语言:sql + 提示:代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 + +12. 公共函数应添加文档注释(JSDoc / Javadoc) + 严重级别:info + 适用语言:javascript, typescript, java + 提示:公共函数缺少文档注释,建议补充说明用途、参数和返回值 diff --git a/data/import-verification/02-standard-formats/team-coding-rules.xlsx b/data/import-verification/02-standard-formats/team-coding-rules.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..a23405bdfdfae16ce3cc85899fc58b50e1425224 GIT binary patch literal 7828 zcmZ`;WmHsc*B-hXDM7lW8KisYE@>nkVCW9%Zs`;WLAo2HJEaj}7(u!O0YT!!$M;)4 zvflTsbx0)gXA|U_(Km|D4qZ!EzD$Awae~sVYxc9e(gSncsgQE+F zsiPyiryWE&UKyi@6Ic39VSA;pVOzpXVzyv=*hlFZUxG!NMd**CcR`d*q+u5?zSGl6 zSmA(XNi>%D2zcz0S=@ubQPM$L=8owFFd8oCBf%{;@+naoI-Su*Bi8qr)*((3CZ;^w z6za$G)q}j*?c=&rHT*gl68l_}vLT@=dJs~- zfn1RtxE5`A$R29!Zr2nc8nBR&dvu3f#3P@X{*8VxB!fJ4j>OlbQ2wzyl>+|TbOdCh z-Sle8U}!%%Z;Ifi2%TM=cl?y&hp>Rc3I;5KY6XnfB@<-U+%{2{F-=z8#gqFl(}4j` z5YDy4XW`Q`$!4s-Qy9V##Bhe6h={l0ZtdhQdLis*lSdn9^m5Kh32l*0AhnB$bxdsO zRB{yh1VeyCj62DWz3k%-2RFUvuS>$7?L|R#uI*X%y=V);VhjtEe$QdJ70WID5MMkk zit8(kvj^JAFwCY!Lk0k{836!-d+m5aI9$P&c9y@NT)*^lpl_tP%uo1g>p8fd=VxOq z#UOQFI`)L@5?ei{Mcd5aW7!&Qi(y)3@!Oj?2>#PSCop5Odz$c??!3T7uk3|B_TbT> zW|)1Xmew(#&4K*-aAS=m&Q($)=umTD4iAz4qo9yYgI00^;q2qrcz(IHEeXuvGnt`g zV3MP(S9Yz=vQujXA=6-llmh&HX2?Cp@ z1N#F;IbXMIN|2TE4PL-~DDY)CWY{n^?-SpFOM-Jh!LhFp&?g$^BIoLeu9bc^A;xDE zNp(?eH#6+ny6G~Qa|^59RbDA(zUqG=~n%gEp6N#t=GPfFu>5uhQoJLuGGW~oS5zml{%nImm;$rajrSH=*+XdjM>X_d zcDh_*&@q{F#Gx^XWKJj4N+J#hW?$6fQJi$jHU{1Bjl`6vt$0&UAT0>#n4z15l4De| z?P2nMmE+*y4v#?e1ng*Ocz&nK1-<2c=gg+DTt(WH5Jflc8gMrfus;16>fc5gzuen& z`SEl$|4XzvvM}SmFgZ^2dKYV4@p_Z8%tXN8BU)4cZLh%p76_kR{a@%dU?A+Sa zr@hAD>YSRRgPvXV#=Y>Cm0nXki>AGpu^NBDeO~7rh4j=G23~sfS9BiR3WZ&dSEw{E zbEf3sXM-eZG{BNEu4dGt?14adNi%50Wa5b)?U$P`WsfG^XoxfUs72{YLYr}eLM8bI zZ@Zh-<6d>IQ}_*oNF9+Jm$&EN=2v{AQIu<~Ie{oimaDOoI%09bq-kB0KjTh^+)0+W z`Ll!RLh)Ts1{vuWeweGOT zM;9!YRS=Y%LcR4iX+XR(jl0%9dm7(UDP6pPRJ|1MTAsZkK@?CRlT7vaDbCp+e zLL!3Og2^5ktx(U!FqzSEDtA`~6?t1@+v+Z)BW%3o1>p~S(5oV8|CdfzSp)JNB;zTe z^#l{w*?&zs2G0oo+qEKj18c+dp|Su zp%YQxW3eXf?fdzh8$iCFfkkb6u`VNv4aVHgmHVP4hy`_AmitciB$Jo(KbM}8Rwvqq zG6EOP`J?DJg5}U}aOQ^H;7QS{+uUCQRrNlU%c?VI1yI;}Cuz=k_1m(KxN!|PnMf`9 zzUAmEPv6pBeXbW+xv%rtj?}*?Y>jm0Cwi}tZwcq;ASYF)=39dG;|p9_E{)e2Ui^jR zaPbKH?#m!oIZ)To*ib#qNlLcAXlxmx)rQ2z;Y{tW_fMU0ua6C#{8y`r{WUl#X$U*Q zK-@c!#o>OU*Q&KmW?0_WhMW*5SK_q~&~vURDvaaozyT(OI=z4t>*_AECu?%cJInJS zZ{A!h>^51{Cwdm!f10m%u=WtJV@P=tq=5d#R|nV@vrt%i;4#MLwQAV#MhLxX>$X&# z@FftP@l+tvwPHjujio4>)$PpqDevor;eBl7B}wD%r(H$D{3PS=r{V0YR4f8w8BTcG z>Smu8?H&;Uk;;F34Y5QM{yw*Q?yWgxR~gZ8H`k^{aI)@5FFTncbcC{5nWxjad1&c! zp(cdNxC)Vy#w(PD=kBNOlH8TBYj>s_Cjx8Osd*@Vn&HUrp z7&jT?Rn&moG=G=i>kz|TlnTEr?TbABg+*i1rS}P0Eu5qyHq$)xO(DukTt}J9A?md@ zDp_s|Jq~*NDW+|WD(m0w+&T2MDk^z5P0`@UwKLb_B3>$My9!_GpWlz)4={{u{9Zl-4EuE*7E#NjD(bn=)v&|5z zs%>G>QP=iU>o?P?#2}@Y0jI>`0wDEK)4nf&zE4*Rq{g?bpH6DG>kYTpDxhb8v`bH% zGb%^BUCm^g*@_4nN@{u2nm}syI%V%YFX?#BT)6{+HwTPbb#<-=z=C?R7y?OilzYo& zyg4!YZ1Sy%UKyprOdHo0j_6{>lI2Ka1pY-QCHuZO_2y5KuMA8K=@}8;vL$B3G(<`e zKHn)2PSPs^Vg;SNtZnQ&Y!A8>3gETEXQfsmMayHmZ0opcF|>H2^*yP>JMd65x#} z$0qI#zxWKk0tu`NxJ1-t>xwz5sEa9{EMUo0K|doTyxQ5Jn>QJACf(V!NZ8CQ*VD!< zN~+IRDYed2l9_Ymo_=1?oO)SrP?Q{BD_2GwzOiIKES>7~x)P{~4Le=wVbx3hC@F}@ z;f`UY{$WuXLr+ke!y|fRi+`E!#G@%pJ@1Wve8K$sP{GsZy_Q;ZH3}BoF&G&`?Ft2B zmh+6c*m{JejsmNUj=mw(h_1fAA(Au!x6&juH^W?1>+7_bl89$O0B)9TT=T6op~FpF zu)&kGJ;T6b%b6Do3;f82qa2~{6zd5u6W^vV%-+I^QlIAmW04cfIdawvzwzk>E( z8i+Wc4zP7Es#g2P)WQbp@WfzJHT_3}?zZyqc7vU_6zT8kNi@1WUoztjAO{k80FVx7 zs=r>X(>|r*eea0=o7+lgQBCIV%~c zOi0oZvrG{|#jRc&{>?_I-)z4;ME@p8iV?XAuEErtf%(Z_)` zxw?R?rYnKG)j3ortt02h5mda2D4?t?CHt<31i=MI(Kk6OM%l(DuYOL(FE!0n5sOWz zyd*w<2E!CZ84G?ZxYn_-df?R*K?^s`-z<7_yMFlP_OMfI!v6M$`w@J|t&~92VR&Q% zXN?G_2vf>16J;fafNHK0?dZ^anQ#M1j|n)u7{s*7I;t~52+M->=)l}g+MlnM>o*3fWpK(Myc z*Vq*9-RaCExO9ZB?dAT@F1V^Nu(w^Rb$E|ybMDL4ld&7&G!8FerBlP$Lvx|BxT1K68 z@pn5xz^a`><5Rt4rWWVxjmlR3nK!`!mIF;iBCfjhY&~_sPm=%ri$2Z_`d2I^2pG=H5^}t{wwh zATV>ht4-xu7o8bfB`<{=@{(bZcE2Pn6Ua0g8AB`xl zr14XJm7Z0Mz^Vcm7MI!p_3J^{iG%iXh;KtH#y(LpH+uAPu(cCA`25phP% z?J2e9f^qhcr8Cs7R-`Z3foiDB^OXyacuXa!kgwVwe}-m5W7w-cn3%+f=DvA_CCJP= zixi*qjzY()e5#lZq5VaxY@>sgtiZhVm5jQJeI-tt94ol(QU&ta?wkw>nmm%b6i2Lh z+`xhJ?M(zvRaS4Wv;ga?DtHd^TjUP*$75FTpY416NM|4?egZQPW1>%@v&-5r-)l?v z$}cYneIuU~NcXqtn|HpTmEo;FvU_g?yJ>8}$(3IGjtt4t8Pr%uK(-@;*uYugbRM+T z1uM))MmP8BUkbs`RmOdIRpkKX+`Hp%j*9|irb#et%?$&5QFo}A_7#17)Jqz?%C6p) zDpZUuyopZ-ovtqN%N$B^e0OfsBdIos0Rrf9DqD)@LVg>nVq`24{ zx-<(_vA7L>WsWNJl2~QES1)p~05^}{+R|4sjyfiHbowY>(#8L!tf`7V z*1YwT>m0Z6>3EgnRRsAm=Q{nlcbn6=^Xc-?y|w6$93}8@RB}0Kd5aAn9kZ@^Gf_X! zbG9WXdLhPj|;45GbdV&oBPKz4YkVE z%~0uWvxUiF6#KgHBtdiZw%)@y^T#B;p0TX znSIK@V-0t1qOaI!lD=}CvSgM#$>*CPSq)22^)V(vryZa!Y>2F_tyrHIKN;>}2Z?iZaIZ)qq*U891kOMjNYS zvbQ~Cq~4sN_S(6+O1|b(^IY66bv3U_fWeD&Zg}{8U*$@AV73 z7ukJ1*Vn3-kdMCjVf~HcGzQ6aAc4pfDfe#!*Bb)K8kv*H)1{@h<@s$!d_fdCO|4-j zt7JrvIXT7FcFY?F+G16Qe!2vleeXc)=I&?28zrm)QeC#f1yB1nafx+xwFZo1|Csz4 zm@(o~iryO4AC~iiJdaT71<@&w{(_vFP4nqZw~D;BdZsL3R8~!!1ilzgwi=ZR8MCDH z2ZisM2nz?aO|_0zT3RNF7fQRmC%c(&bo4;mN7H;?JR=h9rMIvewK1qM=LEAS;d6&&d z^!9A!ZD+jH91{w9XOfx)wYOm8i*E>Rw0{e#zN)&d0tWyv-wTTKJN$kfEzBGoY<~q{ zta`UXuQ={aN;TzLQ9hDlVst){bTnIs>V0pqxsAZRSjR`__{+y&lQoVXQc=0o@=QeS zo|&&4QU`q;YJuU)iI;pW9`l2SK$-*TJusOo?nN`m{|GYP9oQ#={YyQXogKml$q%<`B)|v@!e}Gt){B@;>olHcA|WxGV1(*H5F4+N$tv>dNM=%3T@q_!CicE86yki@{G{J#~l;5 z-LP#r`m>Qw=GB`cCY;}|at6*7`f>hNJ>8S6{PKI1|F~B_*>BbVcC&vQ;2)Q3c-?^> zERGvu^0gVoaZWtyt&a6HvdP-i9KliiGSGWEJ^+D6UDsoOm5BdeL)SEuPXR)T%SAeIimi{co6e1=hr*p>9&a9?+7fsY&!nKn>wf8UwOf^86LJ-yjK%d}X42TZ{vBGSLQC zG|x|e1dTQ!kcU-@{w?FR>E}Y`d-)U)fA>5Mq#W#BE$v-Rw7eWGU5tLYSVgk3Lk}lr z*quTOYknYwdpc8^-9l{dp=N3`uMNIzW8leAacX>TpCChX-)pnZ_?%}WU(9m@quImy zQf#D8lI9_gBf=EN5?V=Y3c(?Yg$)w}jaFD!rhGoLL`mX_CEv+xT08?kL4pXYa>UKz zOEeGzwZHkw?dzp*3!pf}dMbHmea0F2F2{t{lh7MGDZFE*c14pXc1ht_?gNE??V(nV zIh+-##=L?wUW?Q9wYe|!Nlj%3Qn)(-wft~K7r#A#F6@L#kd#po0S|lc+Uk~y2iX<; zJS3w56m++)lKOpaMkzh8FFxLrAv4?I4UTscMKkM?(Uef3`*H9Y?xx52k8*zyrAfp= zN3JgADA@NZ_-JU~SO3)dv?aR9q+fk6WWJZU_8R$b&3?AirIox7+FT?6;PG$ov2Zr^ zu(p5c!ttLM6A!z8+5$OR({fWj-`z5k_P(C6(5*l!mAk2Jj2DC0Wc~>IvJo zE;FtT1qwN!R0Uf3_uR^%*7(%yPv&;kh}5;Sm*dHTBzzc6y}97>40m}B&hbTGwTpGa zqB1(C^YrtFF7=lRqTa6DVLpCohLHV%B`z;v5PTQY8{F^!&s~ z3afMXu}vHuwnz=hCbWXRC4|o5@e^Rt-lF7!4qmu1NYmpqb!Rc^JYyH}j5=gU_(_G1 zR#zr}EuM^TRb?x*)1}o-!$xOl%-39>e7rl3O6+XPMb80;SQZrP9*@sL!5AZCf8tgE z+fWiCU!ZekFh%dl)5aI2Wv!Kqw+m(G*Fa@oy`r(o28>!5=Hbn=Mn;>->Lk2GOG;{I z*zjmuOlo~xe45j9Hx;d~U{v@VSlo4#+(bi$FZWKkJZ|tJ5JlKdKYsMm$4-ej5@Q`1 zVy-p~n!7>oweKIWvW)lIt8-TVlEImV`$3qR8Mkk9KC4t)*Df`L4fS+Q^6UEi+xbPl z0dcoAtTdUkj>|PBr!U}h75G@I=?uF)y(CT&hr?0W^*KVsF^#EU^yvt%6L85-BZa8_ zqaI|5Q%Baivja#M2c|Pr{vt+WJqSKQnD5&070tb%zsmqg2_z<7gGTX*k@bYSEi2vA zS36dY_0V>#83xE;wRjg)1feB1jOpKH8=;c@?Bg2x$qlPpkGt<2eQ4(6e-Y?QF zpihd%EsqvJF40AT{_c3=2b`ZX&Q}6V-U}jO91zN=jW&GocQjtu`1bn7Kw{S)l0NmB zULCQanW)BK>Wb$liwTG2tk3X^&0Y(?>ufQAnj#!LJHr2-)7^{z&s7-sYk4@edx(BG zAp4C4015;9|Be3taoI!o!wJ$K`1-vm{>wb+A;H5&;vWKv`}X2J!N2VI$AS-89+vEX zST65Jm-j4x3iyZ6hjrB-X#D+1>|a&ZL*TG*$m*RhI;SY%(hTtEf^7~TaZ$tjqfK*dN Vx*tXUDsC|Vi}z`y=vNK_{2xS0+%y0H literal 0 HcmV?d00001 diff --git a/data/import-verification/02-standard-formats/team-coding-rules.yaml b/data/import-verification/02-standard-formats/team-coding-rules.yaml new file mode 100644 index 0000000..4752852 --- /dev/null +++ b/data/import-verification/02-standard-formats/team-coding-rules.yaml @@ -0,0 +1,96 @@ +# ┌─────────────────────────────────────────────────────┐ +# │ 净码特工 · Code Purifier — 用户自定义规则文件 │ +# │ 文件路径:.code-review/rules/user-rules.yaml │ +# │ 格式说明:YAML 数组,每条规则为一个 - id 开头的条目 │ +# └─────────────────────────────────────────────────────┘ +# +# 字段说明: +# id 必填,规则唯一标识(kebab-case) +# severity 必填,严重度:error / warning / info +# description 必填,规则简要描述 +# message 必填,展示给开发者的提示消息 +# languages 可选,规则生效的语言列表(不填则对所有语言生效) +# excludeLanguages 可选,规则排除的语言列表(优先级高于 languages) +# +# 内行数组语法:[javascript, typescript] + +# ── 安全类 ────────────────────────────────────────────── + +- id: no-hardcoded-credentials + severity: error + description: 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 + message: 检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 + languages: [javascript, typescript, java] + +- id: no-eval-usage + severity: error + description: 禁止使用 eval() 函数,存在代码注入风险 + message: eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 + languages: [javascript, typescript] + +- id: no-innerhtml-assignment + severity: warning + description: 禁止直接赋值 innerHTML,可能导致 XSS + message: 避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 + +# ── 命名规范类 ────────────────────────────────────────── + +- id: require-constant-case + severity: warning + description: 常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) + message: 常量应使用全大写命名,如 MAX_RETRY_COUNT + languages: [javascript, typescript, java] + +- id: require-boolean-prefix + severity: info + description: 布尔变量和方法名应以 is/has/can/should 开头 + message: 布尔变量建议添加 is/has/can/should 前缀以提升可读性 + languages: [javascript, typescript] + +# ── 性能类 ────────────────────────────────────────────── + +- id: no-nested-loops-deep + severity: warning + description: 禁止三层及以上嵌套循环,时间复杂度过高 + message: 检测到深层嵌套循环(≥3层),建议重构为扁平结构或使用查找表优化 + languages: [javascript, typescript, java] + +- id: no-sync-in-async + severity: warning + description: 异步函数内禁止调用同步阻塞 API + message: 在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 + languages: [javascript, typescript] + +# ── 代码风格类 ────────────────────────────────────────── + +- id: require-type-annotation + severity: info + description: 函数参数和返回值应显式标注 TypeScript 类型 + message: 建议为函数添加显式类型注解,提升类型安全性 + languages: [typescript] + +- id: no-magic-numbers + severity: info + description: 禁止在代码中直接使用魔法数字,应提取为命名常量 + message: 检测到魔法数字,建议提取为具名常量以提升可维护性 + languages: [javascript, typescript] + +# ── 团队约定类 ────────────────────────────────────────── + +- id: require-error-context + severity: warning + description: throw 语句必须携带错误上下文信息 + message: throw 时应提供足够的上下文信息,便于问题定位 + languages: [javascript, typescript, java] + +- id: no-todo-in-production + severity: info + description: 生产代码中不应遗留 TODO/FIXME/HACK 注释 + message: 代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 + excludeLanguages: [sql] + +- id: require-function-doc + severity: info + description: 公共函数应添加文档注释(JSDoc / Javadoc) + message: 公共函数缺少文档注释,建议补充说明用途、参数和返回值 + languages: [javascript, typescript, java] diff --git a/data/import-verification/03-irregular-content/result-report.md b/data/import-verification/03-irregular-content/result-report.md new file mode 100644 index 0000000..81dfbec --- /dev/null +++ b/data/import-verification/03-irregular-content/result-report.md @@ -0,0 +1,94 @@ +# 不规则内容导入 — 手动验证结果报告(7 种格式全量) + +## 验证信息 + +| 项 | 值 | +|---|---| +| 验证日期 | 2026-09-07 | +| 验证功能 | 自定义规则导入——不规则规则内容(重噪声嵌入)的 7 种文件格式逐一导入 | +| 导入素材 | `data/import-verification/03-irregular-content/team-coding-rules.*`(7 个文件) | +| 导入结果 | `data/import-verification/03-irregular-content/results/irregular-*.yaml`(7 个文件,已全部移出激活目录归档) | +| 规则基准 | 与场景②相同的 12 条规则(id 亦相同),severity 基准 error×2 / warning×5 / info×5 | +| 噪声设计 | 项目背景、团队介绍(12 人分工)、会议纪要、部署流程、版本历史、反面/正面代码示例(硬编码密码 `Admin@123456`、eval 调用、三层循环等)、内部 wiki 链接、Checklist | +| 验证方式 | 在 Extension Development Host 中手动执行完整导入流程(含预览确认),每轮结果落盘核对后归档 | + +## 素材矩阵 + +| # | 文件 | 格式 | 导入路径 | AI 内容转换 | +|---|---|---|---|---| +| 1 | team-coding-rules.yaml | YAML(噪声全在注释) | YamlConverter 直读 | 否 | +| 2 | team-coding-rules.md | Markdown(噪声为真实正文) | 读文本 → AI(freeform) | 是 | +| 3 | team-coding-rules.txt | 纯文本 | 读文本 → AI(freeform) | 是 | +| 4 | team-coding-rules.docx | Word | mammoth 提取 → AI(freeform) | 是 | +| 5 | team-coding-rules.pptx | PowerPoint | officeparser 提取 → AI(freeform) | 是 | +| 6 | team-coding-rules.xlsx | Excel 单表 | 表格 → Markdown → AI(spreadsheet) | 是 | +| 7 | team-coding-rules-multi-sheet.xlsx | Excel 多表 | 逐表渲染合并 → AI(spreadsheet) | 是 | + +(无 template 轮:模板路径为严格表头校验直读,不适配不规则内容场景。) + +## 逐轮结果总表 + +| 轮 | 格式(规则名) | 检出条数 | severity | languages | id 与基准 | 去重标注 | 结论 | +|---|---|---|---|---|---|---|---| +| 1 | yaml(irregular-yaml) | 12/12 | ✅ 全对 | ✅ 全对 | 逐字节一致 | 预览阶段独立去重 | 通过 | +| 2 | md | 12/12 | ✅ 全对 | ✅ 全对 | 漂移(语义等价) | 3 exact,指向真实 | 通过 | +| 3 | txt | 12/12 | ✅ 全对 | ✅ 全对 | 漂移 | 3 exact,同构 | 通过 | +| 4 | docx | 12/12 | ✅ 全对 | ✅ 全对 | 漂移 | 3 exact,同构 | 通过 | +| 5 | pptx | 12/12 | ✅ 全对 | ✅ **全对(零丢失)** | 漂移 | 3 exact,同构 | 通过 | +| 6 | xlsx 单表 | 12/12 | ✅ 全对 | ✅ 全对 | **完全一致** | **2 exact + 1 overlap**(见发现 3) | 通过 | +| 7 | xlsx 多表 | 12/12 | ✅ 全对 | ✅ 全对 | **完全一致** | 3 exact,回归同构 | 通过 | + +## 关键发现 + +### 1. 噪声过滤全场景零失守(本场景核心目标达成) + +7 轮全部通过以下陷阱测试: + +- 项目背景、团队介绍(12 人分工)、会议纪要(「决定在 async 函数中全面禁用同步 API」)、部署流程、版本历史(张三/李四/王五)、Checklist、内部 wiki 链接——**均未变成规则** +- **反面示例陷阱零触发**:代码示例中的 `"Admin@123456"`、`eval(request.body)`、`maxRetry = 3` 等错误示范未被生成为规则,也未污染规则语义 +- **叙事与规则分离**:如「上周代码审查中发现前端模块有 eval() 调用」的叙事上下文被剥离,只提取规则本身 + +### 2. pptx 语言字段差异根因定案:源文件内容差异,AI 两轮行为均正确 + +| 证据 | languages 表现 | +|---|---| +| 场景② pptx | 留空 6 处(当时误判「降级/丢失」) | +| 旧散落结果 rules_ppt.yaml | 大面积留空 | +| 本场景 pptx(噪声更重、文件更大 45KB) | 零留空,8 处全对 | +| 场景② pptx 重测(2026-09-07) | 留空模式与首测逐字段复现 | +| **officeparser 提取文本比对(2026-09-07)** | **02 源文件 950 字符中无任何「适用语言/排除语言」标注;03 源文件含成组「严重级别 \| 语言」标注及「排除语言:sql」** | + +定性演进三版:格式缺陷(02 初稿)→ 高方差(03 初稿,被重测推翻)→ 提取层丢失(被提取比对推翻)→ **最终定案:源文件内容差异**。02 pptx 幻灯片只写了 severity(`[error]/[warning]/[info]` 前缀)没写语言,03 pptx 两者都写了。AI 侧两轮行为均正确:源有的正确映射(含 excludeLanguages: [sql]),源无的按「严禁猜测,留空比猜测错误更安全」留空,语义可推的唯一一条(描述含「TypeScript 类型」)正确推断 [typescript]。**这 6 处留空从来不是「丢失」——源文件没有的数据不能叫丢失**。制作 pptx 规则素材时,如需语言限定必须在幻灯片中显式标注适用语言。 + +### 3. 去重判断方差实锤:同一规则跨轮在 exact 与 overlap 间摆动 + +- xlsx 单表轮:no-hardcoded-credentials 被判 **overlap**(保留生效)——与前 12 轮历史(exact)不同,且两条规则检测目标几乎重合、语言集合相同,exact 更贴切 +- multisheet 轮:**回归 exact**(注释) +- 实际影响:overlap 判保留时该规则与 custom/no-hardcoded-secret 并存双报。定性为 AI 判断方差(与 galaxy 轮次波动同源),预览面板人工复核是设计内的必要补偿 +- 附加证据:docx 轮魔法数字规则 id 为 `avoid-magic-numbers`(与既有规则 id 前缀完全不同),仍被精准标注为 custom/no-magic-numbers 的 exact——去重的语义性(与 id 无关)得到最直接验证 + +### 4. 表格类格式稳定性跨场景复现,multisheet 打出跨场景字节级一致 + +- xlsx 单表、multisheet 两轮的 9 条保留规则 id 再次全部与 yaml 基准一致(「结构化表格 → id 收敛」跨场景复现;自由文本四轮 id 依旧逐轮漂移) +- **multisheet 轮落盘文件与场景② multisheet 结果逐字节一致**(fc 0 差异),且场景②内 multisheet ≡ xlsx 单表——推导链 `02-xlsx ≡ 02-multisheet ≡ 03-multisheet`:AI 从两份完全不同的源文档(15KB 标准多表 vs 24KB 重噪声多表)收敛到同一字节级输出,spreadsheet 链路稳定性拿到最强证据 + +### 5. id 漂移全景 + +自由文本格式(md/txt/docx/pptx)的 AI 生成 id 逐轮漂移(本轮新组合:`constant-naming`、`boolean-variable-prefix`、`require-explicit-types`、`no-todo-fixme-hack` 等),仅个别巧合重合(no-todo-comments、require-doc-comments 在 02/03 的 md 轮均出现)。含义相同的规则若以不同格式多次导入并存将双报——每轮归档移出激活目录即为规避此问题。 + +## 已知观察 + +- **xlsx 轮注释块尾部各多一行孤立 `#`**(外观残留,无功能影响) +- **去重方差的管理含义**:exact/overlap 判定在边界案例上有摆动,重要场景导入后应在预览面板复核重复分组(与 guide.md 归档流程互补) +- 本场景 yaml 轮噪声全部藏在注释中,对解析器无挑战(真正考验由 md/txt/docx/pptx/xlsx 承担) + +## 结论 + +**通过**。7 种格式全部成功导入 12 条规则基准:重噪声零膨胀、反面示例陷阱零触发、severity 零偏差。场景②的 pptx 疑问在本场景得到最终定案:语言字段差异源于源文件内容差异(02 源无语言标注、03 源有),AI 两轮行为均正确,不存在降级或丢失;表格类格式稳定性获得跨场景字节级一致的强证据。去重语义性(avoid-magic-numbers 案例)与判断方差(hardcoded-credentials exact/overlap 摆动)均有实测记录。 + +## 关联 + +- galaxy 素材验证报告:`data/import-verification/01-galaxy-nonstandard/result-report.md`(真实世界非标准格式场景) +- 标准格式验证报告:`data/import-verification/02-standard-formats/result-report.md`(8 种格式,含 pptx 降级原始记录) +- 自动化测试:`tests/excel-converter.test.ts`(转换器渲染层) +- 设计 spec:`docs/superpowers/specs/2026-07-26-custom-rule-import-ux-design.md` diff --git a/data/import-verification/03-irregular-content/results/irregular-docx.yaml b/data/import-verification/03-irregular-content/results/irregular-docx.yaml new file mode 100644 index 0000000..56d905b --- /dev/null +++ b/data/import-verification/03-irregular-content/results/irregular-docx.yaml @@ -0,0 +1,71 @@ +# [DUPLICATE: exact] 重复自定义规则 no-hardcoded-secret(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-hardcoded-credentials +# severity: error +# description: 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 +# message: 检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 +# languages: [javascript, typescript, java] +# duplicateOf: custom/no-hardcoded-secret +# duplicateLevel: exact +# [DUPLICATE: exact] 重复 eslint/no-eval(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-eval +# severity: error +# description: 禁止使用 eval() 函数,存在代码注入风险 +# message: eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 +# languages: [javascript, typescript] +# duplicateOf: eslint/no-eval +# duplicateLevel: exact +- id: no-innerhtml-assignment + severity: warning + description: 禁止直接赋值 innerHTML,可能导致 XSS + message: 避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 +- id: constants-screaming-snake-case + severity: warning + description: 常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) + message: 常量应使用全大写命名,如 MAX_RETRY_COUNT + languages: [javascript, typescript, java] +- id: boolean-prefix-naming + severity: info + description: 布尔变量和方法名应以 is/has/can/should 开头 + message: 布尔变量建议添加 is/has/can/should 前缀以提升可读性 + languages: [javascript, typescript] +- id: no-deep-nested-loops + severity: warning + description: 禁止三层及以上嵌套循环,时间复杂度过高 + message: 检测到深层嵌套循环(≥3层),建议重构为扁平结构或使用查找表优化 + languages: [javascript, typescript, java] +- id: no-sync-api-in-async + severity: warning + description: 异步函数内禁止调用同步阻塞 API + message: 在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 + languages: [javascript, typescript] +- id: explicit-function-types + severity: info + description: 函数参数和返回值应显式标注 TypeScript 类型 + message: 建议为函数添加显式类型注解,提升类型安全性 + languages: [typescript] +# [DUPLICATE: exact] 重复自定义规则 no-magic-numbers(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: avoid-magic-numbers +# severity: info +# description: 禁止在代码中直接使用魔法数字,应提取为命名常量 +# message: 检测到魔法数字,建议提取为具名常量以提升可维护性 +# languages: [javascript, typescript] +# duplicateOf: custom/no-magic-numbers +# duplicateLevel: exact +- id: throw-with-context + severity: warning + description: throw 语句必须携带错误上下文信息 + message: throw 时应提供足够的上下文信息,便于问题定位 + languages: [javascript, typescript, java] +- id: no-todo-fixme-hack + severity: info + description: 生产代码中不应遗留 TODO/FIXME/HACK 注释 + message: 代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 + excludeLanguages: [sql] +- id: require-public-docs + severity: info + description: 公共函数应添加文档注释(JSDoc / Javadoc) + message: 公共函数缺少文档注释,建议补充说明用途、参数和返回值 + languages: [javascript, typescript, java] \ No newline at end of file diff --git a/data/import-verification/03-irregular-content/results/irregular-md.yaml b/data/import-verification/03-irregular-content/results/irregular-md.yaml new file mode 100644 index 0000000..11ed44d --- /dev/null +++ b/data/import-verification/03-irregular-content/results/irregular-md.yaml @@ -0,0 +1,71 @@ +# [DUPLICATE: exact] 重复自定义规则 no-hardcoded-secret(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-hardcoded-credentials +# severity: error +# description: 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 +# message: 检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 +# languages: [java, javascript, typescript] +# duplicateOf: custom/no-hardcoded-secret +# duplicateLevel: exact +# [DUPLICATE: exact] 重复 eslint/no-eval(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-eval +# severity: error +# description: 禁止使用 eval() +# message: eval() 存在代码注入风险,请使用 JSON.parse() 或 Function 构造器替代 +# languages: [javascript, typescript] +# duplicateOf: eslint/no-eval +# duplicateLevel: exact +- id: no-innerhtml-assignment + severity: warning + description: 禁止直接赋值 innerHTML + message: 避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 +- id: constant-naming + severity: warning + description: 常量命名必须使用全大写加下划线的 SCREAMING_SNAKE_CASE + message: 常量应使用全大写命名,如 MAX_RETRY_COUNT + languages: [java, javascript, typescript] +- id: boolean-prefix + severity: info + description: 布尔变量和方法名应以 is/has/can/should 开头 + message: 布尔变量和方法名建议添加 is/has/can/should 前缀以提升可读性 + languages: [javascript, typescript] +- id: no-deep-nested-loops + severity: warning + description: 禁止三层及以上嵌套循环 + message: 检测到深层嵌套循环,建议重构为扁平结构或使用查找表优化 + languages: [java, javascript, typescript] +- id: no-sync-api-in-async + severity: warning + description: 异步函数内禁止调用同步阻塞 API + message: 在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 + languages: [javascript, typescript] +- id: require-explicit-types + severity: info + description: 函数参数和返回值应显式标注 TypeScript 类型 + message: 建议为函数添加显式类型注解,提升类型安全性 + languages: [typescript] +# [DUPLICATE: exact] 重复自定义规则 no-magic-numbers(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-magic-numbers +# severity: info +# description: 禁止在代码中直接使用魔法数字,应提取为命名常量 +# message: 检测到魔法数字,建议提取为具名常量以提升可维护性 +# languages: [javascript, typescript] +# duplicateOf: custom/no-magic-numbers +# duplicateLevel: exact +- id: require-throw-context + severity: warning + description: throw 语句必须携带错误上下文信息 + message: throw 时应提供足够的上下文信息,便于问题定位 + languages: [java, javascript, typescript] +- id: no-todo-comments + severity: info + description: 生产代码中不应遗留 TODO/FIXME/HACK 注释 + message: 代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 + excludeLanguages: [sql] +- id: require-doc-comments + severity: info + description: 公共函数应添加文档注释(JSDoc / Javadoc) + message: 公共函数缺少文档注释,建议补充说明用途、参数和返回值 + languages: [java, javascript, typescript] \ No newline at end of file diff --git a/data/import-verification/03-irregular-content/results/irregular-multisheet.yaml b/data/import-verification/03-irregular-content/results/irregular-multisheet.yaml new file mode 100644 index 0000000..6f83f53 --- /dev/null +++ b/data/import-verification/03-irregular-content/results/irregular-multisheet.yaml @@ -0,0 +1,71 @@ +# [DUPLICATE: exact] 重复自定义规则 no-hardcoded-secret(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-hardcoded-credentials +# severity: error +# description: 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 +# message: 检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 +# languages: [javascript, typescript, java] +# duplicateOf: custom/no-hardcoded-secret +# duplicateLevel: exact +# [DUPLICATE: exact] 重复 eslint/no-eval(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-eval-usage +# severity: error +# description: 禁止使用 eval() 函数,存在代码注入风险 +# message: eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 +# languages: [javascript, typescript] +# duplicateOf: eslint/no-eval +# duplicateLevel: exact +- id: no-innerhtml-assignment + severity: warning + description: 禁止直接赋值 innerHTML,可能导致 XSS + message: 避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 +- id: require-constant-case + severity: warning + description: 常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) + message: 常量应使用全大写命名,如 MAX_RETRY_COUNT + languages: [javascript, typescript, java] +- id: require-boolean-prefix + severity: info + description: 布尔变量和方法名应以 is/has/can/should 开头 + message: 布尔变量建议添加 is/has/can/should 前缀以提升可读性 + languages: [javascript, typescript] +- id: no-nested-loops-deep + severity: warning + description: 禁止三层及以上嵌套循环,时间复杂度过高 + message: 检测到深层嵌套循环(≥3层),建议重构为扁平结构或使用查找表优化 + languages: [javascript, typescript, java] +- id: no-sync-in-async + severity: warning + description: 异步函数内禁止调用同步阻塞 API + message: 在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 + languages: [javascript, typescript] +- id: require-type-annotation + severity: info + description: 函数参数和返回值应显式标注 TypeScript 类型 + message: 建议为函数添加显式类型注解,提升类型安全性 + languages: [typescript] +# [DUPLICATE: exact] 重复自定义规则 no-magic-numbers(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-magic-numbers +# severity: info +# description: 禁止在代码中直接使用魔法数字,应提取为命名常量 +# message: 检测到魔法数字,建议提取为具名常量以提升可维护性 +# languages: [javascript, typescript] +# duplicateOf: custom/no-magic-numbers +# duplicateLevel: exact +- id: require-error-context + severity: warning + description: throw 语句必须携带错误上下文信息 + message: throw 时应提供足够的上下文信息,便于问题定位 + languages: [javascript, typescript, java] +- id: no-todo-in-production + severity: info + description: 生产代码中不应遗留 TODO/FIXME/HACK 注释 + message: 代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 + excludeLanguages: [sql] +- id: require-function-doc + severity: info + description: 公共函数应添加文档注释(JSDoc / Javadoc) + message: 公共函数缺少文档注释,建议补充说明用途、参数和返回值 + languages: [javascript, typescript, java] \ No newline at end of file diff --git a/data/import-verification/03-irregular-content/results/irregular-pptx.yaml b/data/import-verification/03-irregular-content/results/irregular-pptx.yaml new file mode 100644 index 0000000..6659e7b --- /dev/null +++ b/data/import-verification/03-irregular-content/results/irregular-pptx.yaml @@ -0,0 +1,71 @@ +# [DUPLICATE: exact] 重复自定义规则 no-hardcoded-secret(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-hardcoded-secret +# severity: error +# description: 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 +# message: 检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 +# languages: [javascript, typescript, java] +# duplicateOf: custom/no-hardcoded-secret +# duplicateLevel: exact +# [DUPLICATE: exact] 重复 eslint/no-eval(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-eval +# severity: error +# description: 禁止使用 eval() 函数 +# message: eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 +# languages: [javascript, typescript] +# duplicateOf: eslint/no-eval +# duplicateLevel: exact +- id: no-inner-html + severity: warning + description: 禁止直接赋值 innerHTML + message: 避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 +- id: constant-naming-screaming-snake-case + severity: warning + description: 常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) + message: 常量应使用全大写命名,如 MAX_RETRY_COUNT + languages: [javascript, typescript, java] +- id: boolean-prefix + severity: info + description: 布尔变量和方法名应以 is/has/can/should 开头 + message: 布尔变量建议添加 is/has/can/should 前缀以提升可读性 + languages: [javascript, typescript] +- id: no-deep-nested-loops + severity: warning + description: 禁止三层及以上嵌套循环 + message: 检测到深层嵌套循环(≥3层),建议重构为扁平结构或使用查找表优化 + languages: [javascript, typescript, java] +- id: no-sync-in-async + severity: warning + description: 异步函数内禁止调用同步阻塞 API + message: 在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 + languages: [javascript, typescript] +- id: require-explicit-types + severity: info + description: 函数参数和返回值应显式标注 TypeScript 类型 + message: 建议为函数添加显式类型注解,提升类型安全性 + languages: [typescript] +# [DUPLICATE: exact] 重复自定义规则 no-magic-numbers(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-magic-numbers +# severity: info +# description: 禁止在代码中直接使用魔法数字,应提取为命名常量 +# message: 检测到魔法数字,建议提取为具名常量以提升可维护性 +# languages: [javascript, typescript] +# duplicateOf: custom/no-magic-numbers +# duplicateLevel: exact +- id: throw-with-context + severity: warning + description: throw 语句必须携带错误上下文信息 + message: throw 时应提供足够的上下文信息,便于问题定位 + languages: [javascript, typescript, java] +- id: no-todo-fixme-hack + severity: info + description: 生产代码中不应遗留 TODO/FIXME/HACK 注释 + message: 代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 + excludeLanguages: [sql] +- id: require-doc-comments + severity: info + description: 公共函数应添加文档注释(JSDoc / Javadoc) + message: 公共函数缺少文档注释,建议补充说明用途、参数和返回值 + languages: [javascript, typescript, java] \ No newline at end of file diff --git a/data/import-verification/03-irregular-content/results/irregular-txt.yaml b/data/import-verification/03-irregular-content/results/irregular-txt.yaml new file mode 100644 index 0000000..7ae8eea --- /dev/null +++ b/data/import-verification/03-irregular-content/results/irregular-txt.yaml @@ -0,0 +1,71 @@ +# [DUPLICATE: exact] 重复自定义规则 no-hardcoded-secret(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-hardcoded-credentials +# severity: error +# description: 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 +# message: 检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 +# languages: [javascript, typescript, java] +# duplicateOf: custom/no-hardcoded-secret +# duplicateLevel: exact +# [DUPLICATE: exact] 重复 eslint/no-eval(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-eval +# severity: error +# description: 禁止使用 eval() 函数,存在代码注入风险 +# message: eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 +# languages: [javascript, typescript] +# duplicateOf: eslint/no-eval +# duplicateLevel: exact +- id: no-innerhtml-assignment + severity: warning + description: 禁止直接赋值 innerHTML,可能导致 XSS + message: 避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 +- id: constant-uppercase-naming + severity: warning + description: 常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) + message: 常量应使用全大写命名,如 MAX_RETRY_COUNT + languages: [javascript, typescript, java] +- id: boolean-variable-prefix + severity: info + description: 布尔变量和方法名应以 is/has/can/should 开头 + message: 布尔变量建议添加 is/has/can/should 前缀以提升可读性 + languages: [javascript, typescript] +- id: no-deeply-nested-loops + severity: warning + description: 禁止三层及以上嵌套循环,时间复杂度过高 + message: 检测到深层嵌套循环(≥3层),建议重构为扁平结构或使用查找表优化 + languages: [javascript, typescript, java] +- id: no-sync-api-in-async + severity: warning + description: 禁止在异步函数内调用同步阻塞 API + message: 在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 + languages: [javascript, typescript] +- id: explicit-function-types + severity: info + description: 函数参数和返回值应显式标注 TypeScript 类型 + message: 建议为函数添加显式类型注解,提升类型安全性 + languages: [typescript] +# [DUPLICATE: exact] 重复自定义规则 no-magic-numbers(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-magic-numbers +# severity: info +# description: 禁止在代码中直接使用魔法数字,应提取为命名常量 +# message: 检测到魔法数字,建议提取为具名常量以提升可维护性 +# languages: [javascript, typescript] +# duplicateOf: custom/no-magic-numbers +# duplicateLevel: exact +- id: throw-with-context + severity: warning + description: throw 语句必须携带错误上下文信息 + message: throw 时应提供足够的上下文信息,便于问题定位 + languages: [javascript, typescript, java] +- id: no-todo-comments + severity: info + description: 生产代码中不应遗留 TODO/FIXME/HACK 注释 + message: 代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 + excludeLanguages: [sql] +- id: public-function-doc-comments + severity: info + description: 公共函数应添加文档注释(JSDoc / Javadoc) + message: 公共函数缺少文档注释,建议补充说明用途、参数和返回值 + languages: [javascript, typescript, java] \ No newline at end of file diff --git a/data/import-verification/03-irregular-content/results/irregular-xlsx.yaml b/data/import-verification/03-irregular-content/results/irregular-xlsx.yaml new file mode 100644 index 0000000..2f04051 --- /dev/null +++ b/data/import-verification/03-irregular-content/results/irregular-xlsx.yaml @@ -0,0 +1,78 @@ +- id: no-hardcoded-credentials + severity: error + description: 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 + message: 检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 + languages: [javascript, typescript, java] + +# [DUPLICATE: exact] 重复 eslint/no-eval(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-eval-usage +# severity: error +# description: 禁止使用 eval() 函数,存在代码注入风险 +# message: eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 +# languages: [javascript, typescript] +# duplicateOf: eslint/no-eval +# duplicateLevel: exact +# +- id: no-innerhtml-assignment + severity: warning + description: 禁止直接赋值 innerHTML,可能导致 XSS + message: 避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 + +- id: require-constant-case + severity: warning + description: 常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) + message: 常量应使用全大写命名,如 MAX_RETRY_COUNT + languages: [javascript, typescript, java] + +- id: require-boolean-prefix + severity: info + description: 布尔变量和方法名应以 is/has/can/should 开头 + message: 布尔变量建议添加 is/has/can/should 前缀以提升可读性 + languages: [javascript, typescript] + +- id: no-nested-loops-deep + severity: warning + description: 禁止三层及以上嵌套循环,时间复杂度过高 + message: 检测到深层嵌套循环(≥3层),建议重构为扁平结构或使用查找表优化 + languages: [javascript, typescript, java] + +- id: no-sync-in-async + severity: warning + description: 异步函数内禁止调用同步阻塞 API + message: 在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 + languages: [javascript, typescript] + +- id: require-type-annotation + severity: info + description: 函数参数和返回值应显式标注 TypeScript 类型 + message: 建议为函数添加显式类型注解,提升类型安全性 + languages: [typescript] + +# [DUPLICATE: exact] 重复自定义规则 no-magic-numbers(检测目标完全一致) +# 如需启用,删除以下每行开头的 # 即可 +# - id: no-magic-numbers +# severity: info +# description: 禁止在代码中直接使用魔法数字,应提取为命名常量 +# message: 检测到魔法数字,建议提取为具名常量以提升可维护性 +# languages: [javascript, typescript] +# duplicateOf: custom/no-magic-numbers +# duplicateLevel: exact +# +- id: require-error-context + severity: warning + description: throw 语句必须携带错误上下文信息 + message: throw 时应提供足够的上下文信息,便于问题定位 + languages: [javascript, typescript, java] + +- id: no-todo-in-production + severity: info + description: 生产代码中不应遗留 TODO/FIXME/HACK 注释 + message: 代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 + excludeLanguages: [sql] + +- id: require-function-doc + severity: info + description: 公共函数应添加文档注释(JSDoc / Javadoc) + message: 公共函数缺少文档注释,建议补充说明用途、参数和返回值 + languages: [javascript, typescript, java] \ No newline at end of file diff --git a/data/import-verification/03-irregular-content/results/irregular-yaml.yaml b/data/import-verification/03-irregular-content/results/irregular-yaml.yaml new file mode 100644 index 0000000..bbbe8ea --- /dev/null +++ b/data/import-verification/03-irregular-content/results/irregular-yaml.yaml @@ -0,0 +1,225 @@ +# ┌─────────────────────────────────────────────────────────────────┐ +# │ 电商订单管理系统 — 工程规范文档 │ +# │ 团队:订单研发团队(后端6人 + 前端3人 + QA2人 + DevOps1人) │ +# │ 最后更新:2026-07-15 │ +# │ 仓库:git@company.com:order-team/oms.git │ +# └─────────────────────────────────────────────────────────────────┘ +# +# 项目背景: +# 面向 B 端商家的电商订单管理系统,日均订单量约 50 万单。 +# 微服务架构:订单服务、支付服务、库存服务、物流服务。 +# 技术栈:Java 17 + Spring Boot 3.2 + React 18 + TypeScript 5.3 +# +# 架构说明: +# 订单服务采用 CQRS 模式,写操作走主库,读操作走从库。 +# 消息队列使用 RocketMQ 5.x。 +# +# 2026-07-15 会议纪要: +# - 讨论了 Node.js 事件循环阻塞问题 +# - 决定在 async 函数中全面禁用 fs.readFileSync 等同步 API +# - 下个 Sprint 开始 Code Review 时执行 +# +# 部署流程: +# 每周二、四发布,发布窗口 14:00-16:00。 +# CI/CD Pipeline 详见 Jenkins 配置。 +# +# 代码审查 Checklist: +# [ ] 安全规范是否遵守 +# [ ] 命名规范是否一致 +# [ ] 性能是否有明显瓶颈 +# [ ] 代码风格是否统一 +# [ ] 团队约定是否遵循 +# +# ── 安全类 ────────────────────────────────────────────────────────── +# +# 反面示例(请勿模仿): +# +# // Java: 硬编码密码 +# public class DatabaseConfig { +# private String password = "Admin@123456"; +# } +# +# // JavaScript: 使用 eval +# const data = eval(request.body); +# +# // JavaScript: innerHTML 赋值 +# element.innerHTML = userInput; +# +# 正确做法: +# +# @Value("${db.password}") +# private String password; +# +# const data = JSON.parse(request.body); +# +# element.textContent = userInput; +# + +- id: no-hardcoded-credentials + severity: error + description: 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 + message: 检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 + languages: [javascript, typescript, java] + +- id: no-eval-usage + severity: error + description: 禁止使用 eval() 函数,存在代码注入风险 + message: eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 + languages: [javascript, typescript] + +- id: no-innerhtml-assignment + severity: warning + description: 禁止直接赋值 innerHTML,可能导致 XSS + message: 避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 + +# ── 命名规范类 ────────────────────────────────────────────────────── +# +# 参考规范: +# - Google Java Style Guide +# - Airbnb JavaScript Style Guide +# +# 反面示例: +# +# // 常量未使用大写 +# static final int maxRetry = 3; +# static final String DbHost = "localhost"; +# +# // 布尔变量无前缀 +# let active = true; +# function check(): boolean { ... } +# +# 正确做法: +# +# static final int MAX_RETRY = 3; +# static final String DB_HOST = "localhost"; +# +# let isActive = true; +# function canCheck(): boolean { ... } +# + +- id: require-constant-case + severity: warning + description: 常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) + message: 常量应使用全大写命名,如 MAX_RETRY_COUNT + languages: [javascript, typescript, java] + +- id: require-boolean-prefix + severity: info + description: 布尔变量和方法名应以 is/has/can/should 开头 + message: 布尔变量建议添加 is/has/can/should 前缀以提升可读性 + languages: [javascript, typescript] + +# ── 性能类 ────────────────────────────────────────────────────────── +# +# 架构说明: +# 订单服务采用 CQRS 模式,写操作走主库,读操作走从库。 +# 在高并发场景下,以下性能规范尤为重要。 +# +# 反面示例: +# +# // O(n³) 的订单匹配逻辑 +# for (const order of orders) { +# for (const item of order.items) { +# for (const warehouse of warehouses) { +# // 匹配逻辑... +# } +# } +# } +# +# 正确做法: +# +# const warehouseMap = new Map(warehouses.map(w => [w.id, w])); +# for (const order of orders) { +# for (const item of order.items) { +# const wh = warehouseMap.get(item.warehouseId); +# } +# } +# + +- id: no-nested-loops-deep + severity: warning + description: 禁止三层及以上嵌套循环,时间复杂度过高 + message: 检测到深层嵌套循环(≥3层),建议重构为扁平结构或使用查找表优化 + languages: [javascript, typescript, java] + +- id: no-sync-in-async + severity: warning + description: 异步函数内禁止调用同步阻塞 API + message: 在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 + languages: [javascript, typescript] + +# ── 代码风格类 ────────────────────────────────────────────────────── +# +# 反面示例: +# +# // 无类型注解 +# function createOrder(data) { +# return api.post('/orders', data); +# } +# +# // 魔法数字 +# if (order.status === 3) { ... } +# setTimeout(retry, 5000); +# +# 正确做法: +# +# function createOrder(data: CreateOrderDTO): Promise { +# return api.post('/orders', data); +# } +# +# const ORDER_STATUS_SHIPPED = 3; +# const RETRY_DELAY_MS = 5000; +# if (order.status === ORDER_STATUS_SHIPPED) { ... } +# setTimeout(retry, RETRY_DELAY_MS); +# + +- id: require-type-annotation + severity: info + description: 函数参数和返回值应显式标注 TypeScript 类型 + message: 建议为函数添加显式类型注解,提升类型安全性 + languages: [typescript] + +- id: no-magic-numbers + severity: info + description: 禁止在代码中直接使用魔法数字,应提取为命名常量 + message: 检测到魔法数字,建议提取为具名常量以提升可维护性 + languages: [javascript, typescript] + +# ── 团队约定类 ────────────────────────────────────────────────────── +# +# 部署流程说明: +# 每周二、四发布,发布窗口 14:00-16:00。 +# +# 反面示例: +# +# throw new RuntimeException("失败"); +# throw new Error("error"); +# +# 正确做法: +# +# throw new OrderNotFoundException("订单不存在, orderId=" + orderId); +# throw new PaymentFailedException("支付失败", cause); +# +# 版本历史: +# v1.0 2026-06-01 张三 初版 +# v1.1 2026-07-15 李四 新增性能规范 +# v1.2 2026-08-01 王五 补充代码示例 +# + +- id: require-error-context + severity: warning + description: throw 语句必须携带错误上下文信息 + message: throw 时应提供足够的上下文信息,便于问题定位 + languages: [javascript, typescript, java] + +- id: no-todo-in-production + severity: info + description: 生产代码中不应遗留 TODO/FIXME/HACK 注释 + message: 代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 + excludeLanguages: [sql] + +- id: require-function-doc + severity: info + description: 公共函数应添加文档注释(JSDoc / Javadoc) + message: 公共函数缺少文档注释,建议补充说明用途、参数和返回值 + languages: [javascript, typescript, java] diff --git a/data/import-verification/03-irregular-content/team-coding-rules-multi-sheet.xlsx b/data/import-verification/03-irregular-content/team-coding-rules-multi-sheet.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..051cf970ae9434ebc548032770d0b697b5f29fc5 GIT binary patch literal 24690 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 本文档由订单研发团队维护,最后更新于 2026 年 7 月。 + +## 项目背景 + +本项目是一个面向 B 端商家的电商订单管理系统,日均订单量约 50 万单。系统采用微服务架构,包含订单服务、支付服务、库存服务和物流服务四个核心模块。 + +技术栈: +- 后端:Java 17 + Spring Boot 3.2 + MyBatis-Plus +- 前端:React 18 + TypeScript 5.3 + Vite +- 数据库:MySQL 8.0 + Redis 7 +- 消息队列:RocketMQ 5.x + +## 团队介绍 + +订单研发团队目前有 12 人: +- 后端 6 人(含 1 名 Tech Lead) +- 前端 3 人 +- QA 2 人 +- DevOps 1 人 + +团队代码仓库:`git@company.com:order-team/oms.git` + +## 一、安全相关规范 + +在 2026 Q2 的安全审计中,我们发现线上代码中存在硬编码的数据库密码,导致一次严重的安全事件。因此制定以下规范: + +### 1.1 禁止硬编码凭证 + +severity: error +适用语言:JavaScript、TypeScript、Java + +禁止在源码中硬编码密码、令牌、API Key 等敏感凭证。检测到疑似硬编码凭证时,请使用环境变量或密钥管理服务注入。 + +以下是一个**反面示例**(请勿模仿): + +```java +// ❌ 错误做法 +public class DatabaseConfig { + private String password = "Admin@123456"; + private String apiKey = "sk-abc123xyz"; +} + +// ✅ 正确做法 +public class DatabaseConfig { + @Value("${db.password}") + private String password; + + @Value("${api.key}") + private String apiKey; +} +``` + +### 1.2 禁止使用 eval() + +severity: error +适用语言:JavaScript、TypeScript + +上周代码审查中发现前端模块有 `eval()` 调用,存在代码注入风险。eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代。 + +```javascript +// ❌ 错误:使用 eval 解析用户输入 +const data = eval(request.body); + +// ✅ 正确:使用 JSON.parse +const data = JSON.parse(request.body); +``` + +### 1.3 禁止直接赋值 innerHTML + +severity: warning + +这是一条通用规则,适用于所有语言(因为各端都可能涉及 DOM 操作)。避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗。 + +相关讨论参见 [内部 Wiki: XSS 防护指南](https://wiki.internal/security/xss) + +## 二、命名规范 + +> 以下命名规范参考了 Google Java Style Guide 和 Airbnb JavaScript Style Guide,根据团队实际情况做了调整。 + +### 2.1 常量命名 + +severity: warning +适用语言:JavaScript、TypeScript、Java + +常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE)。常量应使用全大写命名,如 MAX_RETRY_COUNT。 + +```java +// ❌ 错误 +static final int maxRetry = 3; +static final String DbHost = "localhost"; + +// ✅ 正确 +static final int MAX_RETRY = 3; +static final String DB_HOST = "localhost"; +``` + +### 2.2 布尔变量前缀 + +severity: info +适用语言:JavaScript、TypeScript + +布尔变量和方法名应以 is/has/can/should 开头。布尔变量建议添加 is/has/can/should 前缀以提升可读性。 + +```typescript +// ❌ 错误 +let active = true; +let user = { verified: true }; +function check(): boolean { ... } + +// ✅ 正确 +let isActive = true; +let user = { isVerified: true }; +function canCheck(): boolean { ... } +``` + +## 三、性能规范 + +### 架构说明 + +订单服务采用 CQRS 模式,写操作走主库,读操作走从库。在高并发场景下,以下性能规范尤为重要。 + +### 3.1 禁止深层嵌套循环 + +severity: warning +适用语言:JavaScript、TypeScript、Java + +禁止三层及以上嵌套循环,时间复杂度过高。检测到深层嵌套循环(≥3层)时,建议重构为扁平结构或使用查找表优化。 + +```javascript +// ❌ 错误:O(n³) 的订单匹配逻辑 +for (const order of orders) { + for (const item of order.items) { + for (const warehouse of warehouses) { + // 匹配逻辑... + } + } +} + +// ✅ 正确:使用 Map 优化为 O(n) +const warehouseMap = new Map(warehouses.map(w => [w.id, w])); +for (const order of orders) { + for (const item of order.items) { + const wh = warehouseMap.get(item.warehouseId); + } +} +``` + +### 3.2 异步函数内禁止同步 API + +severity: warning +适用语言:JavaScript、TypeScript + +异步函数内禁止调用同步阻塞 API。在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本。 + +### 2026-07-15 会议纪要 + +- 讨论了 Node.js 事件循环阻塞问题 +- 决定在 async 函数中全面禁用 fs.readFileSync 等同步 API +- 下个 Sprint 开始 Code Review 时执行 + +## 四、代码风格 + +### 4.1 函数显式类型注解 + +severity: info +适用语言:TypeScript + +函数参数和返回值应显式标注 TypeScript 类型。建议为函数添加显式类型注解,提升类型安全性。 + +```typescript +// ❌ 错误 +function createOrder(data) { + return api.post('/orders', data); +} + +// ✅ 正确 +function createOrder(data: CreateOrderDTO): Promise { + return api.post('/orders', data); +} +``` + +### 4.2 禁止魔法数字 + +severity: info +适用语言:JavaScript、TypeScript + +禁止在代码中直接使用魔法数字,应提取为命名常量。检测到魔法数字,建议提取为具名常量以提升可维护性。 + +```javascript +// ❌ 错误 +if (order.status === 3) { ... } +setTimeout(retry, 5000); + +// ✅ 正确 +const ORDER_STATUS_SHIPPED = 3; +const RETRY_DELAY_MS = 5000; +if (order.status === ORDER_STATUS_SHIPPED) { ... } +setTimeout(retry, RETRY_DELAY_MS); +``` + +## 五、团队约定 + +### 部署流程说明 + +部署流程参考 CI/CD Pipeline 文档。每周二、四发布,发布窗口为 14:00-16:00。 + +### 5.1 throw 语句携带上下文 + +severity: warning +适用语言:JavaScript、TypeScript、Java + +throw 语句必须携带错误上下文信息。throw 时应提供足够的上下文信息,便于问题定位。 + +```java +// ❌ 错误 +throw new RuntimeException("失败"); +throw new Error("error"); + +// ✅ 正确 +throw new OrderNotFoundException("订单不存在, orderId=" + orderId); +throw new PaymentFailedException("支付失败", cause); +``` + +### 5.2 禁止遗留 TODO 注释 + +severity: info +排除语言:SQL + +生产代码中不应遗留 TODO/FIXME/HACK 注释。代码中发现 TODO/FIXME/HACK 注释,请在发布前处理。 + +> 注:SQL 脚本中允许临时性的 TODO 标记,因为数据库迁移脚本的生命周期与代码不同。 + +### 5.3 公共函数文档注释 + +severity: info +适用语言:JavaScript、TypeScript、Java + +公共函数应添加文档注释(JSDoc / Javadoc)。公共函数缺少文档注释,建议补充说明用途、参数和返回值。 + +```java +/** + * 创建订单 + * @param request 订单创建请求 + * @return 订单创建结果 + * @throws InsufficientStockException 库存不足时抛出 + */ +public OrderResult createOrder(CreateOrderRequest request) { ... } +``` + +```typescript +/** + * 获取用户订单列表 + * @param userId 用户ID + * @param page 分页参数 + * @returns 订单列表 + */ +function getUserOrders(userId: string, page: Pagination): Promise { ... } +``` + +## 附录 + +### A. 代码审查 Checklist + +- [ ] 安全规范是否遵守 +- [ ] 命名规范是否一致 +- [ ] 性能是否有明显瓶颈 +- [ ] 代码风格是否统一 +- [ ] 团队约定是否遵循 + +### B. 相关链接 + +- [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html) +- [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript) +- [TypeScript ESLint Rules](https://typescript-eslint.io/rules/) + +### C. 版本历史 + +| 版本 | 日期 | 作者 | 变更说明 | +|------|------|------|----------| +| 1.0 | 2026-06-01 | 张三 | 初版 | +| 1.1 | 2026-07-15 | 李四 | 新增性能规范 | +| 1.2 | 2026-08-01 | 王五 | 补充代码示例 | diff --git a/data/import-verification/03-irregular-content/team-coding-rules.pptx b/data/import-verification/03-irregular-content/team-coding-rules.pptx new file mode 100644 index 0000000000000000000000000000000000000000..d0b19bb56d8e31a301e5de5fce41ad1b2e9fb05b GIT binary patch literal 45798 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 z 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 OfG_GI2#U;@dG`+xVlP|( literal 0 HcmV?d00001 diff --git a/data/import-verification/03-irregular-content/team-coding-rules.txt b/data/import-verification/03-irregular-content/team-coding-rules.txt new file mode 100644 index 0000000..e25244b --- /dev/null +++ b/data/import-verification/03-irregular-content/team-coding-rules.txt @@ -0,0 +1,287 @@ +电商订单管理系统 — 工程规范文档 +团队:订单研发团队(后端6人 + 前端3人 + QA2人 + DevOps1人) +最后更新:2026-07-15 +仓库:git@company.com:order-team/oms.git + +================================================================================ +项目背景 +================================================================================ + +本项目是一个面向 B 端商家的电商订单管理系统,日均订单量约 50 万单。 +系统采用微服务架构,包含订单服务、支付服务、库存服务和物流服务四个核心模块。 + +技术栈: +- 后端:Java 17 + Spring Boot 3.2 + MyBatis-Plus +- 前端:React 18 + TypeScript 5.3 + Vite +- 数据库:MySQL 8.0 + Redis 7 +- 消息队列:RocketMQ 5.x + +================================================================================ +团队介绍 +================================================================================ + +订单研发团队目前有 12 人: +- 后端 6 人(含 1 名 Tech Lead:张三) +- 前端 3 人(负责人:李四) +- QA 2 人 +- DevOps 1 人 + +团队代码仓库:git@company.com:order-team/oms.git +内部 Wiki:https://wiki.internal/order-team + +================================================================================ +一、安全相关规范 +================================================================================ + +在 2026 Q2 的安全审计中,我们发现线上代码中存在硬编码的数据库密码, +导致一次严重的安全事件。因此制定以下规范: + +---- 规则 ---- +名称:禁止硬编码凭证 +严重级别:error +适用语言:javascript, typescript, java +描述:禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 +提示:检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 + +以下是反面示例(请勿模仿): + + // Java: 硬编码密码 + public class DatabaseConfig { + private String password = "Admin@123456"; + private String apiKey = "sk-abc123xyz"; + } + + // JavaScript: 硬编码 Token + const API_TOKEN = "ghp_abc123def456"; + +正确做法: + + @Value("${db.password}") + private String password; + + const apiToken = process.env.API_TOKEN; + +---- 规则 ---- +名称:禁止使用 eval() +严重级别:error +适用语言:javascript, typescript +描述:禁止使用 eval() 函数,存在代码注入风险 +提示:eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 + +上周代码审查中发现前端模块有 eval() 调用: + + // 错误:使用 eval 解析用户输入 + const data = eval(request.body); + + // 正确:使用 JSON.parse + const data = JSON.parse(request.body); + +---- 规则 ---- +名称:禁止直接赋值 innerHTML +严重级别:warning +适用语言:所有语言 +描述:禁止直接赋值 innerHTML,可能导致 XSS +提示:避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 + +相关讨论参见内部 Wiki: XSS 防护指南 + +================================================================================ +二、命名规范 +================================================================================ + +以下命名规范参考了 Google Java Style Guide 和 Airbnb JavaScript Style Guide, +根据团队实际情况做了调整。 + +---- 规则 ---- +名称:常量使用全大写命名 +严重级别:warning +适用语言:javascript, typescript, java +描述:常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) +提示:常量应使用全大写命名,如 MAX_RETRY_COUNT + +反面示例: + + static final int maxRetry = 3; + static final String DbHost = "localhost"; + +正确做法: + + static final int MAX_RETRY = 3; + static final String DB_HOST = "localhost"; + +---- 规则 ---- +名称:布尔变量添加前缀 +严重级别:info +适用语言:javascript, typescript +描述:布尔变量和方法名应以 is/has/can/should 开头 +提示:布尔变量建议添加 is/has/can/should 前缀以提升可读性 + + // 错误 + let active = true; + let user = { verified: true }; + function check(): boolean { ... } + + // 正确 + let isActive = true; + let user = { isVerified: true }; + function canCheck(): boolean { ... } + +================================================================================ +三、性能规范 +================================================================================ + +架构说明:订单服务采用 CQRS 模式,写操作走主库,读操作走从库。 +在高并发场景下,以下性能规范尤为重要。 + +---- 规则 ---- +名称:禁止三层以上嵌套循环 +严重级别:warning +适用语言:javascript, typescript, java +描述:禁止三层及以上嵌套循环,时间复杂度过高 +提示:检测到深层嵌套循环(≥3层),建议重构为扁平结构或使用查找表优化 + + // 错误:O(n³) 的订单匹配逻辑 + for (const order of orders) { + for (const item of order.items) { + for (const warehouse of warehouses) { + // 匹配逻辑... + } + } + } + + // 正确:使用 Map 优化为 O(n) + const warehouseMap = new Map(warehouses.map(w => [w.id, w])); + for (const order of orders) { + for (const item of order.items) { + const wh = warehouseMap.get(item.warehouseId); + } + } + +---- 规则 ---- +名称:异步函数内禁止同步 API +严重级别:warning +适用语言:javascript, typescript +描述:异步函数内禁止调用同步阻塞 API +提示:在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 + +--- 2026-07-15 会议纪要 --- + +- 讨论了 Node.js 事件循环阻塞问题 +- 决定在 async 函数中全面禁用 fs.readFileSync 等同步 API +- 下个 Sprint 开始 Code Review 时执行 +- 张三负责更新 ESLint 配置 +- 李四负责前端代码排查 + +================================================================================ +四、代码风格 +================================================================================ + +---- 规则 ---- +名称:函数显式类型注解 +严重级别:info +适用语言:typescript +描述:函数参数和返回值应显式标注 TypeScript 类型 +提示:建议为函数添加显式类型注解,提升类型安全性 + + // 错误 + function createOrder(data) { + return api.post('/orders', data); + } + + // 正确 + function createOrder(data: CreateOrderDTO): Promise { + return api.post('/orders', data); + } + +---- 规则 ---- +名称:禁止魔法数字 +严重级别:info +适用语言:javascript, typescript +描述:禁止在代码中直接使用魔法数字,应提取为命名常量 +提示:检测到魔法数字,建议提取为具名常量以提升可维护性 + + // 错误 + if (order.status === 3) { ... } + setTimeout(retry, 5000); + + // 正确 + const ORDER_STATUS_SHIPPED = 3; + const RETRY_DELAY_MS = 5000; + if (order.status === ORDER_STATUS_SHIPPED) { ... } + setTimeout(retry, RETRY_DELAY_MS); + +================================================================================ +五、团队约定 +================================================================================ + +部署流程说明: + 每周二、四发布,发布窗口 14:00-16:00。 + CI/CD Pipeline 详见 Jenkins 配置。 + +---- 规则 ---- +名称:throw 语句携带上下文 +严重级别:warning +适用语言:javascript, typescript, java +描述:throw 语句必须携带错误上下文信息 +提示:throw 时应提供足够的上下文信息,便于问题定位 + + // 错误 + throw new RuntimeException("失败"); + throw new Error("error"); + + // 正确 + throw new OrderNotFoundException("订单不存在, orderId=" + orderId); + throw new PaymentFailedException("支付失败", cause); + +---- 规则 ---- +名称:禁止遗留 TODO 注释 +严重级别:info +排除语言:sql +描述:生产代码中不应遗留 TODO/FIXME/HACK 注释 +提示:代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 + +注:SQL 脚本中允许临时性的 TODO 标记,因为数据库迁移脚本的生命周期与代码不同。 + +---- 规则 ---- +名称:公共函数文档注释 +严重级别:info +适用语言:javascript, typescript, java +描述:公共函数应添加文档注释(JSDoc / Javadoc) +提示:公共函数缺少文档注释,建议补充说明用途、参数和返回值 + + /** + * 创建订单 + * @param request 订单创建请求 + * @return 订单创建结果 + * @throws InsufficientStockException 库存不足时抛出 + */ + public OrderResult createOrder(CreateOrderRequest request) { ... } + + /** + * 获取用户订单列表 + * @param userId 用户ID + * @param page 分页参数 + * @returns 订单列表 + */ + function getUserOrders(userId: string, page: Pagination): Promise { ... } + +================================================================================ +附录 +================================================================================ + +A. 代码审查 Checklist + [ ] 安全规范是否遵守 + [ ] 命名规范是否一致 + [ ] 性能是否有明显瓶颈 + [ ] 代码风格是否统一 + [ ] 团队约定是否遵循 + +B. 相关链接 + - Google Java Style Guide: https://google.github.io/styleguide/javaguide.html + - Airbnb JavaScript Style Guide: https://github.com/airbnb/javascript + - TypeScript ESLint Rules: https://typescript-eslint.io/rules/ + +C. 版本历史 + v1.0 2026-06-01 张三 初版 + v1.1 2026-07-15 李四 新增性能规范 + v1.2 2026-08-01 王五 补充代码示例 diff --git a/data/import-verification/03-irregular-content/team-coding-rules.xlsx b/data/import-verification/03-irregular-content/team-coding-rules.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..674d2051e36b08110c07d0a3d6ef6b54cbffcad0 GIT binary patch literal 11026 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 literal 0 HcmV?d00001 diff --git a/data/import-verification/03-irregular-content/team-coding-rules.yaml b/data/import-verification/03-irregular-content/team-coding-rules.yaml new file mode 100644 index 0000000..bbbe8ea --- /dev/null +++ b/data/import-verification/03-irregular-content/team-coding-rules.yaml @@ -0,0 +1,225 @@ +# ┌─────────────────────────────────────────────────────────────────┐ +# │ 电商订单管理系统 — 工程规范文档 │ +# │ 团队:订单研发团队(后端6人 + 前端3人 + QA2人 + DevOps1人) │ +# │ 最后更新:2026-07-15 │ +# │ 仓库:git@company.com:order-team/oms.git │ +# └─────────────────────────────────────────────────────────────────┘ +# +# 项目背景: +# 面向 B 端商家的电商订单管理系统,日均订单量约 50 万单。 +# 微服务架构:订单服务、支付服务、库存服务、物流服务。 +# 技术栈:Java 17 + Spring Boot 3.2 + React 18 + TypeScript 5.3 +# +# 架构说明: +# 订单服务采用 CQRS 模式,写操作走主库,读操作走从库。 +# 消息队列使用 RocketMQ 5.x。 +# +# 2026-07-15 会议纪要: +# - 讨论了 Node.js 事件循环阻塞问题 +# - 决定在 async 函数中全面禁用 fs.readFileSync 等同步 API +# - 下个 Sprint 开始 Code Review 时执行 +# +# 部署流程: +# 每周二、四发布,发布窗口 14:00-16:00。 +# CI/CD Pipeline 详见 Jenkins 配置。 +# +# 代码审查 Checklist: +# [ ] 安全规范是否遵守 +# [ ] 命名规范是否一致 +# [ ] 性能是否有明显瓶颈 +# [ ] 代码风格是否统一 +# [ ] 团队约定是否遵循 +# +# ── 安全类 ────────────────────────────────────────────────────────── +# +# 反面示例(请勿模仿): +# +# // Java: 硬编码密码 +# public class DatabaseConfig { +# private String password = "Admin@123456"; +# } +# +# // JavaScript: 使用 eval +# const data = eval(request.body); +# +# // JavaScript: innerHTML 赋值 +# element.innerHTML = userInput; +# +# 正确做法: +# +# @Value("${db.password}") +# private String password; +# +# const data = JSON.parse(request.body); +# +# element.textContent = userInput; +# + +- id: no-hardcoded-credentials + severity: error + description: 禁止在源码中硬编码密码、令牌、API Key 等敏感凭证 + message: 检测到疑似硬编码凭证,请使用环境变量或密钥管理服务注入 + languages: [javascript, typescript, java] + +- id: no-eval-usage + severity: error + description: 禁止使用 eval() 函数,存在代码注入风险 + message: eval() 存在安全风险,请使用 JSON.parse() 或 Function 构造器替代 + languages: [javascript, typescript] + +- id: no-innerhtml-assignment + severity: warning + description: 禁止直接赋值 innerHTML,可能导致 XSS + message: 避免直接操作 innerHTML,请使用 textContent 或 DOMPurify 清洗 + +# ── 命名规范类 ────────────────────────────────────────────────────── +# +# 参考规范: +# - Google Java Style Guide +# - Airbnb JavaScript Style Guide +# +# 反面示例: +# +# // 常量未使用大写 +# static final int maxRetry = 3; +# static final String DbHost = "localhost"; +# +# // 布尔变量无前缀 +# let active = true; +# function check(): boolean { ... } +# +# 正确做法: +# +# static final int MAX_RETRY = 3; +# static final String DB_HOST = "localhost"; +# +# let isActive = true; +# function canCheck(): boolean { ... } +# + +- id: require-constant-case + severity: warning + description: 常量命名必须使用全大写加下划线(SCREAMING_SNAKE_CASE) + message: 常量应使用全大写命名,如 MAX_RETRY_COUNT + languages: [javascript, typescript, java] + +- id: require-boolean-prefix + severity: info + description: 布尔变量和方法名应以 is/has/can/should 开头 + message: 布尔变量建议添加 is/has/can/should 前缀以提升可读性 + languages: [javascript, typescript] + +# ── 性能类 ────────────────────────────────────────────────────────── +# +# 架构说明: +# 订单服务采用 CQRS 模式,写操作走主库,读操作走从库。 +# 在高并发场景下,以下性能规范尤为重要。 +# +# 反面示例: +# +# // O(n³) 的订单匹配逻辑 +# for (const order of orders) { +# for (const item of order.items) { +# for (const warehouse of warehouses) { +# // 匹配逻辑... +# } +# } +# } +# +# 正确做法: +# +# const warehouseMap = new Map(warehouses.map(w => [w.id, w])); +# for (const order of orders) { +# for (const item of order.items) { +# const wh = warehouseMap.get(item.warehouseId); +# } +# } +# + +- id: no-nested-loops-deep + severity: warning + description: 禁止三层及以上嵌套循环,时间复杂度过高 + message: 检测到深层嵌套循环(≥3层),建议重构为扁平结构或使用查找表优化 + languages: [javascript, typescript, java] + +- id: no-sync-in-async + severity: warning + description: 异步函数内禁止调用同步阻塞 API + message: 在 async 函数中调用同步 API 会阻塞事件循环,请改用异步版本 + languages: [javascript, typescript] + +# ── 代码风格类 ────────────────────────────────────────────────────── +# +# 反面示例: +# +# // 无类型注解 +# function createOrder(data) { +# return api.post('/orders', data); +# } +# +# // 魔法数字 +# if (order.status === 3) { ... } +# setTimeout(retry, 5000); +# +# 正确做法: +# +# function createOrder(data: CreateOrderDTO): Promise { +# return api.post('/orders', data); +# } +# +# const ORDER_STATUS_SHIPPED = 3; +# const RETRY_DELAY_MS = 5000; +# if (order.status === ORDER_STATUS_SHIPPED) { ... } +# setTimeout(retry, RETRY_DELAY_MS); +# + +- id: require-type-annotation + severity: info + description: 函数参数和返回值应显式标注 TypeScript 类型 + message: 建议为函数添加显式类型注解,提升类型安全性 + languages: [typescript] + +- id: no-magic-numbers + severity: info + description: 禁止在代码中直接使用魔法数字,应提取为命名常量 + message: 检测到魔法数字,建议提取为具名常量以提升可维护性 + languages: [javascript, typescript] + +# ── 团队约定类 ────────────────────────────────────────────────────── +# +# 部署流程说明: +# 每周二、四发布,发布窗口 14:00-16:00。 +# +# 反面示例: +# +# throw new RuntimeException("失败"); +# throw new Error("error"); +# +# 正确做法: +# +# throw new OrderNotFoundException("订单不存在, orderId=" + orderId); +# throw new PaymentFailedException("支付失败", cause); +# +# 版本历史: +# v1.0 2026-06-01 张三 初版 +# v1.1 2026-07-15 李四 新增性能规范 +# v1.2 2026-08-01 王五 补充代码示例 +# + +- id: require-error-context + severity: warning + description: throw 语句必须携带错误上下文信息 + message: throw 时应提供足够的上下文信息,便于问题定位 + languages: [javascript, typescript, java] + +- id: no-todo-in-production + severity: info + description: 生产代码中不应遗留 TODO/FIXME/HACK 注释 + message: 代码中发现 TODO/FIXME/HACK 注释,请在发布前处理 + excludeLanguages: [sql] + +- id: require-function-doc + severity: info + description: 公共函数应添加文档注释(JSDoc / Javadoc) + message: 公共函数缺少文档注释,建议补充说明用途、参数和返回值 + languages: [javascript, typescript, java] diff --git a/data/import-verification/guide.md b/data/import-verification/guide.md new file mode 100644 index 0000000..bcf7757 --- /dev/null +++ b/data/import-verification/guide.md @@ -0,0 +1,28 @@ +# 自定义规则导入验证 — 目录导航 + +本目录按测试场景分类组织。每个场景独立存放素材、结果与报告,互不干扰、互不覆盖。 + +## 场景结构 + +| 目录 | 场景 | 状态 | +|---|---|---| +| `01-galaxy-nonstandard/` | 真实世界非标准格式(双 Sheet、无标准表头、含干扰段落) | ✅ 已完成,报告在内 | +| `02-standard-formats/` | 标准格式矩阵(同一规则集 8 种格式逐一导入) | ✅ 已完成,报告在内 | +| `03-irregular-content/` | 不规则规则内容(重噪声嵌入,7 种格式) | ✅ 已完成,报告在内 | + +每个场景目录内的约定: + +- 素材文件直接放在场景根目录 +- 导入结果(从 `.code-review/rules/` 移出的 yaml)统一放 `results/` 子目录 +- `result-report.md` 为该场景的验证结果报告 + +## 规则命名约定(防覆盖) + +| 场景 | 规则名格式 | 示例 | +|---|---|---| +| 02 标准格式 | `standard-rules-<格式>` | `standard-rules-md` | +| 03 不规则内容 | `irregular-<格式>` | `irregular-md` | + +- 导入时插件拒绝覆盖 `.code-review/rules/` 下的同名规则文件,前缀错开即无冲突 +- 每轮验证核对完成后,及时把结果 yaml 从 `.code-review/rules/` 移入对应场景的 `results/` 归档 +- `tests/fixtures/` 下的素材副本是自动化测试依赖,与本目录素材无关,勿混用