You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
π§ Semantic Function Clustering Analysis β pkg/cli, pkg/colorwriter
Analyzed the precomputed package slice for this run: 392 non-test Go files (390 in pkg/cli, 2 in pkg/colorwriter), ~5,900 function declarations. Clustering was done by naming pattern + Serena symbol lookup, then each candidate was verified by reading the actual implementations.
Headline: the package is generally well-organized β the codemod_*.go family (66 files, one get*Codemod() per file) and the pkg/colorwriter build-tag pair are textbook one-file-per-feature. The real findings are concentrated in the outcome_eval_* family, plus a small set of scattered statistics/formatting helpers.
Key findings
#
Finding
Location
Severity
1
Human-comment counting loop duplicated 3Γ
outcome_eval_{issue,pr,comment}.go
High
2
Close-provenance walk duplicated 2Γ with divergent error semantics
Recommendation: extract into outcome_eval.go (which already hosts isBotUser, ghAPIGetArray, resolveItem*):
funccountHumanComments(ctx context.Context, numint, repostring, afterstring) int
with after == "" meaning "no cutoff", which covers all three call sites.
2. Duplicate: close-provenance walk, with a behavioral divergence
isClosedByBot (outcome_eval_issue.go:103) and isClosedByLifecycleBot (outcome_eval_generic.go:77) walk the same issues/{n}/events timeline backward for the most recent closed event and return isBotUser(actor.login).
They differ only in error handling β and the divergence is meaningful:
isClosedByBot returns bare bool; a fetch failure or a missing close event silently yields false β the issue is classified OutcomeRejected ("closed as not planned") when provenance was simply unavailable.
isClosedByLifecycleBot returns (bool, error); the caller maps a failure to OutcomeError with "close provenance unavailable".
The second is the correct behavior. Consolidating on it removes ~15 duplicated lines and fixes a misclassification path in evalCreateIssue.
Recommendation: delete isClosedByBot, move isClosedByLifecycleBot into outcome_eval.go, and have evalCreateIssue handle the error branch the way evalCloseSticky already does.
outcome_eval.go:608 and :623 differ only in input type β []any requiring a type assertion per element vs. []map[string]any. Bodies are otherwise line-for-line identical.
Recommendation: this is a textbook generics case, or simply have labelsToStringsFromNodes convert and delegate:
funclabelsToStringsFromNodes(nodes []any) []string {
maps:=make([]map[string]any, 0, len(nodes))
for_, n:=rangenodes {
ifm, ok:=n.(map[string]any); ok { maps=append(maps, m) }
}
returnlabelsToStringsFromMaps(maps)
}
4. Scattered statistics helpers β and an O(n2) median
Numeric/statistical helpers are spread across four unrelated files with no shared home:
outlier β pure stats in a GitHub-API evaluation file
chiSquarePValue, expectedProportions
experiments_analyze_statistics.go
domain-specific, fine where it is
safePercent is already the proven shared-helper pattern β it is imported by 5 unrelated files (deps_report.go, health_metrics.go, audit_expanded.go, audit_cross_run_render.go, experiments_analyze_statistics.go). The others have not been given the same treatment.
medianFloat (outcome_eval.go:370) additionally uses a hand-written O(n2) selection sort:
slices.Sort is O(n log n), already used elsewhere in the package, and is a one-line replacement.
Recommendation: rename audit_math_helpers.go β math_helpers.go (it is no longer audit-specific given its 5 external consumers) and move medianFloat, meanStdDevInt, and percentileInt into it. Replace the selection sort with slices.Sort.
5. Outlier: logic functions in a types file
trial_types.go is named for type declarations but holds four behavioral functions:
All four are consumed exclusively by trial_helpers.go (lines 125, 176, 195, 230) β verified, no other call sites in the package. Compare with the correctly-scoped forecast_types.go and token_usage_types.go, which contain zero functions.
Recommendation: move all four to trial_helpers.go, leaving trial_types.go as declarations only. Note sanitizeControlChars is a security control (prevents terminal escape-sequence injection from agent-controlled text) β keep its doc comment intact through the move.
6. Repetitive test-seam aliases and evaluator preamble
Ten package-level function aliases exist purely as test seams:
Some evaluators use an alias while others call ghAPIGet directly (outcome_eval_issue.go, outcome_eval_agent.go, and parts of outcome_eval_generic.go) β so the seam is inconsistently applied and a test stubbing one alias silently misses sibling code paths.
Separately, 13 evaluators across 7 files open with the same ~12-line preamble (resolveItemRepo β resolveItemNumber β build OutcomeReport β guard num == 0 || repo == ""), with the guard message drifting between "missing number or repo", "missing issue number or repo", and "missing PR number or repo".
Recommendation (lower priority, larger blast radius): replace the alias sprawl with a single injectable client value, and extract the preamble into newOutcomeReport(item, repoOverride) (OutcomeReport, bool). This is worth doing only if the outcome_eval_* family is being touched anyway.
What was checked and found clean
codemod_*.go (66 files) β exactly one get*Codemod() per file, feature-named. No consolidation warranted.
pkg/colorwriter β New/Stderr/Degrade appear twice, but as (go/redacted):build wasm variants. Correct Go idiom, not duplication.
Common utility names (pluralize, boolPtr, parseNumberFromURL, containsControlCharacters) β each defined exactly once. Already centralized.
sanitize* family β 8 functions, but each targets a genuinely different domain (shell, GHA expressions, branch names, HTTP errors, log injection). Not duplicates.
Finding 6 β only worth bundling into other outcome_eval_* work.
Analysis metadata
Files analyzed: 392 (non-test, from the precomputed run slice)
Function declarations scanned: ~5,900
Verified duplicate clusters: 3
Verified outlier/scatter findings: 3
Method: Serena semantic analysis (activate_project, symbol lookup) + naming-pattern clustering, with every reported finding confirmed by reading the implementation
π§ Semantic Function Clustering Analysis β
pkg/cli,pkg/colorwriterAnalyzed the precomputed package slice for this run: 392 non-test Go files (390 in
pkg/cli, 2 inpkg/colorwriter), ~5,900 function declarations. Clustering was done by naming pattern + Serena symbol lookup, then each candidate was verified by reading the actual implementations.Headline: the package is generally well-organized β the
codemod_*.gofamily (66 files, oneget*Codemod()per file) and thepkg/colorwriterbuild-tag pair are textbook one-file-per-feature. The real findings are concentrated in theoutcome_eval_*family, plus a small set of scattered statistics/formatting helpers.Key findings
outcome_eval_{issue,pr,comment}.gooutcome_eval_{issue,generic}.golabelsToStringsFromNodes/labelsToStringsFromMapsnear-identicaloutcome_eval.go:608,623outcome_eval.go,forecast_montecarlo.go,audit_math_helpers.gotrial_types.gotrial_types.go:43β119ghAPIGettest-seam aliasesoutcome_eval_*.gofiles1. Duplicate: human-comment counting (3 occurrences)
The same "fetch issue comments, count non-bot authors" loop appears three times:
Recommendation: extract into
outcome_eval.go(which already hostsisBotUser,ghAPIGetArray,resolveItem*):with
after == ""meaning "no cutoff", which covers all three call sites.2. Duplicate: close-provenance walk, with a behavioral divergence
isClosedByBot(outcome_eval_issue.go:103) andisClosedByLifecycleBot(outcome_eval_generic.go:77) walk the sameissues/{n}/eventstimeline backward for the most recentclosedevent and returnisBotUser(actor.login).They differ only in error handling β and the divergence is meaningful:
isClosedByBotreturns barebool; a fetch failure or a missing close event silently yieldsfalseβ the issue is classifiedOutcomeRejected("closed as not planned") when provenance was simply unavailable.isClosedByLifecycleBotreturns(bool, error); the caller maps a failure toOutcomeErrorwith"close provenance unavailable".The second is the correct behavior. Consolidating on it removes ~15 duplicated lines and fixes a misclassification path in
evalCreateIssue.Recommendation: delete
isClosedByBot, moveisClosedByLifecycleBotintooutcome_eval.go, and haveevalCreateIssuehandle the error branch the wayevalCloseStickyalready does.3. Near-duplicate: label extraction (~90% identical)
outcome_eval.go:608and:623differ only in input type β[]anyrequiring a type assertion per element vs.[]map[string]any. Bodies are otherwise line-for-line identical.Recommendation: this is a textbook generics case, or simply have
labelsToStringsFromNodesconvert and delegate:4. Scattered statistics helpers β and an O(n2) median
Numeric/statistical helpers are spread across four unrelated files with no shared home:
safePercent,formatPercent,formatPercentagePointChange,formatCountChange,formatFloatDeltaaudit_math_helpers.gomeanStdDevInt,percentileIntforecast_montecarlo.gomedianFloatoutcome_eval.gochiSquarePValue,expectedProportionsexperiments_analyze_statistics.gosafePercentis already the proven shared-helper pattern β it is imported by 5 unrelated files (deps_report.go,health_metrics.go,audit_expanded.go,audit_cross_run_render.go,experiments_analyze_statistics.go). The others have not been given the same treatment.medianFloat(outcome_eval.go:370) additionally uses a hand-written O(n2) selection sort:slices.Sortis O(n log n), already used elsewhere in the package, and is a one-line replacement.Recommendation: rename
audit_math_helpers.goβmath_helpers.go(it is no longer audit-specific given its 5 external consumers) and movemedianFloat,meanStdDevInt, andpercentileIntinto it. Replace the selection sort withslices.Sort.5. Outlier: logic functions in a types file
trial_types.gois named for type declarations but holds four behavioral functions:extractSafeOutputErrors(:43) β artifact parsingaggregateTrialResults(:70) β result aggregationsanitizeControlChars(:90) β security-relevant string sanitizationisControlRune(:117) β its predicateAll four are consumed exclusively by
trial_helpers.go(lines 125, 176, 195, 230) β verified, no other call sites in the package. Compare with the correctly-scopedforecast_types.goandtoken_usage_types.go, which contain zero functions.Recommendation: move all four to
trial_helpers.go, leavingtrial_types.goas declarations only. NotesanitizeControlCharsis a security control (prevents terminal escape-sequence injection from agent-controlled text) β keep its doc comment intact through the move.6. Repetitive test-seam aliases and evaluator preamble
Ten package-level function aliases exist purely as test seams:
Some evaluators use an alias while others call
ghAPIGetdirectly (outcome_eval_issue.go,outcome_eval_agent.go, and parts ofoutcome_eval_generic.go) β so the seam is inconsistently applied and a test stubbing one alias silently misses sibling code paths.Separately, 13 evaluators across 7 files open with the same ~12-line preamble (
resolveItemRepoβresolveItemNumberβ buildOutcomeReportβ guardnum == 0 || repo == ""), with the guard message drifting between"missing number or repo","missing issue number or repo", and"missing PR number or repo".Recommendation (lower priority, larger blast radius): replace the alias sprawl with a single injectable client value, and extract the preamble into
newOutcomeReport(item, repoOverride) (OutcomeReport, bool). This is worth doing only if theoutcome_eval_*family is being touched anyway.What was checked and found clean
codemod_*.go(66 files) β exactly oneget*Codemod()per file, feature-named. No consolidation warranted.pkg/colorwriterβNew/Stderr/Degradeappear twice, but as(go/redacted):build wasmvariants. Correct Go idiom, not duplication.pluralize,boolPtr,parseNumberFromURL,containsControlCharacters) β each defined exactly once. Already centralized.sanitize*family β 8 functions, but each targets a genuinely different domain (shell, GHA expressions, branch names, HTTP errors, log injection). Not duplicates.Suggested order of work
outcome_eval_*work.Analysis metadata
activate_project, symbol lookup) + naming-pattern clustering, with every reported finding confirmed by reading the implementation