ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

gsd-core 中 graphify 模块测试整合:从 7 个散落文件到按 surface 分区的 describe 结构

gsd-core 中 graphify 模块测试整合:从 7 个散落文件到按 surface 分区的 describe 结构 【免费下载链接】gsd-coreGit. Ship. Done - Core项目地址https://gitcode.com/gh_mirrors/ge/gsd-core点击查看免费下载本文围绕 gsd-core 仓库中 graphify项目知识图谱模块的测试治理实践展开它以一次真实的测试重构PR #3761为切入点梳理该模块测试从每个 PR 新增一个独立文件的 test-as-changelog 反模式演进为按 surface 分区、issue 可追溯的结构化 describe 组织方式并结合 src/graphify.cts 源码与 commands/gsd/graphify.md 命令契约逐层解读 status、build、query、staleness、mvp-viz、auto-update、regressions 七个测试面的覆盖逻辑。读完本文你将理解 gsd-core 如何用测试组织纪律约束一个跨命令、跨钩子的可选能力模块以及回归测试如何在源码与技能文档之间建立可执行的结构性护栏。一、背景test-as-changelog 反模式与 #3761 的合并动机1.1 什么是 test-as-changelog 反模式在 gsd-core 的 changeset 记录 .changeset/archived/3761-consolidate-graphify-tests.md 中这一反模式被明确命名每个 PR 都新增一个独立测试文件而不是把新用例追加到既有的graphify.test.cjs中。这种做法的直接后果是测试文件数量与 PR 数量成正比增长且文件名携带 PR 编号或需求特征如enh-3170、bug-3166、feat-3347-config、feat-3347-hook、bug-3579测试的逻辑归属被提交历史取代——同属查询预算的用例散落在不同文件中读者无法从目录结构判断测试覆盖了哪些行为面文件头部注释承担了本应由 describe 块承担的分类职责导致命名空间混乱、重复 fixture 定义增多。从仓库现状看这次治理的直接产物是131 个既有测试 1 个新增 counter-testmvp-viz 的非 MVP 路径全部收敛到一个按 surface 组织 describe 块的单文件中并同时向 CONTEXT.md 的模块索引补充了 Knowledge Graph Module 词条使测试结构、模块文档、能力清单三者对齐。1.2 当前仓库中的最终形态先合并、后按 surface 物理拆分需要说明的是当前仓库的测试文件在头部注释中保留了这段历史的完整轨迹。例如 tests/graphify.test.cjs 开头写着 Split from the consolidated 2336-LOC file. Refs #3761tests/graphify-query.test.cjs 同样标注 Split from the consolidated 2336-LOC file. Refs #3761。从源码结构可以推断#3761 先把散落的测试合并为一个约 2336 行的逻辑单文件随后又按 describe 分区物理拆分回多个文件但每个文件都承接了合并时确立的 surface 分区与 issue 标注纪律。最终形成的文件布局与 describe 分区对应关系如下测试文件describe 分区surface核心覆盖tests/graphify.test.cjsstatus、build三态门、子进程执行、安装与版本检测、构建预检、快照tests/graphify-query.test.cjsquery安全读 JSON、邻接表、seed-and-expand、预算裁剪、diff、优雅降级、属性测试tests/graphify-visualization.test.cjsstaleness、mvp-viz、regressions提交级过期信号、MVP 渲染契约、#3166/#3579 结构性护栏tests/graphify-auto-update.slow.test.cjsauto-updategraphify.auto_update配置键面与钩子行为二、status 测试面三态能力门与封闭式 fixturestatus分区是 #3761 合并后最先重构的 describe 块其核心命题是tri-state gate三态门graphify 命令的可用性不再只看配置文件而是要求已安装 AND 已 surfacing AND 配置开启三者同时成立。2.1 从 isGraphifyEnabled 到 isCapabilityActive在 tests/graphify.test.cjs 的注释中这段 cutover 被记录得十分详细旧的门控isGraphifyEnabled只检查.planning/config.json里的graphify.enabled新的门控isCapabilityActive(graphify, cwd)来自 src/capability-state.cts把能力是否安装、是否在运行时配置目录中 surfacing、是否配置开启三个维度叠加。对应的回归测试 graphifyStatus gate outcome matches isCapabilityActive 是一个fail-first proof它在旧代码上必然失败——例如已安装、未 surfacing、但 config 里 enabledtrue的环境下旧门控返回 true不 disabled新门控返回 falsedisabled。测试用assert.ok(!result.disabled)与assert.strictEqual(result.disabled, true)两个分支把正反两个结果都锁死见 tests/graphify.test.cjs。2.2 TEST-03-HERMETIC封闭式三态 fixture环境依赖型测试是这类能力的典型痛点正路径测试只有在宿主机器恰好 surfacing 了 graphify 时才通过。为此测试块引入了makeSurfacedConfigDir()fixturetests/graphify.test.cjs在临时目录写入显式的.gsd-surface.json{ baseProfile: full, disabledClusters: [], explicitAdds: [], explicitRemoves: [] }再通过CLAUDE_CONFIG_DIR环境变量指向该目录并清空GSD_RUNTIME、GSD_WORKSTREAM、GSD_PROJECT三个环境变量保证planningDir()不会被环境残留重定向注释中甚至点名了 hermeticity 回归 #872。TEST-03-HERMETIC 负例构造了安装 配置开启 未 surfacing的场景.gsd-surface.json中disabledClusters: [graphify]而 config 中graphify.enabled: true断言isCapabilityActive返回 false、graphifyStatus返回 disabled同组还设了 positive controldisabledClusters 为空时返回非 disabled证明 fixture 本身自洽tests/graphify.test.cjs。2.3 status 的其他契约disabledResponse()必须包含可执行的开启指引gsd-tools config-set graphify.enabled truetests/graphify.test.cjs无图时报exists: false与 No graph built yet 消息有图时报 node/edge/hyperedge 计数、last_build、stale、age_hoursSTAT-01/STAT-02links 键回退graphify 输出的边可能写在links而非edgesstatus 的edge_count必须正确读取LINKS-02tests/graphify.test.cjs。三、build 测试面子进程执行、安装检测、版本校验与构建预检build分区由execGraphify、checkGraphifyInstalled、checkGraphifyVersion、graphifyBuild、writeSnapshot五个 describe 组成是源码 src/graphify.cts 中构建管线的直接测试投影。3.1 execGraphifytyped reason 取代 stderr 文本匹配#2974 迁移让execGraphify返回结构化reason字段GRAPHIFY_REASON枚举测试断言从grep stderr 中的 not found/timed out改为直接比对枚举值。枚举定义在 src/graphify.ctsconst GRAPHIFY_REASON Object.freeze({ OK: ok, ENOENT: graphify_not_found, TIMEOUT: graphify_timed_out, EXIT_NONZERO: graphify_exit_nonzero, } as const);测试覆盖tests/graphify.test.cjs成功时exitCode: 0stdout/stderr 原样返回并去除首尾空白ENOENT归一化为exitCode: 127reason: GRAPHIFY_REASON.ENOENT超时归一化为exitCode: 124reason: GRAPHIFY_REASON.TIMEOUT且timeout_ms被回传外部 SIGTERM 不是超时这是对共享谓词isSpawnTimeout位于 src/shell-command-projection.cts的回归——判定以error.code ETIMEDOUT为准因为 Windows 上 SIGTERM 并不可靠且外部 kill 产生的 SIGTERM 不是超时环境变量强制注入PYTHONUNBUFFERED1保证 graphify Python 输出不被缓冲截断默认超时30000ms且options.timeout可被显式覆盖测试用60000作为覆盖 fixture 值。3.2 checkGraphifyInstalled用 --help 而非 --version 探测graphify CLI 不支持--version因此探测命令固定为--helptests/graphify.test.cjs。未安装时的 message 给出安装指引uv pip install graphifyy graphify install。注意这里区分了两个名字CLI 二进制叫graphifyPython 包叫graphifyy。3.3 checkGraphifyVersion版本区间与身份验证版本兼容区间为0.4.0,1.0源码注释明确 Tested range见 src/graphify.cts。测试矩阵tests/graphify.test.cjs版本compatible说明0.4.0 / 0.9.5true区间内0.3.0 / 1.0.0false区间外warning 含 outside tested range无法解析unknownnullwarning 含 Could not parsepython3 缺失versionnullwarning 含 Could not determine值得注意的 #3020 回归即使graphify --version返回了貌似合法的版本号若python3 importlib.metadata无法确认graphifyy包存在就判定为foreign binarycompatible: false并给出命名包的警告——一个恰好打印出版本字符串的无关二进制不能冒充 graphify。调用顺序也有测试锁定先graphify --version失败时再回退到python3 -c from importlib.metadata import version; print(version(graphifyy))。3.4 graphifyBuild结构化预检而非执行graphifyBuild不直接调用 graphify而是返回给调用方命令技能的结构化预检 JSONsrc/graphify.cts{ action: spawn_agent, graphs_dir: planningDir/graphs, graphify_out: cwd/graphify-out, timeout_seconds: 300, version: 0.4.3, version_warning: null, artifacts: [graph.json, graph.html, GRAPH_REPORT.md] }测试验证了未启用时返回 disabled未安装时返回带安装指引的 error成功后action spawn_agent缺失的graphs目录会被自动创建graphify.build_timeout配置能覆盖默认 300 秒写入600后返回timeout_seconds: 600版本出界时附带version_warningtests/graphify.test.cjs。spawn_agent这个名字在 commands/gsd/graphify.md 中被解释为历史遗留graphify v0.7 把构建拆成 AST 提取与聚类写报告两段子代理隔离会在代理退出时 SIGTERM 掉后半段导致缓存已填充但graph.json未写出#3166。因此技能改为前台内联执行完整构建链但 CLI 仍保留spawn_agent信号以兼容外部调用方与测试。3.5 writeSnapshotdiff 基线的写入契约每次成功构建后writeSnapshot把graph.json的 nodes/edges 写入.last-build-snapshot.jsonversion: 1带timestamp作为下一次diff的基线src/graphify.cts。测试覆盖正常写入并校验落盘文件结构、缺图报 not parseable 错误、非法 JSON 报错、空节点/缺失键的宽容处理、以及重建时覆盖旧快照tests/graphify.test.cjs。四、query 测试面BFS 检索、预算裁剪与属性测试query分区tests/graphify-query.test.cjs覆盖从底层工具函数到顶层查询响应的完整链路。4.1 底层工具函数safeReadJson缺失文件、非法 JSON 一律返回null而非抛异常T-02-01 缓解对应 src/graphify.ctsbuildAdjacencyMap构造双向邻接表source→target 与 target→source 都入表孤立节点获得空数组边对象整体存入edge字段同样支持links回退LINKS-01seedAndExpand先在label与description上做大小写不敏感的子串匹配选出种子节点注意不匹配id或name再以 BFS 从种子出发扩展maxHops2跳边按source::target::label去重src/graphify.cts。测试用一个 5 节点样例图精确验证n5 距种子 3 跳必须被排除maxHops1时 n4 必须被排除。4.2 applyBudget置信度分级裁剪与 #2738 预算报告契约applyBudget是 query 面最复杂也最有测试深度的函数。它的裁剪顺序是AMBIGUOUS → INFERRED → EXTRACTED三档置信度逐级丢弃src/graphify.cts同时保证种子集是不可跌破的地板即使预算再紧种子节点必须保留每次移除一个 tier 后用裁剪后可达节点集重新估算避免裁掉 AMBIGUOUS 后孤儿节点让结果已达标、却仍继续裁掉 INFERRED的二级缺陷#2738裁剪结果附加trimmed脚注[N edges omitted, M nodes unreachable]budget_estimate必须等于实际发射载荷的 token 数——估算器对buildQueryResponse的产物含包装键、2 空格缩进、甚至budget_estimate自身位数做固定点迭代serializeForOutputestimateTokens并与发射器共用同一构建函数二者不可能漂移src/graphify.cts。测试专门锁定--budget 00 null是 false因此 0 是合法预算而非无预算Number.isFinite同时把NaN、Infinity、-Infinity挡在比较之外任何estimate NaN恒为 false会让循环把三个 tier 全部剥光、返回一个与激进裁剪无法区分的种子-only 载荷。边界覆盖测试则围绕estimate budget这一判定点做e-1 / e / e1三值验证#2738tests/graphify-query.test.cjs。4.3 属性测试预算契约的通用化证明合并后的测试引入了 fast-check 属性测试tests/graphify-query.test.cjs对任意小图和任意预算断言四条不变量budget_met与budget_estimate budget恒等budget_estimate恒等于发射载荷 token 数种子节点在任何预算下存活total_nodes/total_edges恒等于返回数组长度载荷随预算单调不减预算越大返回的边/节点数不可能更少。属性测试把 #2738 的预算报告契约从一个用例提升为任意输入都成立的数学性质。4.4 graphifyQuery 与 graphifyDiff 的顶层行为graphifyQuery的响应形状由buildQueryResponse统一构建src/graphify.ctsterm回显、nodes/edges、total_nodes/total_edges、trimmed且仅在请求预算时才出现budget_met/budget_estimate。graphifyDiff则对比当前图与快照按节点 id、按source::target::relation计算 added/removed/changed且快照与当前图都支持links键LINKS-03。无快照时返回no_baseline: true并提示先构建一次以生成基线。AGENT-03 优雅降级用例明确图缺失时graphifyQuery/graphifyStatus返回错误对象或exists: false绝不抛异常——包括空字符串在内的任意查询词都被遍历验证tests/graphify-query.test.cjs。五、staleness 测试面提交级过期信号#3170staleness分区tests/graphify-visualization.test.cjs验证 graphify v0.7 引入的built_at_commit提交级过期语义。此前 status 只有 mtime 维度的stale24 小时阈值而 mtime 与代码新鲜度可能矛盾——例如 CI 基于旧 checkout 刚构建的图mtime 显示 FRESH但代码已落后。新增字段构成三态语义场景commits_behindcommit_stale在 HEAD 重建0false已知新鲜落后 5 个提交5true无built_at_commitv0.7 之前nullnull未知区别于 false提交被 rebase 掉 / 不可达nullnull非 git 目录nullnull安全细节built_at_commit在交给git前必须通过^[0-9a-f]{4,40}$校验src/graphify.cts否则一个恶意值如--upload-packevil会被当作普通字符串拼进 git argv 造成参数注入。测试用一个--upload-packevil的畸形值验证它被拒绝、不会被回显tests/graphify-visualization.test.cjs。back-compat 子块同时保证新增字段不改变既有字段exists、node_count、stale、age_hours且 disabled 响应路径不携带任何 commit 字段。六、mvp-viz 测试面MVP 渲染契约与 counter-testmvp-viz分区tests/graphify-visualization.test.cjs把 commands/gsd/graphify.md 中关于 MVP 模式的渲染规则固化为结构化契约测试——测试解析技能文档的 YAML frontmatter 与 fenced code block 为结构化 IR再对解析结果断言而不是对原文做文本 grep。契约内容当 ROADMAP.md 中某 phase 的**Mode:** mvp时其图节点必须同时具备两个视觉信号——填充色#22c55e绿色与(MVP)标签后缀phase mode 为 null/absent 时回落为标准渲染。双通道设计颜色 文字服务于色弱与灰度渲染场景PRD Q5 决策。counter-test正是关联文档中提到的新增的第 132 个测试它断言非 MVP phase 的回退渲染路径必须被文档化——fallback 行的存在本身就证明 MVP 渲染不是全局默认从而防止将来有人把 MVP 样式误应用到所有节点。这是用测试钉死文档契约的典型手法文档必须写明特殊情况的例外例外才会被视作例外。七、auto-update 测试面可选自动更新#3347auto-update分区tests/graphify-auto-update.slow.test.cjs覆盖graphify.auto_update配置键的完整生命周期VALID_CONFIG_KEYS集合与isValidConfigKey均接受graphify.auto_updateconfig-set命令才可写入同时保持旧键graphify.enabled有效规范默认值CANONICAL_CONFIG_DEFAULTS.graphify.auto_update false——默认关闭、显式 opt-in符合 #3347 验收标准config-set graphify.auto_update true必须成功且真正写入.planning/config.json。该键驱动 hooks/gsd-graphify-update.sh 钩子在 HEAD 推进后自动重建知识图谱并把执行状态写入.last-build-status.jsongraphifyStatus会把该文件中failed/running状态折叠进既有的stale: true信号src/graphify.cts让下游消费者planner、phase-researcher无需各自改动即可沿用语义关系是近似值的既有注解。八、regressions 测试面技能文档的结构性护栏#3166 / #3579regressions分区最有启发性的一点是对技能文档Markdown本身做结构化断言让文档与实现同步演进防止修复被回滚。8.1 #3166内联构建护栏针对子代理 SIGTERM 截断 graphify v0.7 后半段构建的缺陷测试断言tests/graphify-visualization.test.cjscommands/gsd/graphify.md 的 frontmatterallowed-tools不得包含Task禁止子代理且必须保留Read与Bashconfig 门与内联构建所需所有 fenced code block 中不得出现Task(调用语法仅禁止调用表达式提及单词 Task 的散文不在此列必须存在一个 bash 代码块同时调用graphify update .与gsd_run graphify build snapshot——即构建链的端到端管线被文档级测试钉死。这与技能文档的 Anti-Patterns 一节commands/gsd/graphify.md相互印证禁止 spawn agent、禁止run_in_background: true、禁止直接修改图文件、禁止跳过 config 门、禁止用gsd-tools config get-value读门该命令对缺失键会硬退出。8.2 #3579钩子打包与安装缺口auto-update 钩子在 1.50.0-canary 系列中死胎的两个缺口被回归测试捕获scripts/build-hooks.js的HOOKS_TO_COPY漏掉了gsd-graphify-update.shGap 1以及hooks/lib/gsd-graphify-rebuild.sh未被安装器复制Gap 2。测试的实际策略是运行真实的构建脚本与安装器再断言文件系统结果hooks/dist/gsd-graphify-update.sh与hooks/dist/lib/gsd-graphify-rebuild.sh必须存在且安装到CLAUDE_CONFIG_DIR目标后钩子与 lib 辅助脚本均已部署tests/graphify-visualization.test.cjs。这类测试不 mock而是跑真实产物因此能捕获打包清单这类纯装配缺陷。九、源码侧的单一真相源src/graphify.cts合并测试所对应的实现在 src/graphify.cts 中保持为单一 TypeScript 模块。文件头注释ADR-457 build-at-publish说明手写的bin/lib/graphify.cjs已坍缩为 TypeScript 真相源行为逐字节保留仅增加类型。模块内部按测试分区一一对应地组织三态门统一通过isCapabilityActive(graphify, cwd)进入disabledResponse()返回标准禁用响应src/graphify.cts子进程execGraphify走 src/shell-command-projection.cts 的execTool统一了超时判定、ENOENT 归一化与跨平台二进制解析图定位resolveGraphLocation支持graphify.graph_path配置#1825允许一个伞级图服务多个兄弟项目status把解析后的绝对路径作为graph_path回传#4836shell-out 调用方可把它作为--graph传入知识图谱模块在 CONTEXT.md 的 Knowledge Graph Module 词条中对上述职责做了总览——这正是关联文档提到的 glossary 条目使模块索引、能力清单与测试分区三者一致。十、可复现的工程实践启示回顾这次测试治理可以提炼出四条可迁移的工程纪律以行为面surface而非 PR 划分测试归属status/build/query/staleness/mvp-viz/auto-update/regressions的分区让这个能力有哪些契约一眼可读测试文件不再是对提交历史的镜像。回归测试必须 fail-first 且封闭每个回归用例都注释旧代码上此测试必然失败的证明如三态门 cutover并用显式 fixture.gsd-surface.json 环境变量隔离消除宿主环境依赖杜绝恰好在某台机器上通过的假阳性。对文档与配置面做结构化断言mvp-viz 与 regressions 分区直接解析技能文档为 IR 后断言让 Markdown 也纳入回归覆盖auto-update 分区验证VALID_CONFIG_KEYS与规范默认值防止配置键面悄悄漂移。属性测试巩固数值型契约预算裁剪这类任意输入都必须成立的契约用 fast-check 断言单调性与计量恒等式比单点用例更接近数学证明。若要在本仓库实际运行这些测试可直接执行node --test tests/graphify.test.cjs tests/graphify-query.test.cjs tests/graphify-visualization.test.cjsauto-update 用例为慢速标签运行tests/graphify-auto-update.slow.test.cjs前请先确认仓库测试环境的node:test版本支持所需 API。测试夹具集中在 tests/helpers/graphify.cjsenableGraphify、writeGraphJson、SAMPLE_GRAPH等源码真相源在 src/graphify.cts命令契约在 commands/gsd/graphify.md功能文档可参考 docs/features/knowledge-graph-integration.md 与 docs/features/graphify-commit-based-staleness.md。赞分享【免费下载链接】gsd-coreGit. Ship. Done - Core项目地址https://gitcode.com/gh_mirrors/ge/gsd-core点击查看免费下载相关推荐gsd-core 安装器测试整合3758 将 11 个测试文件收敛为 2 个参数化套件gsd core 安装器测试整合 3758 将 11 个测试文件收敛为 2 个参数化套件 本文以 .changeset/archived/3758 consoCherry Studio 文件模块 IPC 重构从 52 个散落通道到 FileManager 统一入口Cherry Studio 文件模块 IPC 重构从 52 个散落通道到 FileManager 统一入口 导读 本文基于 cherry studio 仓库中人工智能大模型AI 应用交互助手本地部署get-shit-doneMilestone 模块测试集群整合实战——从 10 个文件到 4 个的测试治理方案get shit doneMilestone 模块测试集群整合实战——从 10 个文件到 4 个的测试治理方案 本文以 PR 3753 的 changeset人工智能AI 应用提示工程开发工具工作流自动化AI Agent上一篇如何快速扩展AI界面完整的A2UI自定义组件开发指南下一篇终极指南使用syzkaller进行内核测试覆盖率分析的10个关键技巧创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表