refactor: harden backend per spec/backend-hardening #6

Merged
dries merged 1 commit from chore-backend into main 2026-05-05 02:17:17 +02:00
Owner

Summary

Risk-reduction pass on the Go backend: focused tests, observability,
and panic safety for the high-risk modules identified in the codebase
analysis. No user-visible behaviour change except the metrics
dashboard's session/project log, which now sorts by cost descending
(was: most-recent activity first) so the most expensive entries
surface first.

Per-package coverage lift:

  • internal/pricing: 0% → 80.0%
  • internal/server: 48.4% → 57.3%
  • internal/platforms/opencode: 57.6% → 71.3%

Notable changes:

  • pricing.Lookup matcher: longest-prefix-then-contains (was
    bidirectional strings.Contains, which made "gpt-4" match
    "gpt-4o"); fetch failures now log WARN.
  • whisper.go: extracted executor + fileStat interfaces so
    transcribe is unit-testable without whisper/ffmpeg installed.
  • dispatchSessionSubpath: 110-line nested switch replaced by a
    declarative sessionSubRoutes table; 404 body includes the
    offending path.
  • Auto-archive + projects-index loops wrap each tick in
    runWithRecover so a panicking iteration logs at ERROR and the
    loop survives.
  • OpenCode adapter: WARN on AgentCatalog/SlashCommands upstream
    failure (was silent (nil, nil)); DEBUG line summarising skipped
    messages in convertOpenCodeMessages; RWMutex around
    discoverPortsImpl and pending-prompts cache so test seam swaps
    are race-safe; new httptest-backed opencodeFake exercises
    fetchSessionFromOpenCodeCtx end-to-end.
  • GetMetricsDashboard: 11 positional params → single
    MetricsDashboardOptions struct; Sessions/Projects sort by Cost
    desc, ties break by recency.
  • New FuzzConvertOpenCodeMessages with seed corpus.
  • New Makefile targets: test-race, test-fuzz, test-coverage, help.

See spec/backend-hardening/{requirements,architecture}.md for the
full design.

Testing

  • make test, make test-race, make test-coverage — green
  • make test-fuzz — 10s no panics
  • go vet, platform-branching guard — clean
## Summary Risk-reduction pass on the Go backend: focused tests, observability, and panic safety for the high-risk modules identified in the codebase analysis. No user-visible behaviour change except the metrics dashboard's session/project log, which now sorts by cost descending (was: most-recent activity first) so the most expensive entries surface first. Per-package coverage lift: - `internal/pricing`: 0% → **80.0%** - `internal/server`: 48.4% → **57.3%** - `internal/platforms/opencode`: 57.6% → **71.3%** Notable changes: - `pricing.Lookup` matcher: longest-prefix-then-contains (was bidirectional `strings.Contains`, which made `"gpt-4"` match `"gpt-4o"`); fetch failures now log WARN. - `whisper.go`: extracted `executor` + `fileStat` interfaces so transcribe is unit-testable without whisper/ffmpeg installed. - `dispatchSessionSubpath`: 110-line nested switch replaced by a declarative `sessionSubRoutes` table; 404 body includes the offending path. - Auto-archive + projects-index loops wrap each tick in `runWithRecover` so a panicking iteration logs at ERROR and the loop survives. - OpenCode adapter: WARN on AgentCatalog/SlashCommands upstream failure (was silent `(nil, nil)`); DEBUG line summarising skipped messages in `convertOpenCodeMessages`; RWMutex around `discoverPortsImpl` and pending-prompts cache so test seam swaps are race-safe; new httptest-backed `opencodeFake` exercises `fetchSessionFromOpenCodeCtx` end-to-end. - `GetMetricsDashboard`: 11 positional params → single `MetricsDashboardOptions` struct; Sessions/Projects sort by Cost desc, ties break by recency. - New `FuzzConvertOpenCodeMessages` with seed corpus. - New Makefile targets: `test-race`, `test-fuzz`, `test-coverage`, `help`. See `spec/backend-hardening/{requirements,architecture}.md` for the full design. ## Testing - `make test`, `make test-race`, `make test-coverage` — green - `make test-fuzz` — 10s no panics - `go vet`, platform-branching guard — clean
refactor: harden backend per spec/backend-hardening
All checks were successful
CI / Frontend (pull_request) Successful in 1m33s
CI / Backend (pull_request) Successful in 2m38s
CI / Playwright E2E (pull_request) Successful in 3m18s
CI / Build (pull_request) Successful in 1m48s
CI / Semantic Tag (pull_request) Has been skipped
CI / Frontend (push) Successful in 1m31s
CI / Backend (push) Successful in 2m41s
CI / Playwright E2E (push) Successful in 4m0s
CI / Build (push) Successful in 1m58s
CI / Semantic Tag (push) Successful in 4s
Release / Build Frontend (push) Successful in 31s
Release / Build darwin/amd64 (push) Successful in 1m59s
Release / Build darwin/arm64 (push) Successful in 2m9s
Release / Build linux/amd64 (push) Successful in 2m40s
Release / Build linux/arm64 (push) Successful in 1m15s
Release / Publish Release (push) Successful in 16s
22f1a04776
Add focused tests, observability, and panic safety to the high-risk
backend modules identified in the codebase analysis. No user-visible
behaviour changes except the metrics dashboard's session/project log,
which now sorts by cost descending (was: most-recent activity first)
so the most expensive entries surface first.

Test coverage rises in the two worst-covered packages:
  internal/server          48.4% → 57.3%  (target ≥55%)
  internal/platforms/opencode 57.6% → 71.3%  (target ≥70%)
  internal/pricing          0%   → 80.0%   (target ≥80%)

Notable changes:

  - internal/pricing: extract New(client, url) constructor; replace
    bidirectional strings.Contains matcher with longest-prefix-then-
    contains so "gpt-4" no longer accidentally matches "gpt-4o";
    log a WARN on fetch failure (was silent zero-cost).
  - internal/server/whisper.go: extract executor + fileStat
    interfaces so transcribe can be unit-tested without whisper /
    ffmpeg installed.
  - internal/server/handlers.go: replace the 110-line nested switch
    in dispatchSessionSubpath with a sessionSubRoutes table + small
    pattern matcher; 404 body now includes the offending path.
  - internal/server/{server,projects_index}.go: wrap auto-archive
    and projects-index loop ticks in runWithRecover so a panicking
    iteration logs at ERROR and the loop survives.
  - internal/platforms/opencode: log WARN on AgentCatalog /
    SlashCommands upstream failure (was silent (nil, nil));
    log DEBUG with the per-call skipped count in
    convertOpenCodeMessages; protect discoverPortsImpl and the
    pending-prompts cache globals with an RWMutex so test seam
    swaps are race-safe; add a httptest-backed opencodeFake helper
    so the live-session pipeline (fetchSessionFromOpenCodeCtx) can
    be tested end-to-end.
  - internal/db: refactor GetMetricsDashboard's 11-parameter
    signature into MetricsDashboardOptions; sort Sessions and
    Projects by Cost desc with LastRequestTime as tie-breaker.
  - Add FuzzConvertOpenCodeMessages with a small seed corpus.
  - Makefile: add test-race, test-fuzz, test-coverage, help targets.

See spec/backend-hardening/{requirements,architecture}.md for the
full design and acceptance criteria.
dries merged commit 22f1a04776 into main 2026-05-05 02:17:17 +02:00
dries deleted branch chore-backend 2026-05-05 02:17:17 +02:00
Sign in to join this conversation.
No description provided.