Skip to content

Go cleanup: dead code, pattern fixes, dedup, CI#7

Merged
nickna merged 6 commits into
mainfrom
chore/go-cleanup
Jun 10, 2026
Merged

Go cleanup: dead code, pattern fixes, dedup, CI#7
nickna merged 6 commits into
mainfrom
chore/go-cleanup

Conversation

@nickna

@nickna nickna commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Codebase-wide Go cleanup from a deadcode/staticcheck/manual sweep. Net −539 lines across 52 files. Four commits, ordered by risk:

1. Dead code deletion (c9bd201, −599 lines)

Everything verified unreachable from all cmd/ entry points with GOOS=linux deadcode (Linux tags matter — on Windows the carbonyl runner's callers are invisible and false-positive):

  • tui/components: BrailleCanvas widget (never wired up), FlipAnimation + RenderFlipEdge (Deal/Pulse/CoinShower remain in use)
  • tui/theme: BlendHex + hex-math helpers
  • imaging/graphics: kitty/sixel/iterm2 encoders and Encode/EncodeWithFallback. Detect/Protocol stay (tested, plumbed through transport) — but note the detected protocol is currently a write-only session field; nothing reads it.
  • doors/roulette: Payout (superseded by GrossReturn, which the coordinator uses)
  • doors/roulette/multiplayer: the Registry's ctx/cancel/Stop machinery. Its doc comment prescribed a Stop()-after-Persist shutdown ordering it could never deliver (the internal context derived from main's signal context, and reg.ctx was unexported so main couldn't follow the prescribed pattern anyway). Removed; the Run context the caller passes is the real lifecycle, and the refund hook covers in-flight bets.
  • auth: NoopRateLimiter (zero refs, even tests), DefaultRateLimitParams, unused dummyAlgo field, dead _ = pgx.ErrNoRows placeholder
  • transport: unused Server.ListenAndServe (main serves via the netlimit-wrapped listener)
  • web: requireQueries, the requestExt type, OAuthProviders.Has
  • misc: chatTypingStyle, the unused stubRecorder test helper

2. Pattern fixes (b45e430)

  • renderProfile header ordering: handlers called w.WriteHeader() before renderProfile, whose later Content-Type set was a silent no-op — error re-renders shipped without a charset. renderProfile now takes the status and owns the full Content-Type → WriteHeader → execute sequence; all call sites across profile/boards/chat/weather/avatar updated (boards' new-topic re-render had the same bug).
  • Session ctx convention: Root.fetchStatusTempCmd used context.Background(); now sess.CtxWithTimeout(5s) so the status-bar weather fetch cancels on SSH disconnect.
  • VerifyDummy recursion footgun: it round-tripped through Verify, whose unknown-format branch calls VerifyDummy — a dummy hash that ever lost its PHC prefix would recurse forever. Now calls verifyPHC directly.
  • staticcheck nits: S1039, S1001, ST1005 ×2.

3. Duplication consolidation (a2aa852)

  • New providers/httpjson: one GET-and-decode helper replacing ~10 hand-rolled copies (hackernews, lobsters, coingecko ×2, yahoo, frankfurter, open-meteo, nws, geocoding). Non-200 yields a typed *StatusError with a body snippet; providers keep their error prefixes by wrapping and preserve their 429 special-cases via errors.As.
  • finance/news: hand-rolled rssCacheEntry mutex cache → ttlcache.Cache (same TTL + stale-on-error, gains singleflight).
  • New web/cookies.go: secureCookie/expiredCookie centralize the Path/HttpOnly/SameSite/Secure attribute set used by all five cookie sites.
  • web/handlers_oauth: extracted sealTokenFields from the near-identical insert/upsert token writes.
  • tui/screens/chat: extracted seedChannelLog from the bootstrap/refan/local-switch handlers; the PFP-before-AppendAll ordering constraint now lives in one place, and the local-switch nil-reactions guard is preserved via an explicit flag.
  • tui/screens: truncateArea/truncateRow folded into format.go (truncateRunes is the rune-aware variant; byte-based truncateRow was truncate with a worse n≤1 edge that could split a rune); handToStrings/handStrings unified.

4. CI + line endings (3add895)

  • .github/workflows/ci.yml: build/vet/test/gofmt/staticcheck/deadcode on every push + PR. Linux runner is load-bearing (carbonyl build tags). No LFS checkout — the bundle is only needed by deploy.yml's docker build.
  • .gitattributes: *.go text eol=lf so Windows checkouts stop making gofmt -l flag every file. All 273 .go files already store LF in the index, so no renormalization churn.

Deliberately not changed

  • HTTP server ReadTimeout/WriteTimeout: /ws/bbs is a long-lived hijacked connection and the deadline interaction needs investigation first; Cloudflare fronts the HTTP surface meanwhile.
  • audit.NoopRecorder: test-covered nil-object of the Recorder interface (unlike the truly orphaned NoopRateLimiter).

Verification

go build, go vet, full go test ./..., GOOS=linux go build, and GOOS=linux staticcheck ./... all clean at every commit boundary.

nickna added 6 commits June 9, 2026 18:42
Verified unreachable from all cmd/ entry points (GOOS=linux to keep the
carbonyl runner's build-tagged callers visible):

- tui/components: BrailleCanvas widget (never wired up), FlipAnimation +
  RenderFlipEdge (DealAnimation/Pulse/CoinShower remain in use)
- tui/theme: BlendHex and its hex-math helpers
- imaging/graphics: kitty/iterm2/sixel encoders and Encode/EncodeWithFallback
  (protocol Detect stays - transport still records the detected protocol)
- doors/roulette: Payout (superseded by GrossReturn, which the coordinator
  uses); test pins GrossReturn cases only now
- doors/roulette/multiplayer: Registry ctx/cancel/Stop - main runs the
  coordinator on the signal context directly, so the registry-owned
  lifecycle was vestigial; NewRegistry loses its ctx param
- auth: NoopRateLimiter, DefaultRateLimitParams, unused dummyAlgo field,
  dead pgx.ErrNoRows placeholder in classifyInsertError
- transport: unused Server.ListenAndServe (main serves via the
  netlimit-wrapped listener)
- web: requireQueries, requestExt type, OAuthProviders.Has
- tui/screens: unused chatTypingStyle
- security/audit: unused stubRecorder test helper
- web: renderProfile now takes the status code and owns the full header
  sequence (Content-Type before WriteHeader). Three handlers previously
  called WriteHeader before renderProfile, which made the later
  Content-Type set a silent no-op, serving error re-renders without a
  charset. All call sites across profile/boards/chat/weather/avatar
  handlers updated; boards' new-topic re-render had the same bug.
- tui: Root.fetchStatusTempCmd uses sess.CtxWithTimeout instead of
  context.Background so the status-bar weather fetch cancels on SSH
  disconnect, per the session package's own convention.
- auth: VerifyDummy evaluates verifyPHC directly instead of recursing
  through Verify, whose unknown-format branch calls VerifyDummy - a
  dummyHash without the PHC prefix would have recursed forever.
- staticcheck style nits: drop arg-less fmt.Sprintf in chat helpText
  (S1039), use copy() for the palette16 prefix in ansiconvert (S1001),
  reword finance resolver error strings to not end in ':' (ST1005).
…eens

- providers/httpjson (new): the one GET-and-decode helper shared by the
  JSON providers. Owns request-with-context, header set, 200 check (non-200
  yields a typed *StatusError carrying a body snippet), and decode. Callers
  keep their provider-prefixed errors by wrapping, and special-case upstream
  statuses via errors.As (CoinGecko/Yahoo 429 messages preserved). Converts
  ~10 hand-rolled copies across hackernews, lobsters, coingecko, yahoo,
  frankfurter, open-meteo, nws, and geocoding.
- finance/news: replace the hand-rolled rssCacheEntry mutex cache with
  ttlcache.Cache[string, []Headline] (same TTL, adds singleflight; stale-
  on-error behavior preserved via ttlcache.StaleOnError).
- web/cookies.go (new): secureCookie/expiredCookie constructors centralize
  the Path/HttpOnly/SameSite/Secure attribute set used by all five cookie
  sites (session mint+clear, oauth state, flash).
- web/handlers_oauth: extract sealTokenFields, the serialization step the
  near-identical insert/upsert token writes shared.
- tui/screens/chat: extract seedChannelLog for the log-init sequence the
  bootstrap/refan/local-switch handlers each repeated; the PFP-before-
  AppendAll ordering constraint now lives in one place.
- tui/screens: fold truncateArea/truncateRow into format.go - truncateRunes
  is the rune-aware variant, byte-based truncateRow was truncate with a
  worse n<=1 edge (could split a rune); unify handToStrings/handStrings
  into one slice-based helper in format.go.
- .github/workflows/ci.yml: build, vet, test, gofmt, staticcheck, and
  deadcode on every push/PR. Linux runner is load-bearing - the carbonyl
  runner is //go:build linux, so any other GOOS false-positives its
  helpers as dead. deadcode always exits 0, so the step fails on output
  (allowing the test-covered NoopRecorder noop). No LFS checkout; the
  Carbonyl bundle is only needed by deploy.yml's docker build.
- .gitattributes: force LF for *.go / go.mod / go.sum so Windows
  checkouts under autocrlf stop making gofmt -l flag every file. All
  273 .go files already store LF in the index, so this only affects
  fresh checkouts - no renormalization commit needed.
@nickna nickna merged commit 2e5f141 into main Jun 10, 2026
1 check passed
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.

1 participant