claude-code-superkit 0.0.0-stage → 1.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +374 -2
- package/bin/cli.js +153 -0
- package/bin/inject-tokens.js +224 -0
- package/bin/measure-tokens.js +17 -0
- package/bin/superkit-counts-verify.sh +30 -0
- package/lib/codex.js +246 -0
- package/lib/docs-scaffold.js +147 -0
- package/lib/installer.js +499 -0
- package/lib/prompts.js +51 -0
- package/lib/settings-builder.js +51 -0
- package/lib/superpowers.js +99 -0
- package/lib/utils.js +117 -0
- package/lib/validator.js +84 -0
- package/package.json +49 -4
- package/packages/codex/AGENTS.md +396 -0
- package/packages/codex/INSTALL.md +342 -0
- package/packages/codex/config.toml +22 -0
- package/packages/codex/hooks/superkit.mjs +203 -0
- package/packages/codex/hooks.json +30 -0
- package/packages/codex/legacy-baseline.json +88 -0
- package/packages/codex/native-skills.txt +65 -0
- package/packages/codex/rules/default.rules +565 -0
- package/packages/codex/skills/ai-slop-cleaner/SKILL.md +44 -0
- package/packages/codex/skills/api-contract-sync/SKILL.md +96 -0
- package/packages/codex/skills/architect/SKILL.md +49 -0
- package/packages/codex/skills/audit-backend/SKILL.md +80 -0
- package/packages/codex/skills/audit-frontend/SKILL.md +82 -0
- package/packages/codex/skills/audit-infra/SKILL.md +87 -0
- package/packages/codex/skills/audit-orchestrator/SKILL.md +114 -0
- package/packages/codex/skills/behavioral-nudge-engine/SKILL.md +110 -0
- package/packages/codex/skills/benchmark/SKILL.md +49 -0
- package/packages/codex/skills/bot-reviewer/SKILL.md +94 -0
- package/packages/codex/skills/code-reviewer/SKILL.md +67 -0
- package/packages/codex/skills/codebase-onboarding-engineer/SKILL.md +46 -0
- package/packages/codex/skills/comment-rot-analyzer/SKILL.md +75 -0
- package/packages/codex/skills/commit-helper/SKILL.md +101 -0
- package/packages/codex/skills/critic/SKILL.md +56 -0
- package/packages/codex/skills/database-reviewer/SKILL.md +79 -0
- package/packages/codex/skills/debug-observer/SKILL.md +107 -0
- package/packages/codex/skills/dependency-checker/SKILL.md +69 -0
- package/packages/codex/skills/design-system-reviewer/SKILL.md +121 -0
- package/packages/codex/skills/dev-orchestrator/SKILL.md +304 -0
- package/packages/codex/skills/docs-reviewer/SKILL.md +86 -0
- package/packages/codex/skills/drizzle-orm-expert/SKILL.md +246 -0
- package/packages/codex/skills/e2e-test-generator/SKILL.md +95 -0
- package/packages/codex/skills/evaluator/SKILL.md +63 -0
- package/packages/codex/skills/frontend-perf-reviewer/SKILL.md +95 -0
- package/packages/codex/skills/frontend-ui-color-reviewer/SKILL.md +68 -0
- package/packages/codex/skills/frontend-ui-design-critic/SKILL.md +99 -0
- package/packages/codex/skills/frontend-ui-interaction-reviewer/SKILL.md +102 -0
- package/packages/codex/skills/frontend-ui-motion-reviewer/SKILL.md +85 -0
- package/packages/codex/skills/frontend-ui-reviewer/SKILL.md +81 -0
- package/packages/codex/skills/frontend-ui-typography-reviewer/SKILL.md +62 -0
- package/packages/codex/skills/gltf-debugging/SKILL.md +128 -0
- package/packages/codex/skills/go-benchmark/SKILL.md +217 -0
- package/packages/codex/skills/go-concurrency-reviewer/SKILL.md +113 -0
- package/packages/codex/skills/go-error-reviewer/SKILL.md +107 -0
- package/packages/codex/skills/go-grpc-patterns/SKILL.md +285 -0
- package/packages/codex/skills/go-modernizer/SKILL.md +111 -0
- package/packages/codex/skills/go-observability-reviewer/SKILL.md +121 -0
- package/packages/codex/skills/go-performance-reviewer/SKILL.md +112 -0
- package/packages/codex/skills/go-reviewer/SKILL.md +109 -0
- package/packages/codex/skills/go-samber-do/SKILL.md +158 -0
- package/packages/codex/skills/go-samber-lo/SKILL.md +178 -0
- package/packages/codex/skills/go-samber-oops/SKILL.md +174 -0
- package/packages/codex/skills/goal-verifier/SKILL.md +53 -0
- package/packages/codex/skills/health-checker/SKILL.md +109 -0
- package/packages/codex/skills/html-to-3d-texture/SKILL.md +153 -0
- package/packages/codex/skills/impeccable-craft/SKILL.md +101 -0
- package/packages/codex/skills/lint-runner/SKILL.md +85 -0
- package/packages/codex/skills/migrate/SKILL.md +60 -0
- package/packages/codex/skills/migration-reviewer/SKILL.md +88 -0
- package/packages/codex/skills/minimal-change-engineer/SKILL.md +44 -0
- package/packages/codex/skills/new-migration/SKILL.md +59 -0
- package/packages/codex/skills/nextjs-supabase-auth/SKILL.md +227 -0
- package/packages/codex/skills/output-enforcement/SKILL.md +71 -0
- package/packages/codex/skills/plan-checker/SKILL.md +53 -0
- package/packages/codex/skills/postgresql-optimization/SKILL.md +159 -0
- package/packages/codex/skills/pre-deploy-validator/SKILL.md +111 -0
- package/packages/codex/skills/presentation-reviewer/SKILL.md +88 -0
- package/packages/codex/skills/product-3d-lighting/SKILL.md +137 -0
- package/packages/codex/skills/project-architecture/SKILL.md +52 -0
- package/packages/codex/skills/py-reviewer/SKILL.md +100 -0
- package/packages/codex/skills/r3f-scene-reviewer/SKILL.md +88 -0
- package/packages/codex/skills/r3f-scroll-driven-3d/SKILL.md +162 -0
- package/packages/codex/skills/reality-checker/SKILL.md +61 -0
- package/packages/codex/skills/redis-patterns/SKILL.md +260 -0
- package/packages/codex/skills/review-orchestrator/SKILL.md +151 -0
- package/packages/codex/skills/rs-reviewer/SKILL.md +98 -0
- package/packages/codex/skills/ru-text/SKILL.md +132 -0
- package/packages/codex/skills/scaffold-endpoint/SKILL.md +44 -0
- package/packages/codex/skills/security-scanner/SKILL.md +94 -0
- package/packages/codex/skills/silent-failure-hunter/SKILL.md +176 -0
- package/packages/codex/skills/telegram-bot-builder/SKILL.md +120 -0
- package/packages/codex/skills/test-generator/SKILL.md +79 -0
- package/packages/codex/skills/test-runner/SKILL.md +101 -0
- package/packages/codex/skills/threejs-color-management/SKILL.md +97 -0
- package/packages/codex/skills/tree-generator/SKILL.md +63 -0
- package/packages/codex/skills/ts-reviewer/SKILL.md +90 -0
- package/packages/codex/skills/ui-design-reviewer/SKILL.md +89 -0
- package/packages/codex/skills/ui-reviewer/SKILL.md +103 -0
- package/packages/codex/skills/visual-reviewer/SKILL.md +85 -0
- package/packages/codex/skills/writing-agents/SKILL.md +165 -0
- package/packages/codex/skills/writing-commands/SKILL.md +173 -0
- package/packages/core/CLAUDE.md +118 -0
- package/packages/core/INTERNAL-FILES +16 -0
- package/packages/core/agents/ai-slop-cleaner.md +187 -0
- package/packages/core/agents/api-contract-sync.md +127 -0
- package/packages/core/agents/architect.md +205 -0
- package/packages/core/agents/audit-backend.md +137 -0
- package/packages/core/agents/audit-frontend.md +129 -0
- package/packages/core/agents/audit-infra.md +182 -0
- package/packages/core/agents/behavioral-nudge-engine.md +170 -0
- package/packages/core/agents/code-reviewer.md +195 -0
- package/packages/core/agents/codebase-onboarding-engineer.md +172 -0
- package/packages/core/agents/comment-rot-analyzer.md +115 -0
- package/packages/core/agents/critic.md +172 -0
- package/packages/core/agents/database-reviewer.md +201 -0
- package/packages/core/agents/debug-observer.md +261 -0
- package/packages/core/agents/dependency-checker.md +199 -0
- package/packages/core/agents/docs-reviewer.md +206 -0
- package/packages/core/agents/e2e-test-generator.md +261 -0
- package/packages/core/agents/evaluator.md +141 -0
- package/packages/core/agents/goal-verifier.md +130 -0
- package/packages/core/agents/health-checker.md +194 -0
- package/packages/core/agents/migration-reviewer.md +161 -0
- package/packages/core/agents/minimal-change-engineer.md +219 -0
- package/packages/core/agents/plan-checker.md +139 -0
- package/packages/core/agents/pre-deploy-validator.md +189 -0
- package/packages/core/agents/reality-checker.md +175 -0
- package/packages/core/agents/scaffold-endpoint.md +162 -0
- package/packages/core/agents/security-scanner.md +236 -0
- package/packages/core/agents/silent-failure-hunter.md +276 -0
- package/packages/core/agents/test-generator.md +146 -0
- package/packages/core/agents/tree-generator.md +141 -0
- package/packages/core/agents/ui-reviewer.md +172 -0
- package/packages/core/agents/visual-reviewer.md +211 -0
- package/packages/core/commands/audit.md +166 -0
- package/packages/core/commands/benchmark.md +130 -0
- package/packages/core/commands/commit.md +148 -0
- package/packages/core/commands/dev.md +302 -0
- package/packages/core/commands/docs-init.md +75 -0
- package/packages/core/commands/lint.md +137 -0
- package/packages/core/commands/migrate.md +146 -0
- package/packages/core/commands/new-migration.md +182 -0
- package/packages/core/commands/pair.md +209 -0
- package/packages/core/commands/review.md +195 -0
- package/packages/core/commands/security-scan.md +142 -0
- package/packages/core/commands/superkit-evolve.md +231 -0
- package/packages/core/commands/superkit-init.md +274 -0
- package/packages/core/commands/test.md +108 -0
- package/packages/core/commands/workflow.md +150 -0
- package/packages/core/docs/guide/01-getting-started.md +41 -0
- package/packages/core/docs-templates/README.md +33 -0
- package/packages/core/docs-templates/adr-template.md +62 -0
- package/packages/core/docs-templates/architecture/api-contracts.md +26 -0
- package/packages/core/docs-templates/architecture/api-reference.md +48 -0
- package/packages/core/docs-templates/architecture/auth-and-sessions.md +38 -0
- package/packages/core/docs-templates/architecture/backend-layers.md +42 -0
- package/packages/core/docs-templates/architecture/data-flow.md +26 -0
- package/packages/core/docs-templates/architecture/database-schema.md +51 -0
- package/packages/core/docs-templates/architecture/deployment.md +41 -0
- package/packages/core/docs-templates/architecture/frontend-state.md +46 -0
- package/packages/core/helpers/statusline.cjs +370 -0
- package/packages/core/hooks/CHAIN-SEMANTICS.md +84 -0
- package/packages/core/hooks/audit-settings-source.sh +98 -0
- package/packages/core/hooks/audit-trail.sh +120 -0
- package/packages/core/hooks/block-dangerous-git.sh +189 -0
- package/packages/core/hooks/bundle-import-check.sh +64 -0
- package/packages/core/hooks/compact-state-inject.sh +84 -0
- package/packages/core/hooks/config-protection.sh +68 -0
- package/packages/core/hooks/console-log-warning.sh +28 -0
- package/packages/core/hooks/context-monitor.sh +35 -0
- package/packages/core/hooks/dev-edit-counter.sh +59 -0
- package/packages/core/hooks/dev-marker-set.sh +55 -0
- package/packages/core/hooks/dev-required-on-commit.sh +426 -0
- package/packages/core/hooks/doc-check-on-commit.sh +396 -0
- package/packages/core/hooks/edit-streak-check.sh +63 -0
- package/packages/core/hooks/evolve-check.sh +78 -0
- package/packages/core/hooks/gateguard-pre-edit.sh +154 -0
- package/packages/core/hooks/gateguard-record-facts.sh +37 -0
- package/packages/core/hooks/intake-classifier.py +449 -0
- package/packages/core/hooks/lib/profile.sh +141 -0
- package/packages/core/hooks/loop-guard.sh +75 -0
- package/packages/core/hooks/migration-safety.sh +56 -0
- package/packages/core/hooks/plan-completion-gate.sh +61 -0
- package/packages/core/hooks/pre-compact-save.sh +89 -0
- package/packages/core/hooks/security-patterns.sh +119 -0
- package/packages/core/hooks/session-context-restore.sh +76 -0
- package/packages/core/hooks/subagent-stop-validate.sh +73 -0
- package/packages/core/hooks/superkit-counts-verify.sh +346 -0
- package/packages/core/hooks/superkit-update.sh +367 -0
- package/packages/core/hooks/tests/README.md +42 -0
- package/packages/core/hooks/tests/audit-trail-chain_test.sh +62 -0
- package/packages/core/hooks/tests/block-dangerous-git_test.sh +144 -0
- package/packages/core/hooks/tests/chain-semantics/h1.sh +11 -0
- package/packages/core/hooks/tests/chain-semantics/h2.sh +9 -0
- package/packages/core/hooks/tests/chain-semantics/h3.sh +11 -0
- package/packages/core/hooks/tests/chain-semantics/run-experiment.sh +65 -0
- package/packages/core/hooks/tests/chain-semantics/settings-experiment.json +15 -0
- package/packages/core/hooks/tests/counts-verify_test.sh +118 -0
- package/packages/core/hooks/tests/dev-required-on-commit_test.sh +207 -0
- package/packages/core/hooks/tests/dev-required-wip-on-main_test.sh +20 -0
- package/packages/core/hooks/tests/doc-check-on-commit_test.sh +122 -0
- package/packages/core/hooks/tests/edit-streak-check_test.sh +106 -0
- package/packages/core/hooks/tests/internal-manifest_test.sh +130 -0
- package/packages/core/hooks/tests/json-path_test.sh +108 -0
- package/packages/core/hooks/tests/mirror-invariants_test.sh +139 -0
- package/packages/core/hooks/tests/nudge-throttle_test.sh +95 -0
- package/packages/core/hooks/tests/profile-helper_test.sh +21 -0
- package/packages/core/hooks/tests/run-all.sh +47 -0
- package/packages/core/hooks/tests/session-key-helper_test.sh +17 -0
- package/packages/core/hooks/tests/superkit-update_test.sh +311 -0
- package/packages/core/hooks/tests/warn-visibility_test.sh +59 -0
- package/packages/core/hooks/user-intent-detect.sh +44 -0
- package/packages/core/hooks/verify-hooks.sh +69 -0
- package/packages/core/rules/auto-commands.md +124 -0
- package/packages/core/rules/coding-style.md +68 -0
- package/packages/core/rules/dev-workflow.md +77 -0
- package/packages/core/rules/documentation.md +106 -0
- package/packages/core/rules/frontend-aesthetics.md +53 -0
- package/packages/core/rules/git-workflow.md +14 -0
- package/packages/core/rules/security.md +29 -0
- package/packages/core/rules/superkit-integrity.md +114 -0
- package/packages/core/settings.json +229 -0
- package/packages/core/skills/drizzle-orm-expert/SKILL.md +260 -0
- package/packages/core/skills/nextjs-supabase-auth/SKILL.md +259 -0
- package/packages/core/skills/postgresql-optimization/SKILL.md +150 -0
- package/packages/core/skills/project-architecture/SKILL.md +31 -0
- package/packages/core/skills/project-scanner/SKILL.md +132 -0
- package/packages/core/skills/redis-patterns/SKILL.md +261 -0
- package/packages/core/skills/ru-text/SKILL.md +156 -0
- package/packages/core/skills/telegram-bot-builder/SKILL.md +145 -0
- package/packages/core/skills/writing-agents/SKILL.md +220 -0
- package/packages/core/skills/writing-commands/SKILL.md +176 -0
- package/packages/core/skills/writing-hooks/SKILL.md +335 -0
- package/packages/extras/bot-reviewer.md +279 -0
- package/packages/extras/design-system-reviewer.md +234 -0
- package/packages/extras/red-blue-auditor/README.md +117 -0
- package/packages/extras/red-blue-auditor/agent.md +128 -0
- package/packages/extras/red-blue-auditor/patterns/agent-config.txt +4 -0
- package/packages/extras/red-blue-auditor/patterns/hook-injection.txt +8 -0
- package/packages/extras/red-blue-auditor/patterns/mcp-risk.txt +5 -0
- package/packages/extras/red-blue-auditor/patterns/permission-abuse.txt +6 -0
- package/packages/extras/red-blue-auditor/patterns/secrets.txt +17 -0
- package/packages/extras/red-blue-auditor/scan.sh +88 -0
- package/packages/extras/skillsmp-search/SKILL.md +134 -0
- package/packages/frontend-3d/README.md +62 -0
- package/packages/frontend-3d/agents/frontend-perf-reviewer.md +164 -0
- package/packages/frontend-3d/agents/presentation-reviewer.md +146 -0
- package/packages/frontend-3d/agents/r3f-scene-reviewer.md +128 -0
- package/packages/frontend-3d/agents/ui-design-reviewer.md +169 -0
- package/packages/frontend-3d/commands/capture-screen.md +166 -0
- package/packages/frontend-3d/hooks/bundle-size-warn.sh +93 -0
- package/packages/frontend-3d/hooks/gsap-pattern-check.sh +74 -0
- package/packages/frontend-3d/hooks/r3f-color-check.sh +76 -0
- package/packages/frontend-3d/hooks/tailwind-version-guard.sh +98 -0
- package/packages/frontend-3d/rules/frontend-aesthetics-3d.md +81 -0
- package/packages/frontend-3d/rules/gsap-conventions.md +129 -0
- package/packages/frontend-3d/rules/threejs-conventions.md +116 -0
- package/packages/frontend-3d/skills/gltf-debugging/SKILL.md +145 -0
- package/packages/frontend-3d/skills/html-to-3d-texture/SKILL.md +183 -0
- package/packages/frontend-3d/skills/output-enforcement/SKILL.md +79 -0
- package/packages/frontend-3d/skills/product-3d-lighting/SKILL.md +166 -0
- package/packages/frontend-3d/skills/r3f-scroll-driven-3d/SKILL.md +209 -0
- package/packages/frontend-3d/skills/threejs-color-management/SKILL.md +111 -0
- package/packages/frontend-ui/NOTICE.md +99 -0
- package/packages/frontend-ui/README.md +59 -0
- package/packages/frontend-ui/agents/ui-color-reviewer.md +174 -0
- package/packages/frontend-ui/agents/ui-design-critic.md +198 -0
- package/packages/frontend-ui/agents/ui-interaction-reviewer.md +259 -0
- package/packages/frontend-ui/agents/ui-motion-reviewer.md +266 -0
- package/packages/frontend-ui/agents/ui-reviewer.md +251 -0
- package/packages/frontend-ui/agents/ui-typography-reviewer.md +222 -0
- package/packages/frontend-ui/hooks/tests/ui-animation-easing-check_test.sh +78 -0
- package/packages/frontend-ui/hooks/tests/ui-banned-fonts-check_test.sh +77 -0
- package/packages/frontend-ui/hooks/tests/ui-color-check_test.sh +75 -0
- package/packages/frontend-ui/hooks/ui-animation-easing-check.sh +86 -0
- package/packages/frontend-ui/hooks/ui-banned-fonts-check.sh +90 -0
- package/packages/frontend-ui/hooks/ui-color-check.sh +102 -0
- package/packages/frontend-ui/rules/color-and-contrast.md +230 -0
- package/packages/frontend-ui/rules/frontend-design-aesthetics.md +124 -0
- package/packages/frontend-ui/rules/interaction-polish.md +335 -0
- package/packages/frontend-ui/rules/motion-and-animation.md +283 -0
- package/packages/frontend-ui/rules/spatial-and-layout.md +212 -0
- package/packages/frontend-ui/rules/typography-guidelines.md +185 -0
- package/packages/frontend-ui/rules/ui-anti-patterns.md +309 -0
- package/packages/frontend-ui/settings.json +24 -0
- package/packages/frontend-ui/skills/impeccable-craft/SKILL.md +187 -0
- package/packages/gan/README.md +232 -0
- package/packages/gan/agents/gan-evaluator.md +214 -0
- package/packages/gan/agents/gan-generator.md +171 -0
- package/packages/gan/agents/gan-planner.md +206 -0
- package/packages/gan/rubrics/functionality.md +66 -0
- package/packages/gan/rubrics/ui-quality.md +77 -0
- package/packages/gan/skills/gan-evaluator/SKILL.md +91 -0
- package/packages/gan/skills/gan-generator/SKILL.md +72 -0
- package/packages/gan/skills/gan-planner/SKILL.md +93 -0
- package/packages/stack-agents/go/go-concurrency-reviewer.md +210 -0
- package/packages/stack-agents/go/go-error-reviewer.md +187 -0
- package/packages/stack-agents/go/go-modernizer.md +160 -0
- package/packages/stack-agents/go/go-observability-reviewer.md +185 -0
- package/packages/stack-agents/go/go-performance-reviewer.md +160 -0
- package/packages/stack-agents/go/go-reviewer.md +277 -0
- package/packages/stack-agents/go/references/benchmark-methodology.md +280 -0
- package/packages/stack-agents/go/references/channel-patterns.md +384 -0
- package/packages/stack-agents/go/references/cli-cobra-viper.md +190 -0
- package/packages/stack-agents/go/references/code-style.md +262 -0
- package/packages/stack-agents/go/references/context-propagation.md +317 -0
- package/packages/stack-agents/go/references/data-structures.md +315 -0
- package/packages/stack-agents/go/references/database-patterns.md +334 -0
- package/packages/stack-agents/go/references/design-patterns.md +411 -0
- package/packages/stack-agents/go/references/di-frameworks.md +146 -0
- package/packages/stack-agents/go/references/error-creation.md +251 -0
- package/packages/stack-agents/go/references/error-inspection.md +348 -0
- package/packages/stack-agents/go/references/error-wrapping.md +230 -0
- package/packages/stack-agents/go/references/gopls-driving.md +62 -0
- package/packages/stack-agents/go/references/goroutine-lifecycle.md +351 -0
- package/packages/stack-agents/go/references/graphql-patterns.md +221 -0
- package/packages/stack-agents/go/references/grpc-patterns.md +373 -0
- package/packages/stack-agents/go/references/modernize-guide.md +522 -0
- package/packages/stack-agents/go/references/module-management.md +191 -0
- package/packages/stack-agents/go/references/naming-conventions.md +176 -0
- package/packages/stack-agents/go/references/observability-pipeline.md +352 -0
- package/packages/stack-agents/go/references/performance-profiling.md +250 -0
- package/packages/stack-agents/go/references/refactoring-mechanics.md +127 -0
- package/packages/stack-agents/go/references/rest-openapi-patterns.md +160 -0
- package/packages/stack-agents/go/references/samber-do.md +201 -0
- package/packages/stack-agents/go/references/samber-libraries.md +363 -0
- package/packages/stack-agents/go/references/samber-lo.md +260 -0
- package/packages/stack-agents/go/references/samber-oops.md +200 -0
- package/packages/stack-agents/go/references/security-checklist.md +441 -0
- package/packages/stack-agents/go/references/standard-stdlib-now.md +181 -0
- package/packages/stack-agents/go/references/stay-updated.md +147 -0
- package/packages/stack-agents/go/references/structs-interfaces.md +312 -0
- package/packages/stack-agents/go/references/sync-primitives.md +395 -0
- package/packages/stack-agents/go/references/testing-patterns.md +483 -0
- package/packages/stack-agents/go/references/troubleshooting.md +98 -0
- package/packages/stack-agents/python/py-reviewer.md +194 -0
- package/packages/stack-agents/rust/rs-reviewer.md +188 -0
- package/packages/stack-agents/typescript/ts-reviewer.md +135 -0
- package/packages/stack-hooks/go/go-context-check-on-edit.sh +56 -0
- package/packages/stack-hooks/go/go-error-check-on-edit.sh +54 -0
- package/packages/stack-hooks/go/go-format-on-edit.sh +32 -0
- package/packages/stack-hooks/go/go-safety-check-on-edit.sh +54 -0
- package/packages/stack-hooks/go/go-vet-on-edit.sh +61 -0
- package/packages/stack-hooks/go/golangci-lint-on-edit.sh +54 -0
- package/packages/stack-hooks/python/ruff-on-edit.sh +67 -0
- package/packages/stack-hooks/rust/cargo-check-on-edit.sh +64 -0
- package/packages/stack-hooks/typescript/typecheck-on-edit.sh +76 -0
- package/packages/stack-rules/go/go-conventions.md +44 -0
- package/packages/stack-rules/go/go-safety.md +35 -0
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
# Testing Patterns
|
|
2
|
+
|
|
3
|
+
> Reference document for test-generator. Loaded on demand via Read tool.
|
|
4
|
+
|
|
5
|
+
## Table-Driven Tests
|
|
6
|
+
|
|
7
|
+
The standard Go pattern for testing multiple cases with shared setup.
|
|
8
|
+
|
|
9
|
+
```go
|
|
10
|
+
func TestParseStatus(t *testing.T) {
|
|
11
|
+
tests := []struct {
|
|
12
|
+
name string
|
|
13
|
+
input string
|
|
14
|
+
want Status
|
|
15
|
+
wantErr error
|
|
16
|
+
}{
|
|
17
|
+
{
|
|
18
|
+
name: "valid active",
|
|
19
|
+
input: "active",
|
|
20
|
+
want: StatusActive,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "valid inactive",
|
|
24
|
+
input: "inactive",
|
|
25
|
+
want: StatusInactive,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "empty string",
|
|
29
|
+
input: "",
|
|
30
|
+
wantErr: ErrInvalidStatus,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "unknown value",
|
|
34
|
+
input: "deleted",
|
|
35
|
+
wantErr: ErrInvalidStatus,
|
|
36
|
+
},
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
for _, tt := range tests {
|
|
40
|
+
t.Run(tt.name, func(t *testing.T) {
|
|
41
|
+
got, err := ParseStatus(tt.input)
|
|
42
|
+
|
|
43
|
+
if tt.wantErr != nil {
|
|
44
|
+
if !errors.Is(err, tt.wantErr) {
|
|
45
|
+
t.Errorf("ParseStatus(%q) error = %v, wantErr = %v", tt.input, err, tt.wantErr)
|
|
46
|
+
}
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if err != nil {
|
|
51
|
+
t.Fatalf("ParseStatus(%q) unexpected error: %v", tt.input, err)
|
|
52
|
+
}
|
|
53
|
+
if got != tt.want {
|
|
54
|
+
t.Errorf("ParseStatus(%q) = %v, want %v", tt.input, got, tt.want)
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Subtests
|
|
62
|
+
|
|
63
|
+
Group related tests and provide isolation. Each subtest can be run independently.
|
|
64
|
+
|
|
65
|
+
```go
|
|
66
|
+
func TestUserService(t *testing.T) {
|
|
67
|
+
svc := setupTestService(t)
|
|
68
|
+
|
|
69
|
+
t.Run("Create", func(t *testing.T) {
|
|
70
|
+
t.Run("valid user", func(t *testing.T) {
|
|
71
|
+
user, err := svc.Create(ctx, validUser)
|
|
72
|
+
require.NoError(t, err)
|
|
73
|
+
assert.NotZero(t, user.ID)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
t.Run("duplicate email", func(t *testing.T) {
|
|
77
|
+
_, _ = svc.Create(ctx, validUser)
|
|
78
|
+
_, err := svc.Create(ctx, validUser)
|
|
79
|
+
assert.ErrorIs(t, err, domain.ErrAlreadyExists)
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
t.Run("FindByID", func(t *testing.T) {
|
|
84
|
+
t.Run("existing user", func(t *testing.T) {
|
|
85
|
+
created, _ := svc.Create(ctx, validUser)
|
|
86
|
+
found, err := svc.FindByID(ctx, created.ID)
|
|
87
|
+
require.NoError(t, err)
|
|
88
|
+
assert.Equal(t, created.ID, found.ID)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
t.Run("non-existent user", func(t *testing.T) {
|
|
92
|
+
_, err := svc.FindByID(ctx, 99999)
|
|
93
|
+
assert.ErrorIs(t, err, domain.ErrNotFound)
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Run specific subtest:
|
|
99
|
+
// go test -run TestUserService/Create/valid_user
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## t.Parallel
|
|
103
|
+
|
|
104
|
+
Marks a subtest for parallel execution. Critical rule: **don't share mutable state between parallel tests.**
|
|
105
|
+
|
|
106
|
+
```go
|
|
107
|
+
func TestProcess(t *testing.T) {
|
|
108
|
+
tests := []struct {
|
|
109
|
+
name string
|
|
110
|
+
input string
|
|
111
|
+
want string
|
|
112
|
+
}{
|
|
113
|
+
{"lowercase", "hello", "HELLO"},
|
|
114
|
+
{"uppercase", "WORLD", "WORLD"},
|
|
115
|
+
{"mixed", "GoLang", "GOLANG"},
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
for _, tt := range tests {
|
|
119
|
+
t.Run(tt.name, func(t *testing.T) {
|
|
120
|
+
t.Parallel() // runs concurrently with other parallel subtests
|
|
121
|
+
|
|
122
|
+
got := Process(tt.input)
|
|
123
|
+
if got != tt.want {
|
|
124
|
+
t.Errorf("Process(%q) = %q, want %q", tt.input, got, tt.want)
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Parallel test rules:**
|
|
132
|
+
- Never access shared mutable state (test fixtures, external resources)
|
|
133
|
+
- Each parallel test should be fully independent
|
|
134
|
+
- The parent test waits for all parallel children before returning
|
|
135
|
+
- Use `t.Cleanup` for per-test teardown
|
|
136
|
+
|
|
137
|
+
## Fuzzing (Go 1.18+)
|
|
138
|
+
|
|
139
|
+
Automatically generate inputs to find edge cases and panics.
|
|
140
|
+
|
|
141
|
+
```go
|
|
142
|
+
func FuzzParseJSON(f *testing.F) {
|
|
143
|
+
// Seed corpus — known-good inputs
|
|
144
|
+
f.Add([]byte(`{"name":"alice","age":30}`))
|
|
145
|
+
f.Add([]byte(`{}`))
|
|
146
|
+
f.Add([]byte(`null`))
|
|
147
|
+
f.Add([]byte(`[]`))
|
|
148
|
+
|
|
149
|
+
f.Fuzz(func(t *testing.T, data []byte) {
|
|
150
|
+
var user User
|
|
151
|
+
err := json.Unmarshal(data, &user)
|
|
152
|
+
if err != nil {
|
|
153
|
+
return // invalid JSON is expected
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Re-marshal and verify roundtrip
|
|
157
|
+
encoded, err := json.Marshal(user)
|
|
158
|
+
if err != nil {
|
|
159
|
+
t.Fatalf("Marshal after successful Unmarshal failed: %v", err)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
var user2 User
|
|
163
|
+
if err := json.Unmarshal(encoded, &user2); err != nil {
|
|
164
|
+
t.Fatalf("Roundtrip failed: %v", err)
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Run: go test -fuzz=FuzzParseJSON -fuzztime=30s
|
|
170
|
+
// Corpus stored in: testdata/fuzz/FuzzParseJSON/
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## goleak Integration
|
|
174
|
+
|
|
175
|
+
Detect goroutine leaks in tests using go.uber.org/goleak.
|
|
176
|
+
|
|
177
|
+
```go
|
|
178
|
+
// Option 1: Package-level — catches leaks from any test
|
|
179
|
+
func TestMain(m *testing.M) {
|
|
180
|
+
goleak.VerifyTestMain(m)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Option 2: Per-test — granular control
|
|
184
|
+
func TestWorker(t *testing.T) {
|
|
185
|
+
defer goleak.VerifyNone(t)
|
|
186
|
+
|
|
187
|
+
w := NewWorker()
|
|
188
|
+
w.Start()
|
|
189
|
+
w.Stop() // must stop cleanly, no leaked goroutines
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## synctest (Go 1.24 experimental / Go 1.25+ stable)
|
|
194
|
+
|
|
195
|
+
Deterministic goroutine scheduling for testing concurrent code. Eliminates flaky timing-dependent tests.
|
|
196
|
+
|
|
197
|
+
Use synctest.Test in Go 1.25+; synctest.Run was the Go 1.24 experimental API (behind GOEXPERIMENT=synctest).
|
|
198
|
+
|
|
199
|
+
```go
|
|
200
|
+
import "testing/synctest"
|
|
201
|
+
|
|
202
|
+
func TestDebouncer(t *testing.T) {
|
|
203
|
+
synctest.Test(t, func(t *testing.T) {
|
|
204
|
+
var count atomic.Int32
|
|
205
|
+
debounce := NewDebouncer(100*time.Millisecond, func() {
|
|
206
|
+
count.Add(1)
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
debounce.Trigger()
|
|
210
|
+
debounce.Trigger()
|
|
211
|
+
debounce.Trigger()
|
|
212
|
+
|
|
213
|
+
// Advance virtual time — no real sleeping
|
|
214
|
+
synctest.Wait() // wait for all goroutines to block
|
|
215
|
+
time.Sleep(100 * time.Millisecond) // virtual sleep, instant in real time
|
|
216
|
+
|
|
217
|
+
synctest.Wait()
|
|
218
|
+
if got := count.Load(); got != 1 {
|
|
219
|
+
t.Errorf("expected 1 call, got %d", got)
|
|
220
|
+
}
|
|
221
|
+
})
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## httptest
|
|
226
|
+
|
|
227
|
+
### Unit Tests — ResponseRecorder
|
|
228
|
+
|
|
229
|
+
```go
|
|
230
|
+
func TestHealthHandler(t *testing.T) {
|
|
231
|
+
req := httptest.NewRequest("GET", "/health", nil)
|
|
232
|
+
w := httptest.NewRecorder()
|
|
233
|
+
|
|
234
|
+
HealthHandler(w, req)
|
|
235
|
+
|
|
236
|
+
resp := w.Result()
|
|
237
|
+
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
238
|
+
|
|
239
|
+
body, _ := io.ReadAll(resp.Body)
|
|
240
|
+
assert.JSONEq(t, `{"status":"ok"}`, string(body))
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Integration Tests — Test Server
|
|
245
|
+
|
|
246
|
+
```go
|
|
247
|
+
func TestAPIIntegration(t *testing.T) {
|
|
248
|
+
handler := setupRouter() // your actual router
|
|
249
|
+
srv := httptest.NewServer(handler)
|
|
250
|
+
defer srv.Close()
|
|
251
|
+
|
|
252
|
+
client := &http.Client{Timeout: 5 * time.Second}
|
|
253
|
+
|
|
254
|
+
resp, err := client.Get(srv.URL + "/api/users")
|
|
255
|
+
require.NoError(t, err)
|
|
256
|
+
defer resp.Body.Close()
|
|
257
|
+
|
|
258
|
+
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
259
|
+
|
|
260
|
+
var users []User
|
|
261
|
+
require.NoError(t, json.NewDecoder(resp.Body).Decode(&users))
|
|
262
|
+
assert.NotEmpty(t, users)
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Build Tags
|
|
267
|
+
|
|
268
|
+
Separate slow integration tests from fast unit tests.
|
|
269
|
+
|
|
270
|
+
```go
|
|
271
|
+
//go:build integration
|
|
272
|
+
|
|
273
|
+
package user_test
|
|
274
|
+
|
|
275
|
+
import (
|
|
276
|
+
"testing"
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
func TestDatabaseIntegration(t *testing.T) {
|
|
280
|
+
pool := setupTestDB(t)
|
|
281
|
+
defer pool.Close()
|
|
282
|
+
// ...
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
# Canonical local/CI invocation — race detector + test-order shuffle
|
|
288
|
+
go test -race -shuffle=on ./...
|
|
289
|
+
|
|
290
|
+
# Run only unit tests (default, no tags)
|
|
291
|
+
go test ./...
|
|
292
|
+
|
|
293
|
+
# Run integration tests
|
|
294
|
+
go test -tags=integration ./...
|
|
295
|
+
|
|
296
|
+
# Run all tests
|
|
297
|
+
go test -tags=integration ./...
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
`go test -race -shuffle=on ./...` is the canonical local/CI invocation: `-race` surfaces data races and `-shuffle=on` surfaces hidden inter-test ordering dependencies. Reserve `-race` for correctness/CI runs, not every incremental save — it costs a 2–3× slowdown.
|
|
301
|
+
|
|
302
|
+
## testcontainers
|
|
303
|
+
|
|
304
|
+
Docker-based dependencies for integration tests.
|
|
305
|
+
|
|
306
|
+
```go
|
|
307
|
+
//go:build integration
|
|
308
|
+
|
|
309
|
+
func setupPostgres(t *testing.T) *pgxpool.Pool {
|
|
310
|
+
t.Helper()
|
|
311
|
+
|
|
312
|
+
ctx := context.Background()
|
|
313
|
+
container, err := postgres.Run(ctx,
|
|
314
|
+
"postgres:16-alpine",
|
|
315
|
+
postgres.WithDatabase("testdb"),
|
|
316
|
+
postgres.WithUsername("test"),
|
|
317
|
+
postgres.WithPassword("test"),
|
|
318
|
+
testcontainers.WithWaitStrategy(
|
|
319
|
+
wait.ForLog("database system is ready to accept connections").
|
|
320
|
+
WithOccurrence(2).
|
|
321
|
+
WithStartupTimeout(30*time.Second),
|
|
322
|
+
),
|
|
323
|
+
)
|
|
324
|
+
require.NoError(t, err)
|
|
325
|
+
|
|
326
|
+
t.Cleanup(func() {
|
|
327
|
+
require.NoError(t, container.Terminate(ctx))
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
connStr, err := container.ConnectionString(ctx, "sslmode=disable")
|
|
331
|
+
require.NoError(t, err)
|
|
332
|
+
|
|
333
|
+
pool, err := pgxpool.New(ctx, connStr)
|
|
334
|
+
require.NoError(t, err)
|
|
335
|
+
|
|
336
|
+
t.Cleanup(func() { pool.Close() })
|
|
337
|
+
|
|
338
|
+
// Run migrations
|
|
339
|
+
runMigrations(t, connStr)
|
|
340
|
+
|
|
341
|
+
return pool
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## Golden Files
|
|
346
|
+
|
|
347
|
+
Compare output against known-good "golden" files. Update with `-update` flag.
|
|
348
|
+
|
|
349
|
+
```go
|
|
350
|
+
var update = flag.Bool("update", false, "update golden files")
|
|
351
|
+
|
|
352
|
+
func TestRender(t *testing.T) {
|
|
353
|
+
tests := []struct {
|
|
354
|
+
name string
|
|
355
|
+
input Input
|
|
356
|
+
golden string
|
|
357
|
+
}{
|
|
358
|
+
{"basic", basicInput, "testdata/basic.golden"},
|
|
359
|
+
{"complex", complexInput, "testdata/complex.golden"},
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
for _, tt := range tests {
|
|
363
|
+
t.Run(tt.name, func(t *testing.T) {
|
|
364
|
+
got := Render(tt.input)
|
|
365
|
+
|
|
366
|
+
if *update {
|
|
367
|
+
os.WriteFile(tt.golden, []byte(got), 0644)
|
|
368
|
+
return
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
want, err := os.ReadFile(tt.golden)
|
|
372
|
+
require.NoError(t, err)
|
|
373
|
+
|
|
374
|
+
if diff := cmp.Diff(string(want), got); diff != "" {
|
|
375
|
+
t.Errorf("Render mismatch (-want +got):\n%s", diff)
|
|
376
|
+
}
|
|
377
|
+
})
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Update golden files: go test -run TestRender -update
|
|
382
|
+
// Verify: go test -run TestRender
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## Coverage-Adaptive Refactoring Safety Net
|
|
386
|
+
|
|
387
|
+
Before you refactor (see `refactoring-mechanics.md`), measure the test coverage
|
|
388
|
+
of the *exact code you are about to move* and let that number set your caution.
|
|
389
|
+
Coverage is a floor for safety, not a target — the point is to know whether a
|
|
390
|
+
transform is guarded before you make it.
|
|
391
|
+
|
|
392
|
+
**Diagnostic — measure the blast radius's own coverage:**
|
|
393
|
+
|
|
394
|
+
```bash
|
|
395
|
+
go test -covermode=atomic -coverpkg=./... -coverprofile=cover.out ./...
|
|
396
|
+
go tool cover -func=cover.out # per-function %, find the code you'll touch
|
|
397
|
+
go tool cover -html=cover.out # line-level view of what's exercised
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Read the **per-function** column, not the package total — a package at 75% can
|
|
401
|
+
hide a 0%-covered function you are about to rewrite.
|
|
402
|
+
|
|
403
|
+
**Tier your transforms by that function's coverage:**
|
|
404
|
+
|
|
405
|
+
| Coverage of the target | Posture | Allowed transforms |
|
|
406
|
+
|-----------------------|---------|--------------------|
|
|
407
|
+
| **≥ 80%** | Guarded | Aggressive transforms OK — any ladder rung, including hand-written `dst` surgery. Tests will catch a regression. |
|
|
408
|
+
| **40–80%** | Harden first | Add tests over the untested branches, *then* transform. Prefer construction-guaranteed rungs (`gofmt -r`, `eg`, gopls, `//go:fix`). |
|
|
409
|
+
| **< 40%** | Feathers mode | Write characterization tests and install seams *before any transform*; restrict to construction-guaranteed tools only. No freehand edits. |
|
|
410
|
+
|
|
411
|
+
### Characterization tests (distinct from Golden Files)
|
|
412
|
+
|
|
413
|
+
A **characterization test** pins the code's *current* behavior — bugs and all —
|
|
414
|
+
so a refactor can prove it changed nothing. You are not asserting what the code
|
|
415
|
+
*should* do; you are recording what it *does* today, so any drift fails loudly.
|
|
416
|
+
Feed representative inputs, run the code, and assert on whatever it returns
|
|
417
|
+
right now (even if that value is wrong — a `// KNOWN BUG: preserved` comment
|
|
418
|
+
belongs there, and the fix is a *separate, behavioral* commit).
|
|
419
|
+
|
|
420
|
+
This is a different intent from the **Golden Files** section above. Golden files
|
|
421
|
+
are one *implementation technique* — a good way to store a large characterization
|
|
422
|
+
expectation on disk — but characterization is the *purpose*: locking behavior
|
|
423
|
+
before a structural change. A `cmp.Diff` against an inline `want` is equally a
|
|
424
|
+
characterization test when its job is to pin legacy behavior.
|
|
425
|
+
|
|
426
|
+
### Object seams for untested code
|
|
427
|
+
|
|
428
|
+
Legacy code is often untestable because it reaches out to a concrete dependency
|
|
429
|
+
(a `*sql.DB`, a clock, an HTTP client) it constructs itself. Introduce an
|
|
430
|
+
**object seam**: extract the *smallest* interface the code actually uses, at the
|
|
431
|
+
*consumer* side, and inject it — now the untested unit is exercisable with a
|
|
432
|
+
fake.
|
|
433
|
+
|
|
434
|
+
```go
|
|
435
|
+
// Seam: the consumer declares only what it needs (design-patterns.md §5).
|
|
436
|
+
type rowQuerier interface {
|
|
437
|
+
QueryContext(ctx context.Context, q string, args ...any) (*sql.Rows, error)
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
func loadUsers(ctx context.Context, db rowQuerier) ([]User, error) { /* ... */ }
|
|
441
|
+
// Prod passes *sql.DB; the characterization test passes a fake rowQuerier.
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
The seam is itself a refactor — introduce it *before* the transform you actually
|
|
445
|
+
want, in its own commit, guarded by the characterization tests it enables.
|
|
446
|
+
|
|
447
|
+
### Caveats
|
|
448
|
+
|
|
449
|
+
- **Statement coverage ≠ branch coverage.** `go test` reports statements
|
|
450
|
+
executed, not branch/condition combinations. An 85% function can still have an
|
|
451
|
+
untested error path — read `-html` output, don't trust the number alone.
|
|
452
|
+
- **`go test ./...` silently omits packages with no `_test.go` file.** They do
|
|
453
|
+
not appear as 0% — they simply vanish from the report. Only `-coverpkg=./...`
|
|
454
|
+
forces every package into the profile, revealing the truly-zero ones.
|
|
455
|
+
- **Run `deadcode -test ./...` first.** Do not spend characterization effort on
|
|
456
|
+
code that nothing reaches; prune it (see `refactoring-mechanics.md`) instead.
|
|
457
|
+
|
|
458
|
+
## Test Helpers
|
|
459
|
+
|
|
460
|
+
```go
|
|
461
|
+
// t.Helper marks function as test helper — errors report caller's line
|
|
462
|
+
func createTestUser(t *testing.T, svc *UserService) *User {
|
|
463
|
+
t.Helper()
|
|
464
|
+
user, err := svc.Create(context.Background(), &User{
|
|
465
|
+
Name: "test-" + t.Name(),
|
|
466
|
+
Email: fmt.Sprintf("test-%s@example.com", t.Name()),
|
|
467
|
+
})
|
|
468
|
+
require.NoError(t, err)
|
|
469
|
+
|
|
470
|
+
t.Cleanup(func() {
|
|
471
|
+
svc.Delete(context.Background(), user.ID)
|
|
472
|
+
})
|
|
473
|
+
|
|
474
|
+
return user
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
## When to Use
|
|
479
|
+
|
|
480
|
+
Apply when generating or reviewing tests. Flag violations as:
|
|
481
|
+
- **CRITICAL**: No error path testing, shared mutable state in parallel tests, missing `rows.Close()` in test
|
|
482
|
+
- **WARNING**: Missing subtests for grouped scenarios, no fuzz tests for parsers, integration tests without build tags
|
|
483
|
+
- **SUGGESTION**: Could use table-driven pattern, goleak for goroutine tests, testcontainers for DB tests
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Runtime Troubleshooting (live triage)
|
|
2
|
+
|
|
3
|
+
> Reference document for go-reviewer. Loaded on demand via Read tool.
|
|
4
|
+
> Upstream: go.dev/doc/diagnostics · github.com/go-delve/delve
|
|
5
|
+
|
|
6
|
+
Something is broken at runtime — a hang, a leak, a flake, a panic. This is the triage path: match the symptom to the right tool, and capture evidence *before* you touch anything. For pprof capture and analysis depth — reading a CPU profile, `alloc_objects` hot allocators, benchstat, GOGC/GOMEMLIMIT tuning — see `references/performance-profiling.md`. This document does not re-teach that; it covers the live-triage moves that reference lacks.
|
|
7
|
+
|
|
8
|
+
## Symptom → first move
|
|
9
|
+
|
|
10
|
+
| Symptom | First move |
|
|
11
|
+
|---------|-----------|
|
|
12
|
+
| Hang / deadlock | Goroutine dump (`?debug=2`) — read what every goroutine is blocked on |
|
|
13
|
+
| Memory leak (growing RSS) | Heap profile sampled over time; diff two captures (analysis → performance-profiling.md) |
|
|
14
|
+
| Goroutine leak | `runtime.NumGoroutine()` trend + two goroutine dumps, diff the stacks |
|
|
15
|
+
| High CPU | CPU profile → `references/performance-profiling.md` |
|
|
16
|
+
| Flaky test | `go test -race -count=100` |
|
|
17
|
+
| Slow / wrong HTTP | `httputil.DumpRequestOut` + `net/http/httptrace` |
|
|
18
|
+
| Crash / panic | Read the stack top-down; reproduce under Delve |
|
|
19
|
+
| GC pressure / long pauses | `GODEBUG=gctrace=1` |
|
|
20
|
+
|
|
21
|
+
Pick the row, run the move, then read the output slowly. The evidence tells you where to look; it rarely tells you the fix outright.
|
|
22
|
+
|
|
23
|
+
## Golden Rules (debugging discipline)
|
|
24
|
+
|
|
25
|
+
Work this list top to bottom. Each rule is a defense against a specific way of wasting an afternoon.
|
|
26
|
+
|
|
27
|
+
- [ ] **Reproduce before you fix.** No repro means you are guessing. A failing test that triggers the bug on demand is worth an hour of staring at code.
|
|
28
|
+
- [ ] **Change ONE variable at a time.** Two edits at once and a green result tells you nothing about which one mattered.
|
|
29
|
+
- [ ] **Read the actual error text.** The whole line, the whole stack — not the paraphrase in your head.
|
|
30
|
+
- [ ] **Bisect the search space.** Halve it every step: `git bisect`, comment out half, binary-search the input that triggers it.
|
|
31
|
+
- [ ] **Keep a log of what you ruled out.** Otherwise you re-test the same dead theory an hour later.
|
|
32
|
+
- [ ] **The bug is in YOUR code until proven otherwise.** The runtime and the stdlib are almost never the culprit.
|
|
33
|
+
- [ ] **When stuck, explain it out loud.** Rubber-duck the flow line by line; the gap usually surfaces mid-sentence.
|
|
34
|
+
|
|
35
|
+
## Red Flags (you are flailing — stop)
|
|
36
|
+
|
|
37
|
+
- [ ] Re-running the same command hoping for a different result.
|
|
38
|
+
- [ ] Adding `time.Sleep` to "fix" a race — you moved the window, you did not close it.
|
|
39
|
+
- [ ] Shotgun-editing several suspects at once.
|
|
40
|
+
- [ ] Blaming the runtime, scheduler, or stdlib first.
|
|
41
|
+
- [ ] Calling it "fixed" without knowing why it broke.
|
|
42
|
+
- [ ] Deleting or skipping a test to make CI green.
|
|
43
|
+
|
|
44
|
+
Hit two of these in a row → stop, back up, and reproduce cleanly before touching more code.
|
|
45
|
+
|
|
46
|
+
## Runtime techniques
|
|
47
|
+
|
|
48
|
+
### Delve (interactive debugging)
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
dlv debug ./cmd/app # build + launch under the debugger
|
|
52
|
+
dlv attach <pid> # attach to an already-running process
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
At the prompt: `break main.handleReq` (or `break file.go:42`), `continue` to reach it, `print myVar` to inspect state, `goroutines` / `stack` to see the wider picture. The loop is: set the breakpoint, `continue` to it, `print` the state, step. Use `attach` when a process is already wedged in staging and you want to look without restarting it.
|
|
56
|
+
|
|
57
|
+
### GODEBUG traces (no code change, no rebuild)
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
GODEBUG=schedtrace=1000 ./app # scheduler snapshot every 1000ms
|
|
61
|
+
GODEBUG=gctrace=1 ./app # one line per GC cycle
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Read a `schedtrace` line — `SCHED 1000ms: gomaxprocs=8 idleprocs=0 runqueue=42 ...`: `idleprocs=0` alongside a large `runqueue` means the program is CPU-bound and goroutines are starving for a thread. Read a `gctrace` line — `gc 12 @4.5s 3%: 0.1+5.2+0.05 ms clock ... 45->48->24 MB`: the `45->48->24 MB` is heap-before → peak → heap-after, and `3%` is cumulative GC CPU. A steadily rising post-GC number (the last figure) across cycles is a real leak, not churn.
|
|
65
|
+
|
|
66
|
+
### Goroutine dump for hangs
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
curl localhost:6060/debug/pprof/goroutine?debug=2 # full stacks, human-readable
|
|
70
|
+
kill -QUIT <pid> # no pprof endpoint? dumps all stacks to stderr
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Read the blocked-on state at the top of each goroutine (`chan receive`, `sync.Mutex.Lock`, `select`, `IO wait`) and the wait duration in the header. The tell for a deadlock: a mutex or channel that *every* blocked goroutine is waiting on — trace back to whoever holds it and never releases.
|
|
74
|
+
|
|
75
|
+
### Safe production pprof
|
|
76
|
+
|
|
77
|
+
The `/debug/pprof` endpoint leaks memory contents and full stacks — treat it as privileged. Never bind it to a public interface: put it behind auth, or expose it only on `localhost` / a private admin interface. And **capture before you restart** — a restart destroys the evidence you need. Pull the goroutine dump and a heap profile *first*, then recycle the process.
|
|
78
|
+
|
|
79
|
+
### Flaky tests
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
go test -race -count=100 -run TestFlaky ./pkg/
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`-count=100` defeats the test cache and forces real re-runs, exposing ordering and shared-state flakes; `-race` surfaces the data race underneath most of them. Green at `-count=1` but red at `-count=100` means the test leaks state between runs, or the code under test has a race.
|
|
86
|
+
|
|
87
|
+
### HTTP triage
|
|
88
|
+
|
|
89
|
+
```go
|
|
90
|
+
b, _ := httputil.DumpRequestOut(req, true) // exact wire bytes, client side
|
|
91
|
+
b, _ := httputil.DumpResponse(resp, true) // exact wire bytes of the response
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
When the request "looks right" but the server disagrees, dump the actual bytes — header casing, content encoding, a stray trailing `/`, a missing `Content-Type`. Pair with `net/http/httptrace` to time DNS, connection reuse, and TLS. **Strip `Authorization`, `Cookie`, and any token headers before pasting a dump into an issue or chat.**
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
Analysis depth (reading profiles, allocation hunting, GC tuning) lives in `references/performance-profiling.md`. For the underlying concurrency bugs a dump exposes — leaks, deadlocks, unclosed channels — the concurrency checklist in `go-concurrency-reviewer.md` is the catalog; this document is only the triage path to them.
|