Skip to content

fix: allow gaze crap --analyzer on non-Go projects - #254

Merged
jflowers merged 1 commit into
unbound-force:mainfrom
jflowers:opsx/crap-external-analyzer-fix
Sep 14, 2026
Merged

jflowers merged 1 commit into
unbound-force:mainfrom
jflowers:opsx/crap-external-analyzer-fix

Conversation

@jflowers

@jflowers jflowers commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

gaze crap --analyzer failed immediately with Error: no go.mod found on non-Go projects because FindModuleRoot ran before the --analyzer flag was checked. External analyzer users could not use the crap command at all.

This defers module-root resolution until after the --analyzer dispatch, matching the quality command. Go-native analysis still resolves go.mod; external analyzers use the working directory.

Closes #250.

How to Test

go test -race -count=1 -run 'TestCrapWithExternalAnalyzer_BypassesFindModuleRoot|TestRunCrap_GoNativePath' ./cmd/gaze/...
go test -race -count=1 -short ./...

From a directory without go.mod:

gaze crap --analyzer nonexistent --language python .

Expect an analyzer-discovery error, not no go.mod found.

Without --analyzer in a non-Go directory, expect finding module root: ....

How to Demo

  1. From a Python (or other non-Go) project directory, run gaze crap --analyzer <binary> --language python .
  2. Observe that Gaze no longer exits with no go.mod found
  3. From a Go module, run gaze crap ./... and confirm CRAP analysis still works

Key Files Changed

File Change
cmd/gaze/main.go Defer FindModuleRoot from Cobra closure into runCrap after --analyzer check
cmd/gaze/external_analyzer_test.go Regression tests for bypass and Go-native error wrapping
openspec/changes/crap-external-analyzer-fix/ Proposal, design, spec, and tasks

This PR was generated by /uf.finale (AI-assisted).

@jflowers jflowers self-assigned this Sep 4, 2026
@jflowers
jflowers requested a review from em-redhat September 4, 2026 13:29
@jflowers jflowers moved this to Ready for Review 👀 in Unbound Force Planning Sep 4, 2026

@em-redhat em-redhat left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE

Clean, well-scoped fix that defers FindModuleRoot from the Cobra closure into runCrap, placing it after the --analyzer early-return path. This matches the pattern already used by runQuality.

Strengths:

  • Correct fix location — external analyzer users never need a Go module root
  • p.analyzeFunc == nil guard prevents interference with test stubs
  • Error wrapping preserved (fmt.Errorf("finding module root: %w", err))
  • Both paths have regression tests (TestCrapWithExternalAnalyzer_BypassesFindModuleRoot and TestRunCrap_GoNativePath_FindModuleRootFailure)
  • Spec artifacts (proposal, design, specs, tasks) present and complete
  • All 5 CI checks pass

Constitution alignment: All four principles satisfied — Accuracy (external analyzer path no longer wrongly blocked), Minimal Assumptions (no Go module assumption for non-Go projects), Actionable Output (error messages reference actual problems), Testability (both paths covered).

No blocking findings.

Defer FindModuleRoot until after the --analyzer check so external
analyzer users are not blocked by a missing go.mod.

Closes unbound-force#250

Assisted-by: grok-4.6
Generated with AI assistance (grok-4.6)
@jflowers
jflowers force-pushed the opsx/crap-external-analyzer-fix branch from 4e3f4b3 to c893e6a Compare September 8, 2026 20:31
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 14, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 10:07 AM UTC · Completed 10:24 AM UTC

Commit: c893e6a · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $6.94

@fullsend-ai-review fullsend-ai-review Bot added the risk/moderate PR risk: moderate label Sep 14, 2026
@fullsend-ai-review

Copy link
Copy Markdown

Risk Assessment: moderate (2/5)

Details

Small, focused bug fix (16 net code lines in main.go) with OpenSpec artifacts inflating file count. main.go has elevated fix/revert churn but the change is narrow in scope. Linked issue #250 is a clear bug report with reproduction steps, and the PR scope is proportionate.

@fullsend-ai-review

Copy link
Copy Markdown

Review

Findings

Low

  • [similar bug in adjacent code path] cmd/gaze/main.gorunReport has the same unconditional FindModuleRoot call before the --analyzer dispatch. If gaze report --analyzer is invoked from a non-Go project directory, it will fail with "no go.mod found" for the same reason as issue bug: gaze crap --analyzer fails with 'no go.mod found' for non-Go projects #250. This PR correctly fixes the pattern in runCrap but the same pattern survives in runReport.
    Remediation: Consider filing a follow-up issue to defer FindModuleRoot in runReport.

  • [test organization] cmd/gaze/external_analyzer_test.goTestRunCrap_GoNativePath_FindModuleRootFailure tests Go-native runCrap behavior (no analyzer flag) but lives in external_analyzer_test.go. All other TestRunCrap_ tests reside in main_test.go.
    Remediation: Move to main_test.go or rename to TestCrapWithExternalAnalyzer_GoNativePathFallback to match the file's naming convention.

