bootstrap rules for go-error-wrapping-guide.md (5 rules) - #2
Conversation
There was a problem hiding this comment.
PR Review Summary
Branch:feat/bootstrap-error-wrapping → master
Files changed: 6 (3 YAML rules, 1 doc with 5 RULE blocks, 1 index, 1 prompt artifact)
Automated Checks
| Check | Result |
|---|---|
| LICENSE present | ✅ LICENSE file exists |
rules/index.json JSON valid | ✅ Valid JSON (verified via Python) |
.claude-plugin/plugin.json JSON valid | ✅ Valid JSON |
.claude-plugin/marketplace.json JSON valid | ✅ Valid JSON |
make precommit | ⛔ Blocked by sandbox (could not run Makefile) |
Review Findings
Must Fix (Critical)
None identified. The mechanical YAML rules are correctly structured, the inside/has ast-grep composition in no-bare-return-err.yml is valid, and the $$$ARGS variadic capture in no-fmt-errorf.yml follows ast-grep conventions.
Should Fix (Important)
Version mismatch between manifest and changelog —
CHANGELOG.mdshows latest version asv0.11.0, but bothplugin.jsonandmarketplace.jsonhave"version": "0.9.12". These MUST agree before release per the version alignment rule in CLAUDE.md. This PR does not itself change version strings, but this existing drift should be resolved separately.No smoke tests for the three mechanical ast-grep YAMLs —
rules/go/no-bare-return-err.yml,rules/go/no-context-background-in-business-logic.yml, andrules/go/no-fmt-errorf.ymlhave no test coverage. The plan's concern correctly notes this: the judgment rules (4–5) are intentionally YAML-free, but the three mechanical detectors should at minimum be smoke-tested against known Bad/Good patterns (e.g., a minimal Go file exercising each pattern) to confirm they fire as expected. Consider adding ascripts/smoke-test-rules.shthat compiles a temporary Go file and runs ast-grep scan against it.
Nice to Have (Optional)
prompts/completed/artifact committed to repo —prompts/completed/007-bootstrap-rules-go-error-wrapping.mdis a dark-factory execution artifact. Whether to commit these is project-specific; if theprompts/directory is meant to be a clean inbox/outbox, consider whether completed prompts should live elsewhere or be excluded from the repo entirely.$$$ARGSinno-fmt-errorf.ymlcould be documented — The$$$ARGSvariadic capture is correct for ast-grep but may be unfamiliar to future maintainers. A brief comment in the YAML or a note indocs/ast-grep-rule-writing-guide.mdwould reduce future confusion.
Verdict
{
"verdict": "request-changes",
"summary": "The five new RULE blocks and three ast-grep YAMLs are structurally correct and follow all project conventions. However, version drift between CHANGELOG.md (v0.11.0) and the plugin manifests (0.9.12) is a release-blocking inconsistency that must be resolved, and the three mechanical rule YAMLs lack smoke tests to confirm they fire on real code patterns.",
"comments": [
{
"file": "CHANGELOG.md",
"line": 11,
"severity": "major",
"message": "Version mismatch: CHANGELOG.md top entry is v0.11.0 but .claude-plugin/plugin.json and .claude-plugin/marketplace.json both show version 0.9.12. These four version strings must agree before release per CLAUDE.md version alignment rule."
},
{
"file": ".claude-plugin/plugin.json",
"line": 4,
"severity": "major",
"message": "Version mismatch: plugin.json version is 0.9.12 but CHANGELOG.md top entry is v0.11.0. Must match CHANGELOG.md."
},
{
"file": ".claude-plugin/marketplace.json",
"line": 8,
"severity": "major",
"message": "Version mismatch: marketplace.json metadata.version is 0.9.12 but CHANGELOG.md top entry is v0.11.0. Must match CHANGELOG.md."
},
{
"file": ".claude-plugin/marketplace.json",
"line": 15,
"severity": "major",
"message": "Version mismatch: marketplace.json plugins[0].version is 0.9.12 but CHANGELOG.md top entry is v0.11.0. Must match CHANGELOG.md."
},
{
"file": "rules/go/no-bare-return-err.yml",
"line": 1,
"severity": "nit",
"message": "No smoke test for this mechanical ast-grep rule. Add a smoke test (e.g., scripts/smoke-test-rules.sh) to confirm the detector fires on a synthetic `if err != nil { return err }` and does NOT fire on `if err != nil { return errors.Wrapf(ctx, err, \"...\") }`."
},
{
"file": "rules/go/no-context-background-in-business-logic.yml",
"line": 1,
"severity": "nit",
"message": "No smoke test for this mechanical ast-grep rule. Add a smoke test to confirm the detector fires on `context.Background()` in a non-exempt path and does NOT fire in main.go or cmd/**."
},
{
"file": "rules/go/no-fmt-errorf.yml",
"line": 1,
"severity": "nit",
"message": "No smoke test for this mechanical ast-grep rule. Add a smoke test to confirm the $$$ARGS variadic capture correctly matches fmt.Errorf calls and does NOT fire on errors.Wrapf."
}
],
"concerns_addressed": [
"correctness: ast-grep `inside: { kind: if_statement, has: { pattern: err != nil } }` — reviewed the YAML, the composition is valid ast-grep; multi-statement if bodies where `return err` appears inside a closure nested within the if block would be a judgment-tier false positive handled by the go-error-assistant, not a mechanical rule bug.",
"correctness: enforcement field backtick-wrapped paths — confirmed this is the output format of build-index.py and matches the pilot entry; not a bug.",
"correctness: fmt.Errorf $$$ARGS variadic capture — valid ast-grep syntax; $$$ARGS captures variadic args correctly.",
"tests: no smoke coverage for mechanical YAMLs — raised as Should Fix; confirmed by review."
]
}bborbe convention is jobs.test (verified across dark-factory, vault-cli, scripts, semantic-search). coding diverged with jobs.precommit (name: Precommit), which left the master-protection ruleset's required 'test' check permanently MISSING — PRs stayed BLOCKED even after bot APPROVE. Renaming aligns coding with the org standard and unblocks PR merge through the gate.
CHANGELOG.md top entry is v0.11.0 but plugin.json and marketplace.json were both stuck at 0.9.12. maintainer-agent-releaser bumped the CHANGELOG for v0.10.0 and v0.11.0 but did not touch the manifests. make release-check fails on this drift; flagged by the pr-reviewer-agent on PR #2. Aligning all four version strings to 0.11.0 (matches CHANGELOG). This is NOT a new release commit — purely a drift fix. The next genuine release will bump from 0.11.0 to whatever's next.
superseded by new automated review
There was a problem hiding this comment.
{
"verdict": "approve",
"summary": "Bootstrap of 5 RULE blocks (3 mechanical ast-grep + 2 judgment) for go-error-wrapping-guide.md with matching index entries. All YAML files are structurally valid, index entries are correctly sorted with matching anchors/IDs, CI job rename is consistent with recent commits, and rule-block formatting matches the pilot. One known limitation: the fmt.Errorf ast-grep pattern catches both %w-wrapped and standalone forms — the doc permits standalone fmt.Errorf as 'new error without cause' per its examples, so false positives at the mechanical layer are expected and will be adjudicated at the judgment tier (as noted in the PR concerns).",
"comments": [
{
"file": "rules/go/no-fmt-errorf.yml",
"line": 9,
"severity": "major",
"message": "Pattern `fmt.Errorf($$$ARGS)` fires on both fmt.Errorf with %w-wrapped err AND standalone fmt.Errorf(\"message only\") without err. The doc's 'Fix: New Error Without Cause' section explicitly allows standalone fmt.Errorf as an acceptable alternative to errors.Errorf. The rule cannot distinguish between these without whole-function analysis, so false positives are expected at the mechanical layer — judgment tier must filter them. This is acknowledged in the PR concerns and is acceptable behavior given the ast-grep limitation."
},
{
"file": "rules/index.json",
"line": 24,
"severity": "nit",
"message": "enforcement field for mechanical rules uses backtick-wrapped paths (`rules/go/no-bare-return-err.yml`) consistent with existing go-time entries, but the pilot entry go-context/cancel-check-in-loop uses a longer natural-language enforcement string. This is a cosmetic formatting inconsistency across entries, not a functional defect — the field is valid YAML in both forms."
}
],
"concerns_addressed": [
"correctness: no-fmt-errorf ast-grep pattern confirmed to fire on both wrapped and standalone forms — judgment tier required to filter, acceptable per PR concerns",
"correctness: no-bare-return-err pattern correctly targets bare return inside if err!=nil, does not fire on multi-return idioms like return result, err",
"correctness: no-context-background-in-business-logic rule correctly distinguishes business logic from cmd/bootstrap code via path ignores",
"correctness: index.json verified: 9 entries, sorted, anchors match IDs, owner go-error-assistant on all new entries, doc_path consistent",
"tests: ast-grep rules lack unit test YAMLs — acknowledged limitation per PR concerns, no test suite exists in this plugin-only repo per CLAUDE.md",
"tests: index.json changes not validated against a schema — build-index determinism relies on human review and make precommit (JSON validity only)"
]
}Uh oh!
There was an error while loading. Please reload this page.
Restructures the 6 MUST/SHOULD sections in docs/go-prometheus-metrics-guide.md into canonical `### RULE` blocks consumable by the rule-base walker (scripts/build-index.py). Mirrors the bootstrap template proven across PRs #2-5 (errors, security, factory, http-handler). Rules added to rules/index.json (21 → 27 entries): - go-prometheus/counter-pre-initialization (MUST, judgment) Pre-init counters with .Add(0) for known label combos so rate() doesn't silently skip absent series. - go-prometheus/composed-metrics-interface (SHOULD, judgment) Split fat Metrics interfaces into focused sub-interfaces (ISP). - go-prometheus/no-gauge-for-monotonic (MUST, judgment) Never use GaugeVec for values that only increase — breaks rate() and increase() queries. - go-prometheus/counter-total-suffix (MUST, judgment for now) Counter Name must end with _total. Mechanical ast-grep YAML was drafted but CounterOpts struct-literal traversal in ast-grep 0.43.0 needs more debugging; deferring to a focused follow-up PR rather than blocking this bootstrap. - go-prometheus/help-string-quality (MUST, judgment) Unique, accurate Help strings per metric; reject copy-paste residue. - go-prometheus/label-naming-consistency (MUST, judgment) Same label name for same concept across all metrics in the project. All rule blocks carry: Owner (go-metrics-assistant), Applies when, Enforcement, Why, Bad/Good code snippets. Bad example for no-gauge-for-monotonic also de-trades (candleHandleTotalCounter + broker label → orderHandleTotalCounter + tenant label) — leftover trading-domain leak from PR #6's first trim pass. No personal vault paths, no trading-domain terms, no remaining MUST section without a rule id (verified by grep).
Restructures the 8 MUST sections in docs/go-testing-guide.md into canonical `### RULE` blocks. Same template as PRs #2-5, #8. Rules added (all judgment for this PR; mechanical ast-grep follow-ups tracked separately): - go-testing/no-stdlib-table-tests (MUST) Ginkgo-suite packages must use DescribeTable/Entry, not for/t.Run. - go-testing/no-testing-t-direct (MUST) No bare testing.T in Ginkgo-suite packages — use Describe/It. - go-testing/no-bare-error-call (MUST) Wrap error-returning calls in Gomega matchers (Succeed/HaveOccurred/ MatchError) — errcheck enforces this in precommit. - go-testing/suite-test-file-required (MUST) Every test-containing package needs *_suite_test.go or Ginkgo silently discovers no specs. - go-testing/main-test-with-compiles (MUST) Every binary needs main_test.go with a Compiles It-block backed by gexec.Build. - go-testing/suite-timeout-required (MUST) suiteConfig.Timeout must be set so hung tests fail fast. - go-testing/counterfeiter-mocks-required (MUST) No hand-written mocks — they drift silently. - go-testing/libtime-injection-required (MUST) Cross-references go-time/no-time-now-direct; test-quality scope. rules/index.json: 27 → 42 entries This also picks up 7 agent-cmd/* entries from PR #9 (#9 merged the doc but didn't include the walker output regen — caught locally via make build-index). Net new in this PR: 8 go-testing rules. Pre-emptive checks (lessons from PRs #6, #8): no personal vault paths, no trading-domain terms, no internal contradictions (rule examples don't violate sibling rules).
Restructures the 4 MUST sections in docs/go-licensing-guide.md into canonical `### RULE` blocks. Same template as PRs #2-5, #8, #10. Rules added: - go-licensing/license-file-required (MUST, judgment) Public Go repos MUST have a root LICENSE file. Private/internal repos exempt. Detection requires file-existence check — not ast-grep. - go-licensing/readme-license-section-required (MUST, judgment) Public README must have a ## License H2 section pointing to LICENSE. Markdown structure check — not ast-grep. - go-licensing/source-file-header-required (MUST, addlicense) All non-vendor *.go files need the 3-line BSD-2 header. Enforcement delegates to 'addlicense -check' via make precommit (canonical tool; already wired into the toolchain). - go-licensing/copyright-year-discipline (MUST, judgment) No bulk year-updates for trivial changes; no future/non-numeric years. PR-scope diff inspection — partial ast-grep detection possible for the future-year case but bulk-update trigger needs diff-scope reasoning. rules/index.json: 42 -> 46 Walker drift detected by PR #13's check-index target during first precommit run — regenerated rules/index.json and re-ran precommit clean. New guard working as designed. Pre-emptive checks (lessons from #6, #8): no personal vault paths, no trading-domain terms, no internal contradictions, all cross-refs resolve. License-assistant agent exists at agents/license-assistant.md.
Restructures the godoc style guide with canonical `### RULE` blocks for its enforceable conventions. Mirrors PRs #2-5, #8, #10, #14. Rules added (rules/index.json: 46 -> 50): - go-doc/exported-item-must-have-comment (MUST, judgment) Every exported function/type/const/var needs a doc comment. Mechanical follow-up: revive's 'exported' rule. - go-doc/comment-starts-with-name (MUST, judgment) Doc comment first word must match the identifier name. Mechanical follow-up: revive (or ast-grep via the PR #11 recipe). - go-doc/package-comment-in-doc-go (SHOULD, judgment) Package comment belongs in doc.go to survive refactors of feature files. - go-doc/third-person-no-signature-repeat (SHOULD, judgment) No first-person prose; don't restate the signature. All examples generic (Order, Customer, Discount, Add) — no trading domain. All rule IDs unique against the 46 existing entries. godoc-assistant agent exists at agents/godoc-assistant.md. Pre-emptive checks (lessons from PRs #6, #8, #14): - No personal vault paths - No trading-domain terms - All cross-refs resolve - make build-index regenerated; check-index target passes
Restructures the 6 enforceable conventions in docs/go-architecture-patterns.md into canonical `### RULE` blocks. Mirrors PRs #2-5, #8, #10, #14, #15. Rules added (rules/index.json: 50 -> 56, new go-architecture/* family): - go-architecture/counterfeiter-directive-on-interface (MUST) Every substitutable interface needs a //counterfeiter:generate directive so go generate regenerates the fake when the interface drifts. - go-architecture/new-prefix-constructor-naming (MUST) Constructors start with New (not Create/Make/etc). Partial overlap with go-factory/no-impl-in-factory-pkg for Create*. - go-architecture/constructor-returns-interface (MUST) New* returns the interface, not *concrete struct. Hides implementation, keeps dependency direction one-way. - go-architecture/private-struct-matches-interface (SHOULD) UserService -> userService (first letter lowered). godoc pairs them; IDE outlines pair them; refactors find them with one rename. - go-architecture/no-globals-or-singletons (MUST) Service deps via constructor injection, never package-level vars. Globals break parallel tests, hide the dep graph, make refactors fragile. - go-architecture/business-logic-not-in-main (MUST) main.go is wiring; domain operations live in pkg/. Mixed main.go is untestable and unreachable from other binaries. Cross-references to existing rules (already in index, not duplicated): - go-errors/no-context-background-in-business-logic — covers context discipline - go-context/cancel-check-in-loop — covers infinite-loop ctx.Done() checks - go-time/* family — covers libtime injection All examples generic (User, UserService, Worker, log/db deps). No trading-domain terms (KafkaBrokers grep hit is server infrastructure, not trading-broker terminology — pre-existing in main.go example). No personal vault paths. Pre-emptive checks (lessons from PRs #6, #8, #14, #15): clean grep, unique rule IDs (6 new vs 50 existing), go-architecture-assistant agent exists at agents/go-architecture-assistant.md, make build-index regenerated, check-index passes.
…Error PR #33 bot review caught two real bugs in batch 5's use-error-code-constants YAML + doc: 1. libhttp.NewJSONError doesn't exist. The doc text mis-named NewJSONErrorHandler (a handler factory, different surface entirely). Dropped from YAML regex and doc text. 2. libhttp.WrapWithCode signature is (err, code, statusCode), NOT (err, statusCode, code). Verified against ~/Documents/workspaces/http/http_error-handler.go:65,88. Both the YAML pattern and doc's Bad/Good examples had the wrong arg order — would have caused real violations to be missed silently AND the doc examples would not have compiled. Updated: - rules/go/use-error-code-constants.yml: $CODE binds to arg #2 (not #3); dropped NewJSONError from regex; updated comment block to cite the verified signatures. - docs/go-json-error-handler-guide.md: Applies-when + Enforcement text use correct function names + arg positions; Bad/Good examples show actual libhttp call order. Verified via re-smoked fixture: bad calls with raw "VALIDATION_ERROR" in position #2 fire (both 3-arg WrapWithCode and 4-arg WrapWithDetails); good calls with libhttp.ErrorCodeValidation constant in position #2 are clean. Re bot's index.json drift concern: 'make build-index' regenerates index from the doc's Enforcement field — manual doc edits ARE the source of truth and propagate to the index automatically. Not a process gap.
Summary
Rules added
Scope note: doc's `## Key Rules` lists 7 items; this PR extracts 5. Skipped #4 (multi-return wrapping — snippet variation of rules 1+2) and #6 (remove unused imports — goimports' job).
Test plan