——面向多类型产物的 Stub 检测与 Wiring 验证实战)
从文件存在到功能可用解析 get-shit-done 验证模式Verification Patterns——面向多类型产物的 Stub 检测与 Wiring 验证实战【免费下载链接】get-shit-doneA light-weight and powerful meta-prompting, context engineering and spec-driven development system for Claude Code by TÂCHES.项目地址: https://gitcode.com/GitHub_Trending/getshi/get-shit-done导读get-shit-doneGSD是一个基于 Claude Code 的规格驱动开发Spec-Driven Development系统。在它的每一个执行阶段收尾处都要回答一个关键问题阶段产物到底是真实实现还是只是占位文件/空壳stub本文围绕get-shit-done/references/verification-patterns.md这份核心参考文档展开系统拆解它提出的存在 ≠ 实现四层验证模型覆盖 React/Next.js 组件、API 路由、数据库 Schema、自定义 Hooks、环境变量以及跨层 Wiring接线验证的完整 grep/检查套路。读完你既能掌握一整套可复制、可直接用于任何全栈仓库的自动化验证脚本也能理解它在 GSD 的gsd-verifier验证代理与verify-phase工作流中的落地方式。一、这份文档在 GSD 系统中的位置与价值verification-patterns.md属于 GSD 的共享知识references层被系统文档 docs/ARCHITECTURE.md 明确登记为如何验证不同类型的产物how to verify different artifact types的核心参考。它的直接消费者有三个验证代理 gsd-verifier负责目标回溯goal-backward验证即只信代码库中的证据、不信 SUMMARY.md 里的自述验证工作流 verify-phase把verification-patterns.md列为required_reading必读材料与verification-report.md模板一起驱动验证子代理验证报告模板 verification-report规定.planning/phases/{phase_dir}/{phase_num}-VERIFICATION.md的输出结构验证模式文档中的所有检查结论最终都要沉淀为这种结构化报告。与之配套的还有 gates.md四种闸门类型中的 Revision Gate 即由验证器承担、get-shit-done/references/verification-overrides.md允许对刻意偏差放行以及get-shit-done/references/checkpoints.md前置 checkpoint 的自动化约定。本文只聚焦验证模式本身如何用低成本的手段识破看起来存在、实际上没用的产物。二、核心原则Existence ≠ Implementation存在 ≠ 实现文档开篇即抛出系统中最重要的一条反直觉原则一个文件存在并不代表功能可用。验证必须逐层回答四个问题层级问题检查手段能否自动化1. Exists存在文件是否出现在预期路径[ -f path ]✅ 程序化2. Substantive实质内容是否是真实现而非占位grep stub 特征、行数、模式匹配✅ 程序化3. Wired接线是否与系统其余部分连通grep import/调用/端点引用✅ 程序化可部分4. Functional功能被真正调用时是否真的工作运行/点按/观察⚠️ 常需人工其中 1–3 层可以全部程序化检查第 4 层往往必须靠人工或端到端自动化。这与gsd-verifier代理中一个文件被创建 ≠ 目标达成Task completion ≠ Goal achievement的立场完全一致——在 gsd-verifier 代理中验证器被要求以对抗性预设Adversarial Stance运行先假设阶段目标没有达成直到代码库证据能证明它达成以此反向证伪 SUMMARY 的叙事。三、通用 Stub 检测模式不区分文件类型在针对具体产物类型展开之前文档先给出了四组跨文件类型通用的占位/空壳特征。任何文件只要命中下列 grep 模式就需要被标记为可疑。1. 基于注释的 Stub# Grep patterns for stub comments grep -E (TODO|FIXME|XXX|HACK|PLACEHOLDER) $file grep -E implement|add later|coming soon|will be $file -i grep -E // \.\.\.|/\* \.\.\. \*/|# \.\.\. $file说明TODO/FIXME/XXX/HACK/PLACEHOLDER是欠债标记implement / add later / coming soon / will be是未来式自白第三条匹配. ..形式的省略占位。需要注意GSD 在 gsd-verifier 代理的防反模式扫描中还定义了更严格的规则——本阶段改动的文件里若出现未被正式跟进如issue #123、PR #123、DEF-*引用的TBD/FIXME/XXX标记直接升级为 BLOCKER。2. 输出中的占位文本# UI placeholder patterns grep -E placeholder|lorem ipsum|coming soon|under construction $file -i grep -E sample|example|test data|dummy $file -i grep -E \[.*\]|.*|\{.*\} $file # Template brackets left in说明placeholder / lorem ipsum / coming soon / under construction是典型 UI 占位sample / example / test data / dummy暗示内容来自样例而非真实数据第三条则捕捉模板括号残留在产物中的情况。3. 空实现或琐碎实现# Functions that do nothing grep -E return null|return undefined|return \{\}|return \[\] $file grep -E pass$|\.\.\.|\bnothing\b $file grep -E console\.(log|warn|error).*only $file # Log-only functions说明返回空值、只pass、只打日志不干活的函数都是高概率空壳。4. 应动态生成却硬编码的值# Hardcoded IDs, counts, or content grep -E id.*.*[\].*[\] $file # Hardcoded string IDs grep -E count.*.*\d|length.*.*\d $file # Hardcoded counts grep -E \\\$\d\.\d{2}|\d items $file # Hardcoded display values说明id xxx、写死的数量、写死的金额/条目数通常意味着底层没有真实数据源。重要提醒来自 gsd-verifier 代理grep 命中只有在该值流向渲染/用户可见输出、且没有其他代码路径用真实数据回填它时才构成 Stub。测试辅助代码、类型默认值、会被 fetch/store 覆盖的初始 state 都不算 Stub。四、按产物类型逐层验证4.1 React / Next.js 组件存在性检查——文件存在且确实导出了组件# File exists and exports component [ -f $component_path ] grep -E export (default |)function|export const.*.*\( $component_path实质性检查——返回真实 JSX、有实际内容、消费 props 或 state# Returns actual JSX, not placeholder grep -E return.* $component_path | grep -v return.*null | grep -v placeholder -i # Has meaningful content (not just wrapper div) grep -E [A-Z][a-zA-Z]|className|onClick|onChange $component_path # Uses props or state (not static) grep -E props\.|useState|useEffect|useContext|\{.*\} $component_pathReact 专属的红旗RED FLAGS模式——看到这些基本可判定是 Stub// RED FLAGS - These are stubs: return divComponent/div return divPlaceholder/div return div{/* TODO */}/div return pComing soon/p return null return / // Also stubs - empty handlers: onClick{() {}} onChange{() console.log(clicked)} onSubmit{(e) e.preventDefault()} // Only prevents default, does nothing注意第二组空 handler非常隐蔽console.log假装有行为e.preventDefault()看似处理了提交实则什么都没做。接线检查Wiring——组件真的把自己需要的东西连上了# Component imports what it needs grep -E ^import.*from $component_path # Props are actually used (not just received) # Look for destructuring or props.X usage grep -E \{ .* \}.*props|\bprops\.[a-zA-Z] $component_path # API calls exist (for># Route file exists [ -f $route_path ] # Exports HTTP method handlers (Next.js App Router) grep -E export (async )?(function|const) (GET|POST|PUT|PATCH|DELETE) $route_path # Or Express-style handlers grep -E \.(get|post|put|patch|delete)\( $route_path实质性检查——有真实逻辑、与数据源交互、有错误处理、返回有意义响应# Has actual logic, not just return statement wc -l $route_path # More than 10-15 lines suggests real implementation # Interacts with data source grep -E prisma\.|db\.|mongoose\.|sql|query|find|create|update|delete $route_path -i # Has error handling grep -E try|catch|throw|error|Error $route_path # Returns meaningful response grep -E Response\.json|res\.json|res\.send|return.*\{ $route_path | grep -v message.*not implemented -iAPI 路由专属红旗// RED FLAGS - These are stubs: export async function POST() { return Response.json({ message: Not implemented }) } export async function GET() { return Response.json([]) // Empty array with no DB query } export async function PUT() { return new Response() // Empty response } // Console log only: export async function POST(req) { console.log(await req.json()) return Response.json({ ok: true }) }接线检查# Imports database/service clients grep -E ^import.*prisma|^import.*db|^import.*client $route_path # Actually uses request body (for POST/PUT) grep -E req\.json\(\)|req\.body|request\.json\(\) $route_path # Validates input (not just trusting request) grep -E schema\.parse|validate|zod|yup|joi $route_path功能性验证人工或自动化GET 是否从数据库返回真实数据POST 是否真的创建记录错误响应状态码是否正确鉴权是否真正生效4.3 数据库 SchemaPrisma / Drizzle / SQL存在性检查——Schema 文件存在模型/表有定义# Schema file exists [ -f prisma/schema.prisma ] || [ -f drizzle/schema.ts ] || [ -f src/db/schema.sql ] # Model/table is defined grep -E ^model $model_name|CREATE TABLE $table_name|export const $table_name $schema_path实质性检查——不只是id字段有完整字段/关系/类型# Has expected fields (not just id) grep -A 20 model $model_name $schema_path | grep -E ^\s\w\s\w # Has relationships if expected grep -E relation|REFERENCES|FOREIGN KEY $schema_path # Has appropriate field types (not all String) grep -A 20 model $model_name $schema_path | grep -E Int|DateTime|Boolean|Float|Decimal|JsonSchema 专属红旗// RED FLAGS - These are stubs: model User { id String id // TODO: add fields } model Message { id String id content String // Only one real field } // Missing critical fields: model Order { id String id // No: userId, items, total, status, createdAt }接线检查——迁移已存在且已应用、客户端已生成# Migrations exist and are applied ls prisma/migrations/ 2/dev/null | wc -l # Should be 0 npx prisma migrate status 2/dev/null | grep -v pending # Client is generated [ -d node_modules/.prisma/client ]功能性验证可自动化# Can query the table (automated) npx prisma db execute --stdin SELECT COUNT(*) FROM $table_name4.4 自定义 Hooks 与工具函数存在性检查# File exists and exports function [ -f $hook_path ] grep -E export (default )?(function|const) $hook_path实质性检查——真的用了 React hooks、有意义的返回值、超过琐碎长度# Hook uses React hooks (for custom hooks) grep -E useState|useEffect|useCallback|useMemo|useRef|useContext $hook_path # Has meaningful return value grep -E return \{|return \[ $hook_path # More than trivial length [ $(wc -l $hook_path) -gt 10 ]Hook 专属红旗// RED FLAGS - These are stubs: export function useAuth() { return { user: null, login: () {}, logout: () {} } } export function useCart() { const [items, setItems] useState([]) return { items, addItem: () console.log(add), removeItem: () {} } } // Hardcoded return: export function useUser() { return { name: Test User, email: testexample.com } }接线检查——Hook 被别处 import 并真正调用# Hook is actually imported somewhere grep -r import.*$hook_name src/ --include*.tsx --include*.ts | grep -v $hook_path # Hook is actually called grep -r $hook_name() src/ --include*.tsx --include*.ts | grep -v $hook_path4.5 环境变量与配置存在性检查# .env file exists [ -f .env ] || [ -f .env.local ] # Required variable is defined grep -E ^$VAR_NAME .env .env.local 2/dev/null实质性检查——值不是占位、类型看起来合法# Variable has actual value (not placeholder) grep -E ^$VAR_NAME. .env .env.local 2/dev/null | grep -v your-.*-here|xxx|placeholder|TODO -i # Value looks valid for type: # - URLs should start with http # - Keys should be long enough # - Booleans should be true/false环境变量专属红旗# RED FLAGS - These are stubs: DATABASE_URLyour-database-url-here STRIPE_SECRET_KEYsk_test_xxx API_KEYplaceholder NEXT_PUBLIC_API_URLhttp://localhost:3000 # Still pointing to localhost in prod接线检查——变量真的被代码使用、进入校验 schema# Variable is actually used in code grep -r process\.env\.$VAR_NAME|env\.$VAR_NAME src/ --include*.ts --include*.tsx # Variable is in validation schema (if using zod/etc for env) grep -E $VAR_NAME src/env.ts src/env.mjs 2/dev/null五、Wiring接线验证绝大多数 Stub 藏身之处文档断言接线验证检查的是组件之间是否真正通信。这是 stub 藏得最深的地方。即使每个文件本身都看起来完整一旦彼此没接通系统依然是空壳。GSD 验证代理也明确要求绝不能跳过关键链路验证因为约 80% 的 stub 藏在这里见 gsd-verifier 代理。以下是四种经典接线模式及其红旗。模式 A组件 → API检查点组件是否真的调用了那个 API# Find the fetch/axios call grep -E fetch\([\].*$api_path|axios\.(get|post).*$api_path $component_path # Verify its not commented out grep -E fetch\(|axios\. $component_path | grep -v ^.*//.*fetch # Check the response is used grep -E await.*fetch|\.then\(|setData|setState $component_path红旗// Fetch exists but response ignored: fetch(/api/messages) // No await, no .then, no assignment // Fetch in comment: // fetch(/api/messages).then(r r.json()).then(setMessages) // Fetch to wrong endpoint: fetch(/api/message) // Typo - should be /api/messages模式 BAPI → 数据库检查点API 路由真的查询数据库了吗# Find the database call grep -E prisma\.$model|db\.query|Model\.find $route_path # Verify its awaited grep -E await.*prisma|await.*db\. $route_path # Check result is returned grep -E return.*json.*data|res\.json.*result $route_path红旗// Query exists but result not returned: await prisma.message.findMany() return Response.json({ ok: true }) // Returns static, not query result // Query not awaited: const messages prisma.message.findMany() // Missing await return Response.json(messages) // Returns Promise, not data模式 C表单 → Handler检查点表单提交真的做了点什么吗# Find onSubmit handler grep -E onSubmit\{|handleSubmit $component_path # Check handler has content grep -A 10 onSubmit.* $component_path | grep -E fetch|axios|mutate|dispatch # Verify not just preventDefault grep -A 5 onSubmit $component_path | grep -v only.*preventDefault -i红旗// Handler only prevents default: onSubmit{(e) e.preventDefault()} // Handler only logs: const handleSubmit (data) { console.log(data) } // Handler is empty: onSubmit{() {}}模式 DState → Render检查点组件渲染的是 state而不是硬编码内容# Find state usage in JSX grep -E \{.*messages.*\}|\{.*data.*\}|\{.*items.*\} $component_path # Check map/render of state grep -E \.map\(|\.filter\(|\.reduce\( $component_path # Verify dynamic content grep -E \{[a-zA-Z_]\. $component_path # Variable interpolation红旗// Hardcoded instead of state: return div pMessage 1/p pMessage 2/p /div // State exists but not rendered: const [messages, setMessages] useState([]) return divNo messages/div // Always shows no messages // Wrong state rendered: const [messages, setMessages] useState([]) return div{otherData.map(...)}/div // Uses different data纵深提示GSD 把这种链路检查进一步抽象成了verify.key-links查询gsd-sdk query verify.key-links每条链路会给出{ from, to, via, verified, detail }同时在产物通过 Exists/Substantive/Wired 三层后还有第 4 层数据流追踪Data-Flow Trace——向上游追溯数据源识别出STATIC有 fetch 但只有静态兜底、DISCONNECTED无数据源与HOLLOW_PROP调用处把 props 硬编码为空三类空心状态见 gsd-verifier 代理。六、快速验证清单Quick Verification Checklist文档为每种产物类型给出了一个可直接勾选的最小验证集是人工核对时的速查表。组件清单文件存在于预期路径导出了 function/const 组件返回 JSX非 null/空渲染中没有占位文本使用了 props 或 state非静态事件处理器有真实实现import 解析正确在应用某处被使用API 路由清单文件存在于预期路径导出了 HTTP 方法处理器处理器超过 5 行查询了数据库或服务返回有意义的响应非空/占位有错误处理校验了输入被前端调用Schema 清单模型/表已定义包含所有预期字段字段类型合适必要时定义了关系迁移存在且已应用客户端已生成Hook/工具函数清单文件存在导出了函数有实际实现非空返回在应用某处被使用返回值被消费接线清单组件 → APIfetch/axios 调用存在且使用了响应API → 数据库查询存在且结果被返回表单 → HandleronSubmit 调用了 API/mutationState → Renderstate 变量出现在 JSX 中在 verification-report 模板中这些清单被对应为三类结构化表格Observable Truths可观察真值、Required Artifacts必需产物标注✓ EXISTS SUBSTANTIVE/✗ STUB/✗ MISSING、Key Link Verification关键链路标注✓ WIRED/✗ NOT WIRED。七、可落地的自动化验证脚本文档为验证子代理提供了一套可直接复用的 Bash 函数骨架把存在性 → stub → wiring → 实质性四步固化成脚本逻辑# 1. Check existence check_exists() { [ -f $1 ] echo EXISTS: $1 || echo MISSING: $1 } # 2. Check for stub patterns check_stubs() { local file$1 local stubs$(grep -c -E TODO|FIXME|placeholder|not implemented $file 2/dev/null || echo 0) [ $stubs -gt 0 ] echo STUB_PATTERNS: $stubs in $file } # 3. Check wiring (component calls API) check_wiring() { local component$1 local api_path$2 grep -q $api_path $component echo WIRED: $component → $api_path || echo NOT_WIRED: $component → $api_path } # 4. Check substantive (more than N lines, has expected patterns) check_substantive() { local file$1 local min_lines$2 local pattern$3 local lines$(wc -l $file 2/dev/null || echo 0) local has_pattern$(grep -c -E $pattern $file 2/dev/null || echo 0) [ $lines -ge $min_lines ] [ $has_pattern -gt 0 ] echo SUBSTANTIVE: $file || echo THIN: $file ($lines lines, $has_pattern matches) }使用方式对每个 must-have 产物运行以上检查把结果聚合成 VERIFICATION.md。这与 GSD 验证流程中的每步控制在 10 秒内、不启动服务、不修改状态的约束相呼应gsd-verifier 代理保证验证本身快速、无副作用、可重复。此外gsd-verifier 代理还补充了两级更贴近真实运行的验证行为抽查Behavioral Spot-Checks从 must-haves 中挑 2–4 个可用单条命令验证的行为例如curl验证 API 端点返回非空数据、node $CLI --help验证 CLI 输出、构建产物存在性、模块导出函数类型、npm test -- --grep定向跑测试探针执行Probe Execution对声明了 probe 的阶段验证器必须亲自运行bash scripts/.../tests/probe-*.sh不能拿 SUMMARY 中的 PASS 标记当作证据。八、何时必须升级为人工验证有些东西无法靠 grep 确认必须交给人来测。文档给出了清晰的升级边界永远需要人工视觉外观看起来对不对用户流程走通能不能真的完成这件事实时行为WebSocket、SSE外部服务集成Stripe、发邮件错误信息清晰度提示是否有帮助性能手感是否感觉流畅不确定时转人工grep 追踪不了的复杂接线依赖状态变化的动态行为边界情况与错误状态移动端响应式可访问性Accessibility给人工验证的请求要写成可执行的格式而不是笼统的请测一下## Human Verification Required ### 1. Chat message sending **Test:** Type a message and click Send **Expected:** Message appears in list, input clears **Check:** Does message persist after refresh? ### 2. Error handling **Test:** Disconnect network, try to send **Expected:** Error message appears, message not lost **Check:** Can retry after reconnect?在 GSD 的整体状态机里存在人工验证项会直接决定阶段状态是否为human_needed——即使所有可自动验证的产物都通过只要有一个人工项未完成状态就不得标记为passed见 gsd-verifier 代理 的决策树与 gates.md 中 Revision/Escalation 两种闸门语义。九、前置 Checkpoint 的自动化约定Pre-Checkpoint Automationverification-patterns.md末尾把验证与checkpoint关联起来并指向 checkpoints.md 的automation_reference一节几条关键原则是在展示 checkpoint 之前验证代理应先搭建好验证环境用户永远不需要亲自运行 CLI 命令只需访问 URL服务生命周期管理在 checkpoint 前启动服务、处理端口冲突、在需要的时间窗口内保持运行CLI 安装安全的场景自动安装否则把选择权交给用户并进入 checkpoint错误处理在 checkpoint 前修复损坏的环境绝不在设置失败的状态下展示 checkpoint。这条约定的本质与整份文档一脉相承验证要前置、自动化要彻底、失败不能带病过关。十、结语把验证从感觉变成清单verification-patterns.md提供的是一套不依赖运行应用即可执行的静态证据链四层验证模型Exists → Substantive → Wired → Functional、按产物类型组织的红旗清单、四条经典 Wiring 模式、可直接抄走的 Bash 检查函数以及哪些必须交给人测的清醒边界。它最终被 GSD 系统固化成gsd-verifier代理的对抗式验证流程与 VERIFICATION.md 报告结构agents/gsd-verifier.md、get-shit-done/workflows/verify-phase.md、get-shit-done/templates/verification-report.md。无论你是想复用这套模式为自己的 AI 编码流程把关还是单纯想在人工 code review 之外多一层廉价的自动化防线都可以直接从本文第五节开始抄起 grep把文件存在从一句结论降级为一个待验证的假设。【免费下载链接】get-shit-doneA light-weight and powerful meta-prompting, context engineering and spec-driven development system for Claude Code by TÂCHES.项目地址: https://gitcode.com/GitHub_Trending/getshi/get-shit-done创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考