Skip to content

feat: add comprehensive Go repository support with monorepo detection#412

Merged
jwm4 merged 4 commits into
ambient-code:mainfrom
natifridman:golang
May 12, 2026
Merged

feat: add comprehensive Go repository support with monorepo detection#412
jwm4 merged 4 commits into
ambient-code:mainfrom
natifridman:golang

Conversation

@natifridman
Copy link
Copy Markdown
Contributor

@natifridman natifridman commented May 11, 2026

Summary

  • Add Go-specific assessment logic to 6 assessors that previously returned not_applicable or used wrong language paths for Go repos
  • Add monorepo support for projects with go.mod in subdirectories (e.g., multi-service repos)
  • Fix primary language detection for mixed Go/Python repos using root manifest tiebreaker

Assessors extended

  • TestExecutionAssessor (T1, 10%): *_test.go detection, go test/coverage/race scoring, subdirectory Makefile scanning
  • TypeAnnotationsAssessor (T1, 8%): auto-pass for static typing, interface{}/any overuse penalty
  • StandardLayoutAssessor (T1, 5%): Go layout detection (go.mod, cmd/, internal/, pkg/) with monorepo aggregation
  • CyclomaticComplexityAssessor (T3, 3%): gocyclo tool + golangci-lint cyclop/gocyclo config detection in subdirs
  • StructuredLoggingAssessor (T3, 1.5%): zap/logrus/zerolog/slog detection across all go.mod files
  • InlineDocumentationAssessor (T2, 3%): godoc comment coverage on exported symbols, doc.go detection

Infrastructure

  • BaseAssessor._primary_language(): dispatches by file count with root manifest tiebreaker for mixed-language repos
  • BaseAssessor._find_go_module_roots(): finds go.mod at root and in one-level subdirectories
  • Go.arsrc: directory exclusion list for Go project layout detection
  • Bootstrap templates updated to Go 1.23/1.24, golangci-lint-action v6, added govulncheck
  • go vet added to CI typecheck patterns, enhanced gitignore patterns
  • _has_golangci_lint() searches module root dirs for .golangci.toml/.golangci.json variants

Real-world testing

Repository Before After Delta
opendatahub-io/models-as-a-service (Go monorepo) 40.9 Bronze 59.6 Bronze +18.7
opendatahub-io/opendatahub-operator (Go single-module) N/A 68.4 Silver
opendatahub-io/kserve (Go+Python mixed) 44.3 Bronze 52.9 Bronze +8.6

Test plan

  • 41 new Go-specific unit tests covering all assessors and monorepo patterns (tests/unit/test_assessors_go.py)
  • Full test suite passes: 1193 passed, 0 failed
  • Linting clean: black, isort, ruff check all pass
  • Tested against 3 real-world Go repositories (single-module, monorepo, mixed-language)
  • Existing Python/JS assessor paths unaffected (verified by existing test suite)

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added comprehensive Go language support to code quality assessments, including type annotations, documentation coverage, cyclomatic complexity, and structured logging evaluation.
    • Enhanced Go project structure validation with monorepo support.
    • Added Go vulnerability checking tool (govulncheck) to security workflows.
  • Improvements

    • Updated Go workflow templates to support versions 1.23 and 1.24.
    • Improved CI quality gate detection for Go test and lint commands.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

Warning

Rate limit exceeded

@natifridman has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 53 minutes and 20 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: bc32fc8a-317d-418a-845a-41dcf6748ffe

📥 Commits

Reviewing files that changed from the base of the PR and between bd4b891 and 72d8e81.

📒 Files selected for processing (10)
  • src/agentready/assessors/base.py
  • src/agentready/assessors/code_quality.py
  • src/agentready/assessors/documentation.py
  • src/agentready/assessors/structure.py
  • src/agentready/assessors/stub_assessors.py
  • src/agentready/assessors/testing.py
  • src/agentready/templates/bootstrap/go/workflows/security.yml.j2
  • src/agentready/templates/bootstrap/go/workflows/tests.yml.j2
  • tests/unit/test_assessors_go.py
  • tests/unit/test_bootstrap_templates.py
📝 Walkthrough

Walkthrough

This pull request adds comprehensive Go language support to the agentready repository assessor framework. It introduces language-resolution helpers, expands six assessors with Go-specific logic (type annotations, complexity, logging, documentation, structure, testing), updates CI workflow templates, and adds extensive test coverage spanning Go monorepo layouts and tool integration patterns.

Changes

Go Language Assessment Framework

