Skip to content

feat: add Go adapter and vibe-check analyze CLI command - #21

Merged
jflowers merged 9 commits into
mainfrom
opsx/go-analyze
Aug 31, 2026
Merged

feat: add Go adapter and vibe-check analyze CLI command#21
jflowers merged 9 commits into
mainfrom
opsx/go-analyze

Conversation

@jflowers

Copy link
Copy Markdown
Contributor

Summary

Implements the Go language adapter and vibe-check analyze CLI command — the first language adapter for Vibe-Check, making the toolkit usable for computing design quality metrics on Go codebases.

Closes #2

What this adds

  • Go adapter (internal/goadapter/) implementing metrics.Adapter with 7 metrics:

    • Afferent coupling (Ca), Efferent coupling (Ce), Instability, Abstractness, Distance from main sequence, LCOM4 cohesion, circular dependency detection
    • Go-specific extensions: go.interfaceWidth and go.interfaceProximity
    • Uses golang.org/x/tools/go/packages for type-aware dependency resolution
    • Tarjan's SCC for cycle detection, union-find LCOM4
  • CLI command (cmd/vibe-check/) with:

    • vibe-check analyze [path] — JSON output conforming to ModuleGraph schema v1.1
    • CI gate flags: --max-instability, --max-distance, --max-lcom, --no-circular-deps
    • --timeout flag for analysis time bounds
    • Exit codes: 0 (success), 1 (policy violation), 2 (tool error)
    • Signal handling (SIGINT/SIGTERM) with partial JSON suppression
  • Extensions mechanism in metrics/:

    • Extensions map[string]any field on ModuleResult (backward-compatible, omitempty)
    • Schema bumped from v1.0 to v1.1; validate.go accepts both versions
    • Typed accessor functions (InterfaceWidths, InterfaceProximities) for JSON round-trip safety
  • CI workflow (.github/workflows/ci.yml):

    • SHA-pinned actions, concurrency groups, least-privilege permissions
    • Build, vet, test (-race -count=1), lint (golangci-lint v2.12.2)

Architecture

Three-layer design per the RFC:

  • Layer 1 (metrics/): Universal model — unchanged public API, additive Extensions field
  • Layer 2 (internal/goadapter/): Go-specific analysis, implements metrics.Adapter
  • Layer 3 (cmd/vibe-check/): CLI entry point, delegates to adapter via testable RunAnalyze()

How to Test

# Run full test suite (96 tests)
go test -race -count=1 ./...

# Build the binary
go build -o vibe-check ./cmd/vibe-check/

# Analyze this repo
./vibe-check analyze .

# Analyze with threshold enforcement
./vibe-check analyze --max-instability 0.8 --max-distance 0.5 .

# Check version
./vibe-check --version

# Lint
golangci-lint run ./...

How to Demo

  1. Build the binary: go build -o vibe-check ./cmd/vibe-check/
  2. Run ./vibe-check analyze . — observe JSON output with metrics for each package
  3. Run ./vibe-check analyze --max-instability 0.1 . — observe exit code 1 and violation messages on stderr
  4. Run ./vibe-check analyze --no-circular-deps . — observe no circular deps in this repo
  5. Run ./vibe-check --version — observe version output format

Key Files Changed

Directory Files Description
cmd/vibe-check/ main.go, root.go, analyze.go, analyze_test.go CLI entry point, analyze command with 56 tests
internal/goadapter/ adapter.go, resolve.go, types.go, lcom.go, cycles.go, extensions.go, doc.go Go adapter implementation (7 files)
internal/goadapter/ adapter_test.go, types_test.go, lcom_test.go, cycles_test.go, extensions_test.go Adapter tests (26 tests)
internal/goadapter/testdata/ 6 fixture modules (coupling, types, lcom, extensions, partial, empty) Test fixtures
metrics/ graph.go, modulegraph.schema.json, validate.go, validate_test.go Extensions field, schema v1.1, validation
.github/workflows/ ci.yml CI pipeline with SHA-pinned actions
openspec/changes/go-analyze/ proposal.md, design.md, specs, tasks.md Spec artifacts
root AGENTS.md, CHANGELOG.md, go.mod, go.sum Documentation and dependencies

52 files changed, 4751 insertions, 24 deletions

Known Issues