@fullsend-ai-review fullsend-ai-review Bot added the ready-for-merge All reviewers approved — ready to merge label Sep 14, 2026
@jflowers
jflowers merged commit ec204ea into unbound-force:main Sep 14, 2026
54 of 55 checks passed
@fullsend-ai-retro

fullsend-ai-retro Bot commented Sep 14, 2026

Copy link
Copy Markdown

🤖 Finished Retro · ✅ Success · Started 12:18 PM UTC · Completed 12:29 PM UTC

Commit: c893e6a · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $4.48

@fullsend-ai-retro

Copy link
Copy Markdown

Retro: PR #254 — fix: allow gaze crap --analyzer on non-Go projects

Timeline

Date Event
Sep 2 Issue #250 filed — gaze crap --analyzer fails with "no go.mod found" on non-Go projects
Sep 3 PR #254 opened by jflowers (AI-assisted via grok-4.6), with OpenSpec artifacts
Sep 8 09:34 Human review by em-redhat — APPROVED (detailed, thorough)
Sep 8 20:31 PR sync triggers CI (pass) + fullsend review dispatch
Sep 10 14:53 3 triage runs fire on issue #250 within 1 minute (1 success, 2 cancelled)
Sep 14 10:07 Review agent executes (~6 days after dispatch) — APPROVED, 2 low findings, $6.94, 14 min
Sep 14 12:16 PR merged

Workflow Quality

Review quality: Good. The review agent found a genuine bug the human reviewer missed — the same unconditional FindModuleRoot pattern exists in runReport, meaning gaze report --analyzer will fail identically on non-Go projects. The correctness sub-agent proactively searched for the pattern in adjacent commands, which is exactly the kind of cross-function analysis that adds value. The challenger adjudication correctly kept the real finding and downgraded a weaker semantic-drift finding to info.

Human review: Strong. em-redhat provided a detailed approval covering fix location, error wrapping, test coverage, spec artifacts, CI status, and constitution alignment. The human and agent reviews were complementary — the human verified correctness of the fix itself, while the agent detected the same pattern surviving in a sibling command.

Rework rate: Zero. Single commit, no fix iterations, no changes-requested cycles. The PR was well-scoped and the code was right on the first attempt.

Token cost: Reasonable. $6.94 for a thorough multi-dimension review with challenger adjudication on a 7-file, 282-line PR. Cache read ratio was high (1.9M cache_read vs 156K cache_create), indicating efficient context reuse.

Existing Issues Corroborated

Proposals

One proposal filed — the runReport FindModuleRoot bug found by the review agent. No existing issue tracks this.

Proposals filed

em-redhat pushed a commit that referenced this pull request Sep 17, 2026
runReport called loader.FindModuleRoot unconditionally at the top of
the function, causing gaze report --analyzer to fail with "no go.mod
found" on non-Go projects. This is the same bug pattern fixed in
runCrap by PR #254 (issue #250).

The fix makes FindModuleRoot conditional on p.analyzerFlag == "":
when --analyzer is set, the project may not be a Go module, so cwd
is used directly as moduleDir. When --analyzer is not set (Go-native
path), FindModuleRoot resolves the module root as before.

Added two regression tests:
- TestReportWithExternalAnalyzer_BypassesFindModuleRoot: verifies
  that runReport with --analyzer from a non-Go directory produces an
  analyzer discovery error, not "no go.mod found"
- TestRunReport_GoNativePath_FindModuleRootFailure: verifies that
  runReport without --analyzer still calls FindModuleRoot and
  produces the expected error format

All three commands (crap, quality, report) now follow the same
pattern: check --analyzer before calling FindModuleRoot.

Closes #257
em-redhat pushed a commit that referenced this pull request Sep 17, 2026
runReport called loader.FindModuleRoot unconditionally at the top of
the function, causing gaze report --analyzer to fail with "no go.mod
found" on non-Go projects. This is the same bug pattern fixed in
runCrap by PR #254 (issue #250).

The fix makes FindModuleRoot conditional on p.analyzerFlag == "":
when --analyzer is set, the project may not be a Go module, so cwd
is used directly as moduleDir. When --analyzer is not set (Go-native
path), FindModuleRoot resolves the module root as before.

Added two regression tests:
- TestReportWithExternalAnalyzer_BypassesFindModuleRoot: verifies
  that runReport with --analyzer from a non-Go directory produces an
  analyzer discovery error, not "no go.mod found"
- TestRunReport_GoNativePath_FindModuleRootFailure: verifies that
  runReport without --analyzer still calls FindModuleRoot and
  produces the expected error format

All three commands (crap, quality, report) now follow the same
pattern: check --analyzer before calling FindModuleRoot.

Closes #257
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-merge All reviewers approved — ready to merge risk/moderate PR risk: moderate

Projects

Status: Ready for Review 👀

Development

Successfully merging this pull request may close these issues.

bug: gaze crap --analyzer fails with 'no go.mod found' for non-Go projects

3 participants