feat(review): add REES complexity and Go/Python error-defect analyzers - #4155
Conversation
Adds two cheap, diff-hunk-only REES analyzers per the scoped-down plan for #1477: a new complexity.ts approximates cyclomatic complexity (1 + a count of if/for/while/case/catch/&&/||/?? tokens) for a newly-added function whose opening line is visible in the diff, distinct from deep-nesting.ts's brace- depth readability heuristic. error-swallow.ts is extended (rather than a new file) to also flag Go's if-err-check swallow/discard/return-nil shapes and a Python bare except naming no exception type, since both fit its existing error-handling-block model. Registered in registry.ts/types.ts/render.ts and the REES_ANALYZER_NAMES lists exactly like every sibling analyzer, gated by the existing per-repo review.enrichment toggle. Regenerates the analyzer metadata (UI docs page, .env.example block) and updates the Dockerfile's now-stale line-1 comment. Also normalizes error-swallow.ts/test.ts from pre-existing CRLF to LF line endings (unrelated to this feature, but required to keep git diff --check green once real edits touch those files).
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
gittensory-ui | 1aca8f2 | Commit Preview URL Branch Preview URL |
Jul 08 2026, 08:10 AM |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4155 +/- ##
=======================================
Coverage 93.72% 93.72%
=======================================
Files 384 384
Lines 36230 36230
Branches 13279 13279
=======================================
Hits 33955 33955
Misses 1618 1618
Partials 657 657
🚀 New features to boost your workflow:
|
|
Tip 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✅ Gittensory review result - approve/merge recommendedReview updated: 2026-07-08 08:21:12 UTC
✅ Suggested Action - Approve/Merge
Review summary Nits — 6 non-blocking
Linked issue satisfactionPartially addressed Review context
Contributor next steps
Signal definitions
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
Summary
complexityREES analyzer (review-enrichment/src/analyzers/complexity.ts): an approximate cyclomatic-complexity walker. For a newly-added function whose opening line is visible in the diff (namedfunctiondeclarations or a const/let/var-assigned arrow function — the same structural detectionsize-smell.tsuses for "big-function"), it countsif/for/while/case/catch/&&/||/??token occurrences across the function's ADDED body lines and reports1 + that count(the McCabe formula on the visible slice). This is explicitly not a whole-function true McCabe count — REES has no full-file content, only diff hunks — and is genuinely distinct fromdeep-nesting.ts(feat(enrichment): deep-nesting / arrow-anti-pattern heuristic analyzer #2030), which measures brace nesting depth (a readability smell its own header disclaims as a complexity metric), not decision-point density.error-swallowanalyzer (rather than adding a third analyzer file) with:if err != nil { ... }check (including the very common if-with-initializer formif err := f(); err != nil { ... }), reusing the exact same empty/unused-binding/return-null classification the JS/TScatchpath already has, plus apanic()exclusion mirroring the existingthrowexclusion.except:detector (flake8 E722-equivalent) — a newbare-exceptfinding kind, since catching every exception (includingSystemExit/KeyboardInterrupt) is a defect independent of the handler body.registry.ts/types.ts(BriefFindings.complexity, widenedErrorSwallowFinding.kind) andrender.ts, exactly like every sibling analyzer (floating-promise.ts/deep-nesting.tswere the primary analogues traced). Addscomplexityto bothREES_ANALYZER_NAMEScopies (src/review/enrichment-analyzer-names.tsandpackages/gittensory-engine/src/review/enrichment-analyzer-names.ts— the latter is what the engine's.gittensory.ymlreview.enrichment.*parser validates against, so a repo owner can togglecomplexitythe same way as any other analyzer).errorSwallowalready had a key, so no new entry was needed for the Go/Python extension.review-enrichment/analyzer-metadata.json,apps/gittensory-ui/src/lib/rees-analyzers.ts, the.env.examplegenerated block) vianpm run rees:metadata.review-enrichment/Dockerfile's line-1 comment, which said "analyzers add CLI tools later (feat(enrichment): static analysis + complexity analyzer (lint/semgrep over the diff) #1477)" — this PR deliberately does not add any external linter/AST-parser/CLI tool, so the comment was stale relative to what actually shipped.error-swallow.tsand its test file were already committed with CRLF line endings (confirmed viagit cat-fileon the pre-existing HEAD blob — not introduced by this PR). Since I materially edit both files here,git diff --checkfails on every added line unless the file is normalized, so I converted both to LF to match the rest of the codebase. No other CRLF files in the repo were touched.Why the cheap path, and why not duplicate churn-hotspot
Per the scoped-down plan for #1477: the original issue asked for real external linters (eslint/ruff/golangci-lint/semgrep) baked into the runtime image. This PR intentionally does not do that — REES stays no-checkout/no-external-process.
churn-hotspot.ts(#1513, already shipped) is not precedent for a broader one-time full-file fetch here: it fetches commit history metadata, which cannot exist in a diff in any form at all, so a fetch is its only option. Complexity is partially derivable from the diff text itself (the added lines are real source), so the cheap in-hunk approximation — not a full-file fetch — is the right scope, and is documented as such in the analyzer's own header comment.Scope
type(scope): short summaryConventional Commit format, for examplefix(api): restore profile access checks.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Closes #123) — a linked open issue is required for every contributor PR.Closes #1477
Validation
git diff --checknpm run actionlint(part of the fullnpm run test:cirun below; no workflow files changed)npm run typechecknpm run test:coveragelocally — full unsharded run, 1 file failed then passed in isolation (test/unit/selfhost-ai.test.ts's real-subprocess timing test — confirmed pre-existing/unrelated flake under load, not touched by this diff)npm run test:workersnpm run build:mcpnpm run test:mcp-packnpm run ui:openapi:checknpm run ui:lintnpm run ui:typechecknpm run ui:buildnpm audit --audit-level=moderate— 0 vulnerabilitiescomplexity.ts(decision-point counting, function detection, per-function partitioning of sibling functions, comment-line exclusion, the "signature not in diff" scope limit, custom threshold, findings cap) and 9 new Go/bare-except cases forerror-swallow.ts(empty/unused-binding/return-nil/propagated/logged/panicked, the nil-pointer-vs-err disambiguation, the if-with-initializer form, bare-except vs named-exception). Ran the full local gate vianpm run test:ci(green) plusreview-enrichment's own suite directly (npm run test:node, 1216/1216 passing).review-enrichment/**is not Codecov-measured (onlysrc/**/packages/gittensory-engine/src/**are, pervitest.config.ts's coverageinclude), so I additionally confirmed viacoverage/lcov.infothat the one line I added to each of the twoenrichment-analyzer-names.tscopies is 100%-line-covered by the existing tests that already import those modules.Safety
rees-analyzers.tsdocs data file is regenerated output only).UI Evidencesection — N/A, no visible UI change.CHANGELOG.mdedit.Notes
floating-promise.ts,deep-nesting.ts,error-swallow.ts,size-smell.ts, andchurn-hotspot.ts(per the issue's own guidance).