The following findings from the review council were acknowledged but not resolved:

  • LOW (Adversary): CI version comments use major tags (# v4) instead of exact minor/patch versions
  • LOW (Tester): Boundary value test comment has stale Ce values after fix
  • LOW (Tester): TestAdapter_Capabilities verifies count but not bidirectional completeness
  • LOW (SRE): CI workflow naming ci.yml deviates from CI-010 ci_ prefix convention
  • MEDIUM (Guard): CHANGELOG missing Spec: path references for traceability
  • MEDIUM (SRE): No README.md for user-facing documentation

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

Proposal, design, specs, and tasks for the vibe-check analyze
command and Go language adapter. Includes extensions mechanism
for go.interfaceWidth and go.interfaceProximity metrics.

Refs: #2
- Add Extensions map[string]any to ModuleResult (omitempty)
- Add extensions property to JSON schema, keep additionalProperties: false
- Bump SchemaVersionCurrent from 1.0 to 1.1
- Update validate.go to accept both schema versions
- Add validation that extensions must be JSON object when present

Refs: #2
Go adapter implementing metrics.Adapter interface:
- Package loading via go/packages with NeedTypes and NeedTypesInfo
- Ca/Ce coupling metrics with stdlib/external filtering
- AST-based type classification (interfaces = abstract)
- LCOM4 via union-find connected components
- Tarjan's SCC for circular dependency detection
- go.interfaceWidth and go.interfaceProximity extensions
- Typed extension accessors for JSON round-trip safety
- Environment sanitization via metrics.SanitizeEnvironment
- Comprehensive test suite (26 tests with race detection)

Includes testdata fixtures for coupling, types, LCOM, extensions,
partial builds, and empty directory scenarios.

Refs: #2
Cobra-based CLI with testable RunAnalyze() entry point (AP-002/AP-003):
- analyze subcommand invokes Go adapter
- Threshold flags: --max-instability, --max-distance, --max-lcom, --no-circular-deps
- --timeout flag for analysis time bounds
- --version flag with ldflags-embedded build metadata
- Signal handling (SIGINT/SIGTERM) with partial JSON suppression
- Exit codes: 0=success, 1=policy violation, 2=tool error
- Flag validation (range checks, type checks)
- Comprehensive test suite (56 tests with race detection)

Refs: #2
- Update Project Structure with cmd/vibe-check/ and internal/goadapter/
- Update Architecture section with three-layer design and phasing status
- Add CHANGELOG.md with initial unreleased entries
- Pin CI workflow actions to commit SHAs
- Add concurrency group and descriptive workflow name

Refs: #2
…ns, CI pinning

- Fix CRITICAL: Ce now counts all imports (incl. stdlib) per Martin's definition
- Fix HIGH: Add errors.Is assertions for context cancellation/deadline wrapping
- Fix HIGH: Add Warning.Code/Module/Message assertions for partial builds
- Fix HIGH: Pin golangci-lint to v2.12.2 (was 'latest')
- Fix MEDIUM: Remove GOFLAGS from env allowlist (flag injection risk)
- Fix MEDIUM: Replace os.Exit in RunE with exitCodeError type
- Fix MEDIUM: Replace fragile RunE wrapper with cmd.Flags().Changed()
- Fix MEDIUM: Use strings.HasPrefix instead of slice bounds check
- Fix MEDIUM: Add testing.Short() guards on context tests

Refs: #2
- Mark code-review passed in tasks.md
- Store 4 retrospective learnings in Dewey knowledge base

Assisted-by: claude-opus
Generated with AI assistance (claude-opus)

@jflowers jflowers left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Note: Could not post as APPROVE — GitHub prohibits a PR author approving their own pull request (HTTP 422). Posted as COMMENT instead. Original council verdict: APPROVE.

Council Verdict: APPROVE

Reviewers: divisor-adversary, divisor-architect, divisor-curator, divisor-envoy, divisor-guard, divisor-herald, divisor-scribe, divisor-sre, divisor-testing (9 discovered, all invoked)
Iterations: 2 fix rounds — initial 9/9 REQUEST CHANGES → 8 APPROVE / 1 REQUEST CHANGES → 9/9 APPROVE

Resolved this cycle: 1 CRITICAL, 6 HIGH, 7 MEDIUM. No protected quality/governance gate was weakened (Guard: gatekeeping CLEARED). CI-parity green: go build/vet, go test -race -count=1, golangci-lint v2.12.2 (0 issues).

divisor-adversary (APPROVE)

Trust boundary now enforced (validate.go numeric ranges + external.go DisallowUnknownFields); GOFLAGS excluded + regression-locked. 3 LOW advisories: binaryPath validation in ExternalAdapter (not CLI-wired); recursive Tarjan lacks depth guard; public Validate() accepts non-integer for int count fields (boundary already int-decoded).

divisor-architect (APPROVE, Alignment 9/10)

canonicalizeCycle contract/GoDoc/impl aligned to sorted-set semantics + non-coincidental test; computeLCOM4 decomposed; 3-layer boundaries clean. 0 findings remaining.

divisor-guard (APPROVE — GATEKEEPING CLEARED)

All protected gates intact (CI flags, dep pins, 7 capability consts, schema strictness, severity defs, constitution MUSTs). Constitution VI legitimately PASS (LCOM4 defect fixed), III honestly PARTIAL. 1 LOW: CHANGELOG omits Spec: cross-ref.

divisor-testing (APPROVE)

Both prior HIGH now covered with deep non-coincidental assertions; all prior MEDIUM resolved. 2 LOW: testing.Short() guard consistency on loadTestPackage unit tests; a few CLI test names lack _Scenario suffix.

divisor-sre (APPROVE)

--version ReadBuildInfo fallback; README created; error remediation added; coverage-ratchet overclaim corrected. 3 LOW: quadratic countCa (P2); go 1.25.7 patch pin (protected — do not modify); coverage.out ungated/unretained.

divisor-scribe (APPROVE)

Type-classification precision + LCOM struct-field-only reconciled across doc.go/spec/design; schema enum+descriptions. 0 findings remaining.

divisor-curator (APPROVE)

README (128 lines) covers install/usage/flags/exit-codes/JSON+schema/limitations, FA-001 clean. 0 in-tree findings. 5 external pre-merge items (below).

divisor-herald (APPROVE)

CHANGELOG 0.1.0 finalized; Validate()/ExternalAdapter attribution corrected. 1 LOW (stylistic framing).

divisor-envoy (APPROVE)

Errors actionable; terminology/--version claims scoped; README + schema pointer added. 1 LOW: design.md:27 Goals says default ./... while CLI defaults to ..

Linked Issues

Issue Title Notes
#2 vibe-check analyze — Go-native package-level coupling metrics Closed by this PR (P0 foundation). Intent: compute Ca/Ce/Instability/Abstractness/Distance/LCOM4 + cycle detection via go/packages. No explicit acceptance-criteria checkboxes in the issue body.

External Pre-Merge Checklist (cannot action from tree — close before merge)

  1. Create+apply labels: docs#18, blog#19, tutorial#22
  2. Refresh/split stale #18 (predates CLI)
  3. File website-doc-sync issue
  4. File GoReleaser/release-automation issue
  5. Confirm v0.1.0 tag/release published
  6. File provenance follow-up issue (Constitution III PARTIAL)

This review was generated by /review-council (AI-assisted).

Address findings from /uf.review-council (2 iterations, final 9/9 APPROVE):

- lcom: handle generic pointer receivers (*T[P]) via baseTypeName helper;
  add generic fixture + tests (previously dropped methods, corrupting LCOM4)
- cycles: align Cycle contract/GoDoc/impl to sorted-set semantics + test
- adapter: emit zeroed ModuleResult+warning for errored packages; add
  errTotalLoadFailure guard + anyPackageTypeChecked for total load failure
- types: count type aliases (incl alias-to-interface) as concrete
- extensions: add CapInterfaceWidth/CapInterfaceProximity consts +
  ExtensionCapabilities() accessor (DRY)
- validate/external: enforce numeric ranges and DisallowUnknownFields at
  the ExternalAdapter trust boundary
- cmd: extract run()/exitCode()/versionString() (ReadBuildInfo fallback);
  test analyzeCmd via Execute(); add actionable error remediation
- refactor: decompose computeLCOM4; extract packageEnvAllowlist (GOFLAGS excluded)
- docs: add README; finalize CHANGELOG 0.1.0; schema v1.1 enum+descriptions;
  reconcile design/spec/proposal/tasks with implementation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

vibe-check analyze — Go-native package-level coupling metrics

1 participant