Layer / File(s) Summary
Language resolution foundation
src/agentready/assessors/base.py
New _primary_language() selects the dominant language by file count from repository.languages, using root manifest presence at repository.path as a tie-breaker when counts are within 30%. New _find_go_module_roots() locates go.mod files (root and subdirectories, excluding vendor/ and testdata/), enabling monorepo support across all assessors.
Code quality assessors for Go
src/agentready/assessors/code_quality.py
Four assessor enhancements dispatching by primary language to Go code paths: TypeAnnotationsAssessor scans non-test .go files for interface{} and any, computing a ratio-based score; CyclomaticComplexityAssessor tries gocyclo -avg first, then detects golangci-lint complexity linters in root and module directories, raising MissingToolError if neither is available; StructuredLoggingAssessor checks go.mod files in module roots for zap/logrus/zerolog/slog and scans source code for log/slog; CodeSmellsAssessor._has_golangci_lint() expanded to recognize .golangci.json and search module root directories. All include Go-specific remediation generators.
Inline documentation (godoc) assessment
src/agentready/assessors/documentation.py
InlineDocumentationAssessor extended to support Go by dispatching to _assess_go_godoc() when Go is the primary language. Scans exported Go symbols (func, type, var, const, and methods) across *.go files (excluding _test.go and vendor/), checks for doc comments immediately above declarations, tracks doc.go presence, and scores against an 80% coverage threshold. Returns Finding.not_applicable when no exported symbols exist or Go is not the primary language.
Project structure and conventions
src/agentready/assessors/structure.py, src/agentready/assessors/stub_assessors.py
StandardLayoutAssessor._assess_go_layout() validates Go repositories by checking for go.mod in root and subdirectories (module roots), verifying standard Go directories (cmd/, internal/, pkg//api/), detecting main entrypoints, and scanning for *_test.go files. Conditional remediation includes go mod init, directory scaffolding, and test commands. DependencyPinningAssessor finds go.sum in module subdirectories when absent from root. GitignoreAssessor adds Go-specific patterns (bin/, cover.out, coverage.txt).
Test execution and CI assessment
src/agentready/assessors/testing.py
TestExecutionAssessor detects Go test files (*_test.go), scores on presence of go test invocations in CI/Makefile/README, coverage flags (-cover*, -coverprofile, -covermode), and -race flags. Reads module-local Makefiles/Taskfiles/READMEs and CI workflows. CIQualityGatesAssessor extended to recognize go test and $(GO) test commands and go vet typechecking in CI config. Both provide Go-specific remediation with example go test commands.
GitHub Actions workflow templates
src/agentready/templates/bootstrap/go/workflows/security.yml.j2, src/agentready/templates/bootstrap/go/workflows/tests.yml.j2
Security workflow upgraded to Go 1.24 and adds govulncheck (v1.3.0) step. Test workflow updated to run against Go 1.23 and 1.24, upgrades golangci-lint-action from v3 to v9, and adjusts coverage condition to match latest Go version.
Comprehensive test suite
tests/unit/test_assessors_go.py, tests/unit/test_bootstrap_templates.py
New test_assessors_go.py module with 1000+ lines validating all assessor behaviors: Go applicability detection, scoring for type safety (interface{}/any ratio), complexity tool integration, structured logging library detection, godoc coverage, layout structure including monorepo subdirectory go.mod handling, and test execution signals. Includes regression tests for multiline godoc parsing, GO ?= go Makefile variables, comment/string literal filtering, and doc-comment association. Template test updated to expect Go 1.23/1.24 range.

Sequence Diagram

sequenceDiagram
    participant App as Assessor Framework
    participant Base as Language Resolution
    participant Assessor as Go Assessor<br/>(e.g., Types, Layout)
    participant Repo as Repository<br/>Object

    App->>Base: assess(repository)
    Base->>Repo: query repository.languages<br/>+ repository.path
    Base->>Base: _primary_language()<br/>(file counts + manifests)
    Base-->>App: primary_language: "Go"
    
    App->>Assessor: dispatch based on<br/>primary language
    Assessor->>Repo: read_tree() for .go files<br/>+ go.mod locations
    Assessor->>Assessor: _find_go_module_roots()<br/>(root + subdirs)
    Assessor->>Assessor: analyze Go code<br/>(types, structure, docs, etc.)
    Assessor->>Assessor: compute score<br/>+ evidence + remediation
    Assessor-->>App: Finding(pass/fail)
    
    App-->>App: collect findings across<br/>all assessors
Loading

Suggested labels

released

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title follows Conventional Commits format (feat: description) and accurately describes the primary change: adding comprehensive Go repository support with monorepo detection.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 11, 2026

📈 Test Coverage Report

Branch Coverage
This PR 73.0%
Main 72.5%
Diff ✅ +0.5%

Coverage calculated from unit tests only

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/agentready/assessors/base.py`:
- Around line 125-137: _find_go_module_roots currently only checks one directory
level; change it to search recursively (e.g., use rglob or equivalent) for all
go.mod files under repository.path, skip any matches that live inside vendor
directories, and collect the parent directories as module roots; also keep the
repository root if it contains go.mod and dedupe the resulting list (use
Path.parent to get roots and filter out duplicates).
- Around line 109-123: _primary_language() is non-deterministic because it
iterates a set of candidate languages; make the tie-break deterministic by
ordering contenders before checking manifests: build a sorted list of (lang,
count) from lang_counts (sort by descending count then by language name) and
iterate that list (skip top_lang), apply the existing 0.7 closeness check, then
check manifests using self._LANG_ROOT_MANIFESTS for the contender and for
top_lang in a fixed order; return the chosen language accordingly so repeated
runs yield the same result.

In `@src/agentready/assessors/code_quality.py`:
- Around line 554-575: The fallback that returns a Passing Finding when any
.golangci.* file exists is unsafe; update the loop that iterates search_dirs and
config_name to actually parse the matched config file and verify complexity
linters (gocyclo, cyclop, gocognit) are enabled—specifically, read the config
contents, check for disable/disable-all entries and the linters/linters-settings
sections to ensure those linters are not explicitly disabled (or are present in
enabled linters); only then return the Finding with measured_value
"golangci-lint configured". If parsing fails or the file explicitly disables
those linters, do not return the pass Finding (instead return no Finding or a
neutral/failed Finding); keep references to repository.path, search_dirs,
config_name and the Finding construction (attribute=self.attribute) when
implementing this change.

In `@src/agentready/assessors/documentation.py`:
- Around line 1224-1254: The exported-symbol detection and doc-comment check are
wrong: update exported_pattern to also match exported methods with receivers
(e.g., change exported_pattern to allow an optional receiver group before the
name so it matches lines like "func (s *Server) Start()") and adjust the
documentation check so it only counts a preceding comment when it actually
begins with the symbol name (use prev_line.startswith(f"// {symbol_name}")
rather than accepting any "//" line); also handle preceding block comments (/*
... */) by examining the last non-empty previous token block and ensuring its
first line starts with the symbol name before incrementing documented_exported
(references: exported_pattern, symbol_name, documented_exported, total_exported,
the loop over go_files/lines).

In `@src/agentready/assessors/structure.py`:
- Around line 124-125: The current check "if 'Go' in repository.languages"
wrongly triggers Go layout when any Go file exists; change it to only choose the
Go assessor when Go is the repository's primary language (or otherwise wins the
tiebreaker). Update the conditional around the call to
self._assess_go_layout(repository) to inspect the repository's primary-language
field or tiebreaker result (e.g., repository.primary_language or a helper that
returns the dominant language) instead of membership in repository.languages so
mixed repos aren't misclassified.

In `@src/agentready/assessors/stub_assessors.py`:
- Around line 67-71: The check for Go monorepo lockfiles only searches one level
deep (repository.path.glob("*/go.sum")), missing nested modules like
services/auth/go.sum; update the search to recursively find go.sum files (use
repository.path.rglob("go.sum") or repository.path.glob("**/go.sum")) and append
their relative paths to found_strict (keep the existing break logic if you only
need the first hit), referencing the found_strict list and the
repository.path.glob usage in stub_assessors.py.

In `@src/agentready/assessors/testing.py`:
- Around line 414-421: The current scan only looks one level deep for module
build files; update the search to recursively scan the repo for nested
build/task files by replacing the one-level glob used when appending to
files_to_check (currently repository.path.glob("*/Makefile")) with a recursive
search (repository.path.rglob or glob with "**/Makefile"), and also add
recursive patterns for other common build/task filenames (e.g.,
Taskfile.yml/Taskfile.yaml and deeper Makefiles) so files_to_check collects
matches like services/**/Makefile and **/Taskfile.{yml,yaml}; keep using the
same files_to_check list and ci_dir logic for .github workflows but apply rglob
patterns for completeness.
- Around line 369-374: The coverage detection currently only matches
"-coverprofile" and "-covermode" so plain "go test -cover" is missed; update the
regex used to set has_coverage in testing.py (the expression that assigns
has_coverage from re.search) to also recognize plain "-cover" (and variants like
"-cover=", "-cover ./...") by including "-cover" as an alternative (e.g., make
the pattern match "-cover" or "-coverprofile" or "-covermode" with appropriate
word-boundary/optional suffix handling) so the block that increments score and
appends evidence correctly flags repos that use "go test -cover".

In `@src/agentready/templates/bootstrap/go/workflows/security.yml.j2`:
- Around line 24-27: Replace the unpinned installation of govulncheck in the
workflow step that runs "go install golang.org/x/vuln/cmd/govulncheck@latest"
with a pinned version; update the install command to use a specific semantic
version (e.g., `@vX.Y.Z`) or a template variable so CI uses a fixed govulncheck
release, and ensure any documentation or template variables (the govulncheck
install line and the "Run govulncheck" step) are adjusted accordingly to avoid
using `@latest`.

In `@src/agentready/templates/bootstrap/go/workflows/tests.yml.j2`:
- Around line 32-34: The workflow currently sets golangci-lint action version to
"latest" (uses: golangci/golangci-lint-action@v6 with version: latest); change
the version key to a pinned, specific release (for example a concrete
semver/tag) so CI is deterministic, e.g. replace the version: latest entry with
a fixed version string and optionally add a comment or dependabot config to
update it periodically; keep the uses: golangci/golangci-lint-action@v6 line
as-is but ensure the version input is a specific pinned tag rather than
"latest".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 824f50a2-7a19-4949-a344-0d1311be59fe

📥 Commits

Reviewing files that changed from the base of the PR and between 59989f0 and bd5a68d.

📒 Files selected for processing (11)
  • src/agentready/assessors/base.py
  • src/agentready/assessors/code_quality.py
  • src/agentready/assessors/documentation.py
  • src/agentready/assessors/structure.py
  • src/agentready/assessors/stub_assessors.py
  • src/agentready/assessors/testing.py
  • src/agentready/data/Go.arsrc
  • src/agentready/templates/bootstrap/go/workflows/security.yml.j2
  • src/agentready/templates/bootstrap/go/workflows/tests.yml.j2
  • tests/unit/test_assessors_go.py
  • tests/unit/test_bootstrap_templates.py

Comment thread src/agentready/assessors/base.py
Comment thread src/agentready/assessors/base.py Outdated
Comment thread src/agentready/assessors/code_quality.py Outdated
Comment on lines +1224 to +1254
exported_pattern = re.compile(r"^(?:func|type|var|const)\s+([A-Z]\w*)")

for file_path in go_files:
full_path = repository.path / file_path
if full_path.name == "doc.go":
has_doc_go = True

try:
lines = full_path.read_text(encoding="utf-8").splitlines()
except (OSError, UnicodeDecodeError):
continue

for i, line in enumerate(lines):
match = exported_pattern.match(line.strip())
if not match:
continue

total_exported += 1
symbol_name = match.group(1)

# Check if previous non-empty line is a comment starting with symbol name
if i > 0:
prev_idx = i - 1
while prev_idx >= 0 and not lines[prev_idx].strip():
prev_idx -= 1
if prev_idx >= 0:
prev_line = lines[prev_idx].strip()
if prev_line.startswith(
f"// {symbol_name}"
) or prev_line.startswith("//"):
documented_exported += 1
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

In Go's documentation conventions, do exported methods require doc comments, and should doc comments on exported declarations start with the declaration name?

💡 Result:

Yes—Go’s documentation conventions say that every exported (capitalized) name should have a doc comment, and doc comments for types (and similarly for funcs/methods) should start with the declared symbol’s name. Go doc comments are defined as the comments that appear immediately before top-level package, const, func, type, and var declarations, with no intervening blank line. The documentation rules further state: “Every exported (capitalized) name should have a doc comment.”[1] It also says that “These rules all apply both to plain functions and to methods.”[1] For the “should start with the declaration name” part: the Go docs explain that, for types, “doc comments for types start with naming the declared symbol” and give examples; this same “rules all apply … to plain functions and to methods” guidance indicates the same convention applies to exported functions/methods as well.[1] So, in practice: exported methods (which are part of the doc-comment rules for funcs/methods) should have doc comments, and those doc comments should begin with the method name (the declared symbol), typically as the first sentence.

Citations:


Godoc coverage is undercounting methods and overcounting unrelated comments.

The regex pattern fails to capture exported methods because it doesn't account for receivers (e.g., func (s *Server) Start() won't match). Additionally, the documentation check accepts any preceding // line, not just those starting with the symbol name, inflating coverage. Go's official documentation requires every exported name—including methods—to have a doc comment starting with the declared symbol's name, so the assessment is both under- and over-inclusive.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/agentready/assessors/documentation.py` around lines 1224 - 1254, The
exported-symbol detection and doc-comment check are wrong: update
exported_pattern to also match exported methods with receivers (e.g., change
exported_pattern to allow an optional receiver group before the name so it
matches lines like "func (s *Server) Start()") and adjust the documentation
check so it only counts a preceding comment when it actually begins with the
symbol name (use prev_line.startswith(f"// {symbol_name}") rather than accepting
any "//" line); also handle preceding block comments (/* ... */) by examining
the last non-empty previous token block and ensuring its first line starts with
the symbol name before incrementing documented_exported (references:
exported_pattern, symbol_name, documented_exported, total_exported, the loop
over go_files/lines).

Comment thread src/agentready/assessors/structure.py Outdated
Comment thread src/agentready/assessors/stub_assessors.py Outdated
Comment thread src/agentready/assessors/testing.py Outdated
Comment thread src/agentready/assessors/testing.py Outdated
Comment thread src/agentready/templates/bootstrap/go/workflows/security.yml.j2
Comment on lines 32 to 34
uses: golangci/golangci-lint-action@v6
with:
version: latest
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

What is the current stable golangci-lint release recommended for golangci/golangci-lint-action@v6 pinning in GitHub Actions workflows?

💡 Result:

The current stable golangci-lint release is v2.12.2, released on 2026-05-06.[1][2][3] For pinning in GitHub Actions workflows using golangci/golangci-lint-action@v6, the official documentation and examples recommend specifying a particular version like version: v1.60 or version: latest (which installs the latest stable).[4][5][6] While "latest" is shown in examples, for reproducible CI as emphasized in the official docs, pin to the current stable v2.12.2.[7] Note that v6 of the action supports golangci-lint v1 versions based on compatibility notes (e.g., v2.0.0+ works with >=v1.28.3), but given no explicit restriction to v1 and examples using high v1.x, it likely supports v2.x; however, for safety with v6 pinning, consider upgrading to v7+ if using v2.x is needed, as v7 explicitly supports v2 only.[8][9]

Citations:


Pin golangci-lint to a fixed version instead of latest.

Using version: latest makes generated CI nondeterministic and can cause unexpected build failures when upstream releases change behavior. Pinning to a specific version ensures reproducible builds across environments.

Proposed fix
       - name: Run golangci-lint
         uses: golangci/golangci-lint-action@v6
         with:
-          version: latest
+          version: v1.60.3
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
uses: golangci/golangci-lint-action@v6
with:
version: latest
uses: golangci/golangci-lint-action@v6
with:
version: v1.60.3
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/agentready/templates/bootstrap/go/workflows/tests.yml.j2` around lines 32
- 34, The workflow currently sets golangci-lint action version to "latest"
(uses: golangci/golangci-lint-action@v6 with version: latest); change the
version key to a pinned, specific release (for example a concrete semver/tag) so
CI is deterministic, e.g. replace the version: latest entry with a fixed version
string and optionally add a comment or dependabot config to update it
periodically; keep the uses: golangci/golangci-lint-action@v6 line as-is but
ensure the version input is a specific pinned tag rather than "latest".

@jwm4 jwm4 self-requested a review May 11, 2026 15:11
@ralphbean
Copy link
Copy Markdown

Related: #378

@jwm4
Copy link
Copy Markdown
Contributor

jwm4 commented May 11, 2026

🤖 AgentReady Code Review

PR Status: 2 🔴 confirmed accuracy bugs, 1 🟡 code-level concern
Issue #378: All five functional acceptance criteria addressed
Test suite: 41/41 passing (PYTHONPATH=src pytest tests/unit/test_assessors_go.py)


Real-World Validation

We ran agentready assess against four Go repositories to validate the claimed improvements:

Repo Score Cert test_execution type_annotations standard_layout structured_logging inline_documentation
gin-gonic/gin 48.3 Bronze ✗ 80 ✗ 70 ✓ 75 ✗ 0 ✗ 67
cli/cli 60.6 Silver ✓ 80 ✓ 85 ✓ 100 ✓ 100 ✗ 18
prometheus/prometheus 63.9 Silver ✓ 80 ✓ 85 ✓ 100 ✓ 100 ✗ 42
opendatahub-io/models-as-a-service 58.8 Bronze ✓ 100 ✗ 70 ✓ 100 ✓ 100 ✗ 71

The models-as-a-service result (58.8) closely matches the PR's claimed 59.6, validating the improvement. cli/cli and prometheus both correctly reach Silver, where Go repos previously couldn't score above their Python-assessed baseline.


🔴 Confirmed Accuracy Bugs

1. inline_documentation systematically undercounts godoc coverage

Attribute: inline_documentation (Tier 2, 3%)
Location: src/agentready/assessors/documentation.py around _assess_go_godoc

The assessor checks only the last comment line before each exported symbol. Standard Go godoc frequently spans multiple lines, where only the opening line carries the symbol name. Any multi-line comment causes a false negative.

We verified this against cli/cli. Manual analysis of 50 source files found:

Count
Single-line godoc (correctly detected) 120
Multi-line godoc (incorrectly missed) 91
No documentation 442

The assessor reports 14.8% coverage; actual coverage is 32.3%. 43% of documented symbols are silently missed. The fail status, low score, and remediation telling cli/cli maintainers to add godoc are all incorrect.


2. test_execution false negative on $(GO) test Make variable convention

Attribute: test_execution (Tier 1, 10%)
Location: src/agentready/assessors/testing.py, _read_go_build_files / _assess_go_coverage

gin-gonic/gin runs tests via make test, where the Makefile invokes $(GO) test — a standard convention for parameterizing the Go binary path. The assessor's pattern only matches the literal string go test, so has_test_cmd returns False even though tests, coverage config, and race detection are all present and accounted for.

The result: gin scores 80/100 for test execution (correctly finding test files, -coverprofile, and -race) but receives a fail status and remediation telling it to configure test execution. The score and the status contradict each other, and the remediation is misleading.


🟡 Code-Level Concern

3. _primary_language non-deterministic on exact file-count ties

Location: src/agentready/assessors/base.py, _primary_language

max(lang_counts, key=lang_counts.get) is non-deterministic when two languages share the same file count. One instance of this was already caught and corrected within this branch; a second instance survives in the same method.


Summary

The Go support is working and the real-world score improvements are genuine. Two accuracy bugs — the multi-line godoc checker and the $(GO) test pattern — produce meaningfully wrong output on well-maintained, well-documented projects. Both would affect leaderboard scores and the trust users place in the tool's assessment of their Go repos.

This review was generated by Claude Code under the supervision of Bill Murdock.

Copy link
Copy Markdown
Contributor

@jwm4 jwm4 left a comment

Choose a reason for hiding this comment

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

See earlier comment.

@kami619
Copy link
Copy Markdown
Collaborator

kami619 commented May 11, 2026


AgentReady Code Review — PR #412

PR Status: 5 issues found (2 Critical, 2 Major, 1 Minor)
Score Impact: Current 80.0/100 → 81.5/100 if all issues fixed
Certification: Gold → Gold (closer to Platinum threshold)


Critical Issues (Confidence >=90) - Auto-Fix Recommended

  1. Multi-line godoc comment detection bug causes false negatives
  • Attribute: 2.2 Inline Documentation (Tier 2, 3%)
  • Confidence: 95%
  • Score Impact: -1.5 points
  • Location: documentation.py:1248-1256

The godoc checker only inspects the last non-blank line before a symbol. Multi-line Go comments where the continuation line is adjacent to the symbol are missed:
// Handler processes incoming HTTP requests.
// It routes them to the appropriate service method.
func Handler(w http.ResponseWriter, r *http.Request) {}
The checker sees // It routes them... and marks this as undocumented. Fix: walk back through consecutive comment lines and check if the first one starts with // SymbolName.


  1. \bany\b regex matches any in comments and string literals
  • Attribute: 3.3 Type Annotations (Tier 1, 8%)
  • Confidence: 90%
  • Score Impact: -0.5 points
  • Location: code_quality.py:247-250

The regex r"\binterface\s*{\s*}|\bany\b" matches any anywhere — including // fix any bugs and "any value". In typical Go codebases, any in comments inflates the type-weakness count. Fix: strip
comments/strings before matching, or restrict to declaration lines.


Major Issues (Confidence 80-89) - Manual Review Required

  1. Go.arsrc data file is dead code — never loaded
  • Attribute: 4.1 Standard Project Layouts (Tier 1, 5%)
  • Confidence: 85%
  • Location: src/agentready/data/Go.arsrc

33 lines of Go non-source directory exclusions (vendor, testdata, hack, scripts, etc.) that are never loaded. _load_arsrc_file() exists but only loads Python.arsrc. Either integrate it or remove it.

  1. Raw Finding() constructor instead of helpers (9 instances)
  • Attribute: Code Patterns (CLAUDE.md compliance)
  • Confidence: 80%
  • Location: 9 instances across 4 files

CLAUDE.md documents Finding.create_pass()/Finding.create_fail() but all new Go code uses the raw constructor. Functionally correct but inconsistent with docs. Note: existing code has the same
inconsistency, so this is a codebase-wide issue.

@natifridman another round of the review from the https://github.com/ambient-code/agentready/blob/main/.claude/commands/review-agentready.md skill.

natifridman and others added 4 commits May 12, 2026 18:04
Add Go-specific assessment logic to 6 assessors that previously returned
not_applicable or used wrong language paths for Go repos. Includes monorepo
support for projects with go.mod in subdirectories (e.g., multi-service repos).

Assessors extended:
- TestExecutionAssessor: *_test.go detection, go test/coverage/race scoring
- TypeAnnotationsAssessor: auto-pass for static typing, interface{}/any penalty
- StandardLayoutAssessor: Go layout detection (go.mod, cmd/, internal/, pkg/)
- CyclomaticComplexityAssessor: gocyclo + golangci-lint cyclop detection
- StructuredLoggingAssessor: zap/logrus/zerolog/slog in go.mod and source
- InlineDocumentationAssessor: godoc comment coverage on exported symbols

Infrastructure:
- BaseAssessor._primary_language(): dispatches by file count for multi-lang repos
- BaseAssessor._find_go_module_roots(): finds go.mod at root and in subdirs
- Go.arsrc: directory exclusion list for Go projects
- Bootstrap templates updated to Go 1.23/1.24, golangci-lint-action v6, govulncheck
- go vet added to CI typecheck patterns, enhanced gitignore patterns

Tested against opendatahub-io/models-as-a-service (Go monorepo): score improved
from 40.9 to 59.6 (+18.7 points) with 6 previously-failing assessors now passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When file counts between two languages are within 30% of each other,
use root-level project manifests (go.mod, pyproject.toml, package.json)
as a tiebreaker to determine the primary language. This fixes repos like
Go Kubernetes operators with Python SDK subdirectories, where Python may
have slightly more files but Go owns the project root.

Tested against opendatahub-io/kserve (524 Go vs 597 Python files):
Go assessors now correctly fire instead of Python ones (+8.6 points).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes 9 of 10 CodeRabbit review findings:

1. _primary_language(): deterministic tiebreaker — only returns a winner
   when exactly one language has a root manifest match
2. _find_go_module_roots(): use rglob for recursive search, exclude
   vendor/testdata, deduplicate and sort results
3. CyclomaticComplexityAssessor: remove unsafe fallback that assumed
   golangci-lint default linters without parsing config
4. InlineDocumentationAssessor: fix godoc pattern to capture exported
   methods with receivers (func (s *Server) Start()); require doc
   comments to start with "// SymbolName" per Go convention
5. StandardLayoutAssessor: use _primary_language() dispatch instead of
   bare "Go" in repository.languages check
6. DependencyPinningAssessor: use rglob for go.sum search with vendor
   exclusion, find all matches (not just first)
7. TestExecutionAssessor: coverage regex now matches plain -cover flag
   in addition to -coverprofile/-covermode
8. TestExecutionAssessor: use _find_go_module_roots() for build file
   scanning instead of one-level glob
9. Bootstrap template: pin govulncheck to v1.3.0 instead of @latest

Skipped ambient-code#10 (pin golangci-lint version: latest): intentional for
bootstrap templates — golangci-lint-action@v6 documents this pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix multi-line godoc detection: walk back through consecutive //
  comment lines and check first line; support /* */ block comments
- Relax godoc check to match go doc behavior: any comment immediately
  preceding a symbol counts as documentation (not just // SymbolName)
- Strip comments AND string literals before matching \bany\b to avoid
  false positives in type_annotations assessor
- Recognize $(GO) test and make test in CI quality gates and test
  execution assessors
- Make _primary_language() max() deterministic with alphabetical
  tie-breaking
- Upgrade golangci-lint-action@v6 to @v9 in bootstrap template
- Remove dead Go.arsrc file (never loaded)
- Add 12 new tests covering all fixes

Real-world validation:
  gin-gonic/gin:    48.3 → 51.9 (test_execution FAIL→PASS, CI gates 75→85)
  cli/cli:          60.6 → 61.3 (inline_docs 14.8%→31.1%)
  models-as-a-service: 58.8 → 59.6 (stable, no regressions)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
src/agentready/templates/bootstrap/go/workflows/tests.yml.j2 (1)

34-34: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

version: latest remains unpinned.

This reproduces the prior review finding: using latest makes CI nondeterministic and can break generated repositories when upstream releases change. Pin to a specific version.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/agentready/templates/bootstrap/go/workflows/tests.yml.j2` at line 34,
Replace the unpinned YAML key "version: latest" with a fixed, specific version
string (for example "version: 1.2.3") or a project-configured pinned variable so
the generated CI workflow is deterministic; update the
templates/bootstrap/go/workflows/tests.yml.j2 occurrence of "version: latest" to
the chosen pinned semver value or template variable that references a tested
release.
src/agentready/assessors/code_quality.py (1)

590-618: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

The golangci fallback still false-passes disabled complexity linters.

This returns pass if gocyclo, cyclop, or gocognit appears anywhere in the config text, including disable: blocks, comments, or examples. That overstates complexity enforcement and masks missing tooling.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/agentready/assessors/code_quality.py` around lines 590 - 618, The current
fallback in code_quality.py incorrectly flags complexity linters by regex
matching anywhere in config text (variables: config_path, content,
has_complexity) which also matches commented or disabled entries; replace the
blunt regex check with proper parsing: when config_name ends with .yaml/.yml use
a YAML parser (safe_load) and when .toml use a TOML parser (toml.loads), then
inspect the parsed structure for golangci-lint linter configuration keys (e.g.,
top-level "linters", "linters-settings", or "linters.enable"/"linters.disable",
and "enable"/"disable") to determine if gocyclo/cyclop/gocognit are actually
enabled (ensure they are present in enable lists or absent from disable lists),
and only set has_complexity=true and return the Finding when the parsed config
indicates the complexity linters are enabled; keep existing error handling
around config_path.read_text and parsing failures.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/agentready/assessors/base.py`:
- Around line 103-125: The current tie-break uses max(lang_counts, key=lambda k:
(lang_counts[k], k)) which selects the reverse-lexicographic language on equal
counts; change the logic to first compute top_count = max(lang_counts.values())
and then build the top candidates list = [lang for lang, c in
lang_counts.items() if c == top_count] and set top_lang =
sorted(top_candidates)[0] (i.e., pick the alphabetically first) so equal-count
ties choose the earliest alphabetical language; keep the subsequent close_langs,
manifest_winners, _LANG_ROOT_MANIFESTS and repository.path checks intact so the
70% manifest logic still applies.

In `@src/agentready/assessors/documentation.py`:
- Around line 1200-1214: The current logic walks past empty lines so a comment
separated by blank lines (e.g. "// comment\n\nfunc Exported()") is treated as
attached; change the behavior so a blank line immediately before the symbol
disqualifies documentation. Remove the while loop that decrements prev_idx over
empty lines and instead set prev_idx = symbol_idx - 1, immediately check if
prev_idx < 0 or if lines[prev_idx].strip() == "" then return False; otherwise
proceed to set prev_line = lines[prev_idx].strip() and keep the existing checks
for prev_line.startswith("//") and prev_line.endswith("*/") in the functions
using symbol_idx, prev_idx, lines, and prev_line.

---

Duplicate comments:
In `@src/agentready/assessors/code_quality.py`:
- Around line 590-618: The current fallback in code_quality.py incorrectly flags
complexity linters by regex matching anywhere in config text (variables:
config_path, content, has_complexity) which also matches commented or disabled
entries; replace the blunt regex check with proper parsing: when config_name
ends with .yaml/.yml use a YAML parser (safe_load) and when .toml use a TOML
parser (toml.loads), then inspect the parsed structure for golangci-lint linter
configuration keys (e.g., top-level "linters", "linters-settings", or
"linters.enable"/"linters.disable", and "enable"/"disable") to determine if
gocyclo/cyclop/gocognit are actually enabled (ensure they are present in enable
lists or absent from disable lists), and only set has_complexity=true and return
the Finding when the parsed config indicates the complexity linters are enabled;
keep existing error handling around config_path.read_text and parsing failures.

In `@src/agentready/templates/bootstrap/go/workflows/tests.yml.j2`:
- Line 34: Replace the unpinned YAML key "version: latest" with a fixed,
specific version string (for example "version: 1.2.3") or a project-configured
pinned variable so the generated CI workflow is deterministic; update the
templates/bootstrap/go/workflows/tests.yml.j2 occurrence of "version: latest" to
the chosen pinned semver value or template variable that references a tested
release.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 06d4b4ec-3c6d-433d-bc09-6dbc908742ad

📥 Commits

Reviewing files that changed from the base of the PR and between bd5a68d and bd4b891.

📒 Files selected for processing (9)
  • src/agentready/assessors/base.py
  • src/agentready/assessors/code_quality.py
  • src/agentready/assessors/documentation.py
  • src/agentready/assessors/structure.py
  • src/agentready/assessors/stub_assessors.py
  • src/agentready/assessors/testing.py
  • src/agentready/templates/bootstrap/go/workflows/security.yml.j2
  • src/agentready/templates/bootstrap/go/workflows/tests.yml.j2
  • tests/unit/test_assessors_go.py

Comment on lines +103 to +125
top_lang = max(lang_counts, key=lambda k: (lang_counts[k], k))
top_count = lang_counts[top_lang]

if top_count == 0:
return None

# Check if any other candidate is close enough to contest
close_langs = {
lang for lang, count in lang_counts.items() if count >= top_count * 0.7
}
if len(close_langs) > 1:
manifest_winners = [
lang
for lang in sorted(close_langs)
if any(
(repository.path / m).exists()
for m in self._LANG_ROOT_MANIFESTS.get(lang, [])
)
]
if len(manifest_winners) == 1:
return manifest_winners[0]

return top_lang
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
sed -n '95,125p' src/agentready/assessors/base.py
python - <<'PY'
lang_counts = {"Go": 10, "Python": 10, "TypeScript": 10}
current = max(lang_counts, key=lambda k: (lang_counts[k], k))
expected = min(lang_counts, key=lambda k: (-lang_counts[k], k))
print({"current": current, "expected": expected})
PY

Repository: ambient-code/agentready

Length of output: 1110


🏁 Script executed:

# Check if there are tests for the _primary_language method
find . -name "*.py" -type f | xargs grep -l "_primary_language\|lang_counts" | head -20

Repository: ambient-code/agentready

Length of output: 295


🏁 Script executed:

# Look for any documentation or comments about language precedence
rg -A5 -B5 "_primary_language|LANG_ROOT_MANIFESTS" --type py

Repository: ambient-code/agentready

Length of output: 8314


🏁 Script executed:

# Check if there are any existing tests for tie scenarios
find . -name "*test*.py" -o -name "test_*.py" | xargs grep -l "primary_language\|lang_counts" 2>/dev/null

Repository: ambient-code/agentready

Length of output: 209


🏁 Script executed:

# Check the test that uses _primary_language to understand expected behavior
sed -n '1,50p' tests/unit/test_fixers.py | head -100

Repository: ambient-code/agentready

Length of output: 1454


🏁 Script executed:

# Search for any test of _primary_language itself
rg -A20 "test_generate_fix_uses_primary_language" tests/

Repository: ambient-code/agentready

Length of output: 1367


🏁 Script executed:

# Check if there are any unit tests specifically for _primary_language
find . -name "*.py" -path "*/tests/*" -exec grep -l "_primary_language" {} \;

Repository: ambient-code/agentready

Length of output: 95


🏁 Script executed:

# Get the full test_generate_fix_uses_primary_language test
rg -A50 "def test_generate_fix_uses_primary_language" tests/unit/test_fixers.py

Repository: ambient-code/agentready

Length of output: 1846


🏁 Script executed:

# Check if there are any unit tests for BaseAssessor._primary_language itself
rg -B5 -A30 "_primary_language" tests/ --type py

Repository: ambient-code/agentready

Length of output: 2198


🏁 Script executed:

# Check the base.py implementation more completely to understand the fallback behavior
sed -n '90,145p' src/agentready/assessors/base.py

Repository: ambient-code/agentready

Length of output: 2058


🏁 Script executed:

# Test what happens with an exact tie scenario - verify the exact behavior
python3 <<'PY'
# Simulate the scenario with exact tie and no clear manifest winner
lang_counts = {"Go": 10, "Python": 10, "TypeScript": 10}
close_langs = {lang for lang, count in lang_counts.items() if count >= 10 * 0.7}
print("Close languages (within 70%):", sorted(close_langs))
print("Current max() selection:", max(lang_counts, key=lambda k: (lang_counts[k], k)))
print("Expected first alphabetical:", min(lang_counts, key=lambda k: (-lang_counts[k], k)))

# Now show the lexicographic ordering behavior
keys = list(lang_counts.keys())
print("\nLexicographic ordering of language names:")
for lang in sorted(keys, reverse=True):
    print(f"  {lang}")
PY

Repository: ambient-code/agentready

Length of output: 266


Exact-count ties still select the reverse alphabetical language.

On line 103, max(lang_counts, key=lambda k: (lang_counts[k], k)) uses reverse lexicographic ordering for ties. When counts are equal (e.g., Go: 10, Python: 10, TypeScript: 10), this picks TypeScript instead of Go. The 70% manifest check mitigates this in many cases, but fails when zero or multiple manifest files exist, falling back to the wrong language for assessment dispatch.

Fix
-        top_lang = max(lang_counts, key=lambda k: (lang_counts[k], k))
+        top_lang = min(lang_counts, key=lambda k: (-lang_counts[k], k))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/agentready/assessors/base.py` around lines 103 - 125, The current
tie-break uses max(lang_counts, key=lambda k: (lang_counts[k], k)) which selects
the reverse-lexicographic language on equal counts; change the logic to first
compute top_count = max(lang_counts.values()) and then build the top candidates
list = [lang for lang, c in lang_counts.items() if c == top_count] and set
top_lang = sorted(top_candidates)[0] (i.e., pick the alphabetically first) so
equal-count ties choose the earliest alphabetical language; keep the subsequent
close_langs, manifest_winners, _LANG_ROOT_MANIFESTS and repository.path checks
intact so the 70% manifest logic still applies.

Comment on lines +1200 to +1214
prev_idx = symbol_idx - 1
while prev_idx >= 0 and not lines[prev_idx].strip():
prev_idx -= 1
if prev_idx < 0:
return False

prev_line = lines[prev_idx].strip()

if prev_line.startswith("//"):
return True

if prev_line.endswith("*/"):
return True

return False
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Blank lines are still being treated as part of a Go doc comment.

This walks past empty lines, so // comment\n\nfunc Exported() is counted as documented. That inflates godoc coverage even though the comment is not immediately attached to the declaration.

Suggested fix
-        prev_idx = symbol_idx - 1
-        while prev_idx >= 0 and not lines[prev_idx].strip():
-            prev_idx -= 1
-        if prev_idx < 0:
+        prev_idx = symbol_idx - 1
+        if prev_idx < 0 or not lines[prev_idx].strip():
             return False
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/agentready/assessors/documentation.py` around lines 1200 - 1214, The
current logic walks past empty lines so a comment separated by blank lines (e.g.
"// comment\n\nfunc Exported()") is treated as attached; change the behavior so
a blank line immediately before the symbol disqualifies documentation. Remove
the while loop that decrements prev_idx over empty lines and instead set
prev_idx = symbol_idx - 1, immediately check if prev_idx < 0 or if
lines[prev_idx].strip() == "" then return False; otherwise proceed to set
prev_line = lines[prev_idx].strip() and keep the existing checks for
prev_line.startswith("//") and prev_line.endswith("*/") in the functions using
symbol_idx, prev_idx, lines, and prev_line.

@dhshah13
Copy link
Copy Markdown

Thank you, guys, for addressing issue #378. Looking forward to an improved score.

@natifridman
Copy link
Copy Markdown
Contributor Author

🤖 AgentReady Code Review

PR Status: 6 issues found (2 🔴 Critical, 4 🟡 Major)
Score Impact: Current 80.0/100 → 80.0 (no self-score change; issues affect Go repo assessments)
Certification: Gold (unchanged for agentready self-assessment)
CI Status: All checks passing ✅


🔴 Critical Issues (Confidence ≥90) — Assessment Accuracy

1. Godoc blank-line skip contradicts Go doc convention

Attribute: 2.2 Inline Documentation (Tier 2, 3%)
Confidence: 92%
Score Impact: Inflates godoc coverage for Go repos (false positive)
Location: src/agentready/assessors/documentation.py#L1204-L1206

Issue: The docstring says "no blank line between" but the while loop at L1205 skips blank lines between the comment and the declaration. Go's go doc convention requires the doc comment to be immediately preceding — any blank line separates it. This causes comments far above a symbol to be incorrectly counted as doc comments.

# Current (incorrect): skips blank lines
prev_idx = symbol_idx - 1
while prev_idx >= 0 and not lines[prev_idx].strip():
    prev_idx -= 1

Remediation:

# Fix: blank line breaks the association
prev_idx = symbol_idx - 1
if prev_idx < 0 or not lines[prev_idx].strip():
    return False

2. golangci-lint config detection matches disabled linters

Attribute: 3.1 Cyclomatic Complexity (Tier 3, 2%)
Confidence: 90%
Score Impact: False pass for repos that explicitly disable complexity linters
Location: src/agentready/assessors/code_quality.py#L603-L605

Issue: The regex \b(gocyclo|cyclop|gocognit)\b matches the linter name anywhere in the config — including disable: blocks, disable-all: true contexts, and YAML comments. A config that explicitly disables gocyclo would still get a passing score of 80.

This was flagged in both CodeRabbit reviews and remains unaddressed.

Remediation:

# Parse the config properly to check enable/disable state
# For YAML configs: check linters.enable contains the linter
# For TOML configs: check [linters] enable list

🟡 Major Issues (Confidence 80-89) — Manual Review Required

3. Bootstrap template uses version: latest for golangci-lint

Attribute: 16.2 CI Quality Gates (Tier 1, 5%)
Confidence: 85%
Score Impact: −0 (affects generated repos, not self-score)
Location: src/agentready/templates/bootstrap/go/workflows/tests.yml.j2#L34

Issue: version: latest makes generated CI non-deterministic. The action was upgraded from @v6 to @v9 in the latest commit, but version: latest was retained. Similarly, securego/gosec@master in security.yml.j2#L20 pins to @master instead of a tagged release.

Remediation: Pin both to specific versions or use a template variable.


4. Unrelated weight changes bundled into Go support PR

Attribute: N/A (process/scope concern)
Confidence: 85%
Score Impact: ±2-3 points for existing Python/JS repos
Location: src/agentready/data/default-weights.yaml, src/agentready/assessors/__init__.py

Issue: This PR includes several changes beyond Go support that are not mentioned in the PR description:

  • cyclomatic_complexity weight: 3% → 2%
  • structured_logging weight: 3% → 2%
  • IssuePRTemplatesAssessor moved from Tier 3 to Tier 4 (3% → 1%)
  • DependencyPinningAssessor.default_weight: 0.10 → 0.05
  • separation_concerns renamed to separation_of_concerns
  • repomix_config attribute added (2%)

These rebalance scoring for all repos, not just Go. The dependency pinning weight halved silently.

Remediation: Either split these changes into a separate PR or document them in the PR description with before/after score comparisons.


5. Exported symbol regex misses grouped declarations

Attribute: 2.2 Inline Documentation (Tier 2, 3%)
Confidence: 82%
Score Impact: Under-counts exported symbols (false negative, partially offsetting issue #1)
Location: src/agentready/assessors/documentation.py#L1255-L1257

Issue: The regex ^(?:func\s+(?:\([^)]+\)\s+)?|type\s+|var\s+|const\s+)([A-Z]\w*) only matches the keyword at the start of a line. Go's grouped const/var blocks put exported names without a keyword prefix:

const (
    A = 1    // matched (has "const ")
    B = 2    // MISSED (no keyword prefix)
)

This under-counts total exported symbols, which could mask low documentation coverage.


6. Primary language tiebreaker could misclassify mixed repos

Attribute: 4.1 Standard Layout (Tier 1, 5%)
Confidence: 80%
Score Impact: Could route wrong assessor in mixed Go/Python repos
Location: src/agentready/assessors/base.py#L110-L123

Issue: The 70% threshold means a repo with Python=75 files and Go=55 files triggers the manifest tiebreaker (55 ≥ 75×0.7=52.5). If go.mod exists at root but pyproject.toml is in a subdirectory (common in Kubernetes operators with Python SDKs), Go wins despite Python having more files. This skips the Python assessment path entirely.

The manifest_winners logic correctly returns only if exactly 1 winner, but when both languages have root manifests, it falls back to top_lang (the higher count), which is the expected behavior. Partially mitigated but edge cases exist when only Go has a root manifest.


Summary

Category Count Score Impact
🔴 Critical (auto-fix recommended) 2 Inflated Go godoc + complexity scores
🟡 Major (manual review) 4 Weight rebalancing affects all repos
Total 6

🤖 Generated with Claude Code

- If this review was useful, react with 👍. Otherwise, react with 👎.

Copy link
Copy Markdown
Contributor

@jwm4 jwm4 left a comment

Choose a reason for hiding this comment

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

🤖 Follow-up: Re-validation after 72d8e81

The new commit addresses every issue raised in our review (and kami619's). We re-ran against the same four repositories to verify.

Repo Before After Key changes
gin-gonic/gin 48.3 Bronze 52.5 Bronze test_execution fail→pass, inline_documentation fail→pass
cli/cli 60.6 Silver 60.9 Silver inline_documentation 14.8%→38.8%
prometheus/prometheus 63.9 Silver 65.1 Silver type_annotations 85→95, inline_documentation 42→64
models-as-a-service 58.8 Bronze 59.5 Bronze stable, no regressions

All fixes confirmed working. The inline_documentation score for cli/cli is still a fail at 38.8%, but that now reflects genuine documentation gaps in the repo rather than a measurement bug — which is the right outcome.

No new issues found. This looks ready to merge.

This review was generated by Claude Code under the supervision of Bill Murdock.

@jwm4 jwm4 merged commit c32d9c8 into ambient-code:main May 12, 2026
13 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 2.36.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants