Skip to content

REF: consolidate domain logic across TUI and web - #96

Merged
merefield merged 5 commits into
mainfrom
refactor/shared-domain-projections
Nov 5, 2026
Merged

merefield merged 5 commits into
mainfrom
refactor/shared-domain-projections

Conversation

@merefield

@merefield merefield commented Nov 5, 2026 •

Copy link
Copy Markdown
Owner

Why

The architecture audit found several business rules maintained separately by the terminal and web interfaces. Some had already diverged: mutable quota labels could collide, a missing primary allowance could pass scheduled-recovery coverage checks, an optional statusline could report INPUT NEEDED while working, and fractional Usage bars had different scales between renderers.

This PR consolidates those rules at their source, removes redundant state and handwritten browser contracts, and keeps rendering and browser security boundaries separate. It introduces no runtime dependency, service, persistence, or new browser write capability.

Shared identity and session accounting

  • Define quota identity once: backend limit ID, primary/secondary slot and meter kind. Definition keys additionally include duration, not mutable names or future reset timestamps.
  • Reuse that identity in graph history, Sessions quota comparisons, scheduled quota recovery and API-EQ learning. Identical labels or durations no longer conflate distinct allowances, missing/changed windows are detected, and renamed labels refresh without rebasing accounting.
  • Share observed session-state classification and attention/active predicates. No attention signal is no longer interpreted as an input request in the optional statusline.
  • Share bounded token-interval sampling while preserving each interface's existing baseline, cadence and history limits.

Interface-independent calculations

  • Extract the existing process-local API-EQ learning engine into internal/quotaestimate; the TUI retains formatting, localisation, diagnostics and benchmark coordination. Remove its unused issues map. This does not add API-EQ estimates to the browser or change the estimator's confidence policy.
  • Share elapsed-cycle calculations between quota health, reset gauges and graph geometry. Use the existing Go quota-graph regression, coverage and clipping code for browser Pace geometry; remove the JavaScript implementation. Geometry now uses the quota observation timestamp, rather than a separately advancing browser clock; countdown labels continue advancing normally.
  • Share Usage dimension aggregation, ordering, units and bar scaling. Fix fractional totals, preserve signed corrections without turning negative values into positive bar fills, retain missing-versus-zero semantics, and compute browser report projections when reports are fetched rather than on every quota refresh.

Contracts and maintenance

  • Generate TypeScript types, the local slash-command catalogue and Usage dimensions from explicitly browser-safe Go projections. Daily normalisation uses the same dimension catalogue; historical 80%/100% warning classification is owned in Go and projected to the browser. Keep browser-specific help text and security/transport lifecycle code in their adapters.
  • Replace hardcoded browser input-review command paths with Go-produced metadata; handle nullable wire fields explicitly.
  • Add make web-contracts and freshness tests. Numerical browser fixtures are generated by the actual Go projectors, so browser tests do not maintain another copy of the maths.
  • Document these ownership boundaries and the generation workflow. Rebuild embedded frontend assets; refresh the screenshot source fingerprint without changing the seven PNGs.

Size measurements

Re-measured after successful CI, comparing final PR commit 9609afb with default-branch baseline 93b3fb9:

Measurement Before Final Difference
Maintained production Go/Svelte/TypeScript lines 41,878 41,696 -182 (-0.43%)
Embedded production JavaScript, uncompressed 151,565 B 150,289 B -1,276 B (-0.84%)
Embedded production CSS, uncompressed 18,819 B 18,819 B Unchanged
Stripped Linux amd64 standalone binary 16,875,680 B 16,883,872 B +8,192 B (+0.05%)

Source counts now cover all tracked non-test Go files, including the root entrypoints, plus maintained Svelte/TypeScript under web/src. They exclude generated contracts, tests and embedded bundles. This corrects the earlier narrower source-count scope: both totals now include 750 unchanged root-level Go lines; the net reduction remains 182 lines.

Both binaries were freshly built with Go 1.27.3, CGO_ENABLED=0, GOOS=linux, GOARCH=amd64, GOAMD64=v1, -buildvcs=false, -trimpath, -s -w and the same injected version 0.27.1. This removes development/VCS metadata differences from the comparison.

There is no standalone binary-size win. The measurable savings are in maintained source and browser JavaScript; the principal benefit is fewer independently maintained business rules. Generated contracts, numerical fixtures and additional regression tests make the overall diff larger despite the production-source reduction.

Validation

  • Final commit 9609afb: CI and Security completed successfully, including Linux, macOS, Windows, browser tests and both vulnerability scans.

  • Go race and coverage suite across all packages, with the locale subprocess matrix run separately.

  • All 17 terminal locale cases under the race detector; English presentation snapshot unchanged.

  • Direct tests for the extracted estimator: 91.7% statement coverage, including account/plan/window changes, tainted intervals, evidence validation and confidence bounds. Existing TUI accounting integration tests retained.

  • Targeted identity, session-status, sampling, schedule-coverage, fractional/signed Usage, elapsed-cycle boundaries, reset rounding and historical warning-level regressions.

  • All 111 Playwright browser tests, including Go-produced Pace fixtures and fractional-bar scaling and signed corrections.

  • Frontend type/Svelte checks, formatting and production build; go vet ./...; generated-contract and fixture freshness checks.

  • make screenshots-check: all seven README terminal screenshots verified for v0.27.1.

  • Controlled standalone builds and git diff --check.

Deliberately retained boundaries

Terminal/SVG geometry, colours, localisation, selection, transport lifecycles and browser-origin/write-authority protections remain interface-specific. No common abstraction is introduced for code that has genuinely different responsibilities.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Renamed allowances retain stale monitor labels, and negative usage corrections can render as full browser bars because the peak is allowed to become negative.

2 open issues
What changed in this PR

This PR moves shared business rules into the Go core so the terminal and web interfaces use consistent calculations while retaining separate rendering and security responsibilities.

Changes:

  • Centralizes quota identity, session status, token sampling, and API-equivalent estimation.
  • Shares Pace projections and Usage aggregation, including fractional bar scaling.
  • Generates browser contracts and numerical fixtures, adds freshness checks, and documents the workflow.
File Description
web/​tests/​projections.generated.json Adds Go-generated numerical fixtures.
web/​tests/​browser.spec.ts Uses shared fixtures and tests fractional bars.
web/​src/​UsageReports.svelte Renders Go-projected Usage distributions.
web/​src/​state.svelte.ts Replaces handwritten types with generated exports.
web/​src/​SessionCommands.svelte Uses generated commands and input-review metadata.
web/​src/​SessionActions.svelte Adopts generated types and optional timestamps.
web/​src/​Quota.svelte Passes server-produced Pace geometry.
web/​src/​GoalStatus.svelte Accepts nullable goal data.
web/​src/​contracts.generated.ts Defines generated browser contracts and commands.
web/​src/​ConsumptionPace.svelte Replaces browser regression calculations with projections.
web/​.prettierignore Excludes generated contracts and fixtures.
README.md Documents shared ownership and contract generation.
Makefile Adds the web-contracts target.
internal/​web/​zone_test.go Updates quota-slot identity assertions.
internal/​web/​state.go Integrates shared identity, sampling, status, and projections.
internal/​web/​schedules.go Names the browser-safe scheduled-job projection.
internal/​web/​projection_fixtures_test.go Generates and checks numerical fixtures.
internal/​web/​dist/​index.html References the rebuilt frontend bundle.
internal/​web/​control_commands.go Exposes input-review metadata.
internal/​web/​contracts_test.go Generates browser contracts and checks freshness.
internal/​ui/​usage_reports.go Uses shared Usage distributions and scaling.
internal/​ui/​shared_projection_test.go Tests status and label-independent quota identity.
internal/​ui/​quota_tier_test.go Adapts tier tests to the extracted estimator.
internal/​ui/​quota_api_eq.go Retains presentation around the shared estimator.
internal/​ui/​quota_api_eq_test.go Updates estimator integration tests.
internal/​ui/​monitor.go Uses shared attention predicates and sample fields.
internal/​ui/​monitor_test.go Updates sampling and rendering tests.
internal/​ui/​monitor_statusline.go Uses the shared session-status classification.
internal/​ui/​monitor_filter.go Delegates recent-activity classification.
internal/​ui/​monitor_context.go Delegates attention-label selection.
internal/​ui/​monitor_context_test.go Updates sample fixtures.
internal/​ui/​monitor_close_all_test.go Updates retained measurement fixtures.
internal/​ui/​model.go Integrates estimator state, quota keys, and sampling.
internal/​ui/​model_test.go Updates accounting coverage assertions.
internal/​ui/​localisation_test.go Adapts confidence assertions to exported fields.
internal/​ui/​documentation_screenshots_test.go Updates screenshot sample construction.
internal/​ui/​benchmark_quota_test.go Adapts benchmark accounting tests.
internal/​schedule/​quota.go Uses shared quota-definition keys.
internal/​schedule/​identity_test.go Tests missing and changed quota windows.
internal/​quotagraph/​graph.go Shares quota identity and numeric Pace projections.
internal/​quotaestimate/​estimate.go Extracts process-local API-equivalent learning.
internal/​quotaestimate/​estimate_test.go Tests estimator isolation, validation, and confidence.
internal/​codex/​usage_reports.go Adds projected distribution fields.
internal/​codex/​usage_categories.go Centralizes Usage aggregation, ordering, and scaling.
internal/​codex/​types.go Defines stable quota identities and slot keys.
internal/​codex/​session_state.go Centralizes observed session-state rules.
internal/​codex/​session_samples.go Shares bounded token-interval sampling.
internal/​codex/​session_projection_test.go Tests shared identity, status, Usage, and sampling.
assets/​screenshots/​manifest.json Refreshes the screenshot source fingerprint.
.gitattributes Marks generated browser artifacts.

Review effort: Balanced

Comment thread internal/codex/usage_categories.go Resolved
Comment thread internal/ui/model.go Resolved
@merefield

Copy link
Copy Markdown
Owner Author

@copilot how effective was this PR in its goal?

Copilot AI commented Nov 5, 2026

Copy link
Copy Markdown

@copilot how effective was this PR in its goal?

Quite effective against the stated goal: the main duplicated rules now have shared Go implementations or Go-generated contracts/fixtures, and the two reported regressions—stale renamed quota labels and negative corrections producing full-width bars—were fixed with targeted coverage. The reported maintained production code fell by 202 lines and embedded JavaScript by 1,275 bytes. The standalone binary grew by 8 KB (~0.05%), so this wasn’t a binary-size win; the stronger result is reduced divergence risk backed by broad parity and regression tests.

@merefield

Copy link
Copy Markdown
Owner Author

@copilot can you find any remaining duplication or lack of functional consolidation within the project?

Copilot AI commented Nov 5, 2026

Copy link
Copy Markdown

@copilot can you find any remaining duplication or lack of functional consolidation within the project?

Yes—there are a few residual candidates, though I found no obvious new correctness defect:

  • Quota-cycle elapsed math: internal/quotagraph/graph.go:21-25 centralizes elapsed percentage, but similar calculations remain in internal/ui/quota_status.go:119-130, internal/ui/meters.go:287-295, and web/src/Quota.svelte:29-34. The TUI versions could reuse the shared helper; the browser’s live timeline may intentionally use the advancing client clock, unlike Pace geometry tied to the server observation.
  • Usage dimension catalogue: internal/codex/usage_categories.go:10 defines UsageDimensions(), but daily normalization repeats the list in internal/codex/usage_reports.go:290-292, and the browser has its own selector in web/src/UsageReports.svelte:33-37. This could drift when a dimension is added; making the list available to the browser would close that gap.
  • Historical usage warning thresholds: TUI styling uses 80/100 in internal/ui/usage_reports.go:15-26, while browser styling independently uses 80/100 in web/src/UsageReports.svelte:90-93. A shared classification would prevent those thresholds drifting.

One deliberate functional gap is quota-health scoring: it exists in internal/ui/quota_status.go:83-153, while web/src/Quota.svelte:179-181 explicitly says scoring remains terminal-only. That is a parity opportunity only if browser parity is wanted; it appears intentionally out of scope here. I’d leave the repeated offered-answer check in TUI and web separate: one is immediate UI validation, the other is server-side validation at a security boundary.

@merefield

Copy link
Copy Markdown
Owner Author

Addressed the remaining consolidation suggestions from #96 (comment) in 9609afb (REF: share elapsed cycles and remaining Usage metadata).

  • Elapsed-cycle logic: quota health, reset gauges and graph geometry now use quotagraph.ElapsedFraction. Added exact-pace, cycle-boundary, subsecond and rounding regressions. The browser live reset timeline intentionally keeps its advancing client clock; observed Pace geometry stays tied to the quota observation.
  • Usage dimension catalogue: daily normalisation now uses UsageDimensions(), and the browser selector consumes the catalogue generated from that same function, preserving the original labels and order.
  • Historical warnings: UsageWarningLevel owns the 80/100 thresholds, the TUI uses it directly, and the browser renders its Go-projected classification. Relative daily units are explicitly not classified as quota percentages.

Validation: full core Go race/coverage suite, all 111 browser tests, FMA-enabled projection checks, frontend checks/build, go vet, and all seven README screenshot checks passed. The screenshots remain unchanged.

As recommended, terminal-only quota-health scoring remains out of browser scope, and immediate UI validation stays separate from authoritative server-side validation at the security boundary.

@merefield
merefield merged commit 0a8fcd8 into main Nov 5, 2026
10 of 11 checks 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.

3 participants