Import the service-resources wire types from the server - #965
Merged
Conversation
apps/web/src/hooks/use-service-resources.ts hand-mirrored the server's observability type tree: ResourceSample, SubsystemResourceSample, SubsystemSnapshot and ServiceResourcesResponse were all maintained as a second copy. The web copies now `import type` directly from observability/service-resources.ts and observability/subsystem-tracker.ts; esbuild erases type-only imports, so nothing reaches the bundle. ResourceHealthState stays web-side but is now derived as `SubsystemHealthState | "unavailable"` instead of restating six of the server's seven members. Every importer keeps its existing `@/hooks/use-service-resources` path. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review feedback: `| "unavailable"` hardcoded today's difference between the subsystem and overall unions instead of tracking its source. If the server adds an overall-only state, the badge formatters would reject it and the wire-type coupling would not catch the drift. Same member set today, verified by a mutual-assignability assertion against the previous literal union. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
apps/web/src/hooks/use-service-resources.tswas ~180 lines of which nearly all were type declarations hand-mirroring the server's observability type tree. Those declarations are gone; web nowimport types them directly from the server modules that own them.ResourceSample,SubsystemResourceSample,ServiceResourcesResponseapps/server/src/observability/service-resources.tsSubsystemSnapshotapps/server/src/observability/subsystem-tracker.tsResourceHealthStatestays web-side — it is a UI concept (the set of states the dashboard renders a badge for), not a wire type — but it is now derived from both server unions it actually spans:stateBadgeVariant/stateLabelare called with bothsubsystem.stateandoverall.state, so both sources belong in the union. Same member set as the deleted literal union — verified with a throwaway mutual-assignability assertion, not by eye.One file. Every consumer keeps importing from
@/hooks/use-service-resources, so no other file changed.Why this is tech debt
This is the largest single duplication the 2026-08-14 audit's duplicate-block scan found (23 duplicated 7-line windows — the biggest file pair in the repo). It follows the established pattern from #856/#863: web needs only types here, and esbuild erases type-only imports, so nothing reaches the bundle.
Drift found: none
Every prior wire-type consolidation turned up silent divergence, so I diffed the two trees field by field before deleting the web copy. This pair had not drifted — all 13
workloadsfields, all 6agentsfields, and both inlined sub-objects matched the server'sWorkloadSnapshot/AgentProcessSnapshotexactly, in the same order. The one asymmetry wasSubsystemSnapshot.state, typed as the 7-memberResourceHealthStateon web versus the 6-memberSubsystemHealthStateon the server — web was over-broad by"unavailable", a state a subsystem can never actually report. That narrowing is the only type-level behavior change here, and it is a tightening.Feasibility probes (the three that have burned prior runs)
finalize:webbuilds clean, so the import is fully erased.service-resources.tspulls onlynode:os,node:perf_hooks,pgtypes,shared/lib/run-command.jsandsubsystem-tracker.js. No service-layer graph, noAgentManager. (use-jobs.tsalready precedents a type-only import of apg-importing module.)generated/—apps/server/src/generated/is absent in this tree (it only exists afterprepare:runtime-assets, whichcheck:webdoes not run), andcheck:webpasses anyway. That is the Alias web release/assisted-update wire types to the server definitions #863 failure mode probed in its strongest form.Deliberately not touched
service-resources-format.ts:3 formatBytes— the known name collision withshared/lib/format-bytes.ts. Genuinely different (different signature, aBtier, different rounding). Still a rename candidate, not a merge candidate; left alone.AgentProcessSnapshotstays unexported on the server. Web reaches those fields structurally throughServiceResourcesResponse, so exporting it would be churn with no consumer.Validation
pnpm run check·pnpm run finalize:web·pnpm run test:e2e(180 passed, incl.settings.spec.ts:148"shows live service resources and expands subsystem details", which covers this dashboard directly) ·apps/webvitest (912 passed).Closing content-grep on
serverHeapBytes,gitRefreshesInFlight,expectedCadenceMsand thestatusReasonunion returns only the single server declaration plus use sites — no second declaration survives anywhere inapps,scripts,e2e,binorplugins.Next run
Backlog item: the remaining server↔web wire-type pairs, next largest being the reviews type copy that includes an inline third copy at
shared/mcp/server.ts:448.🤖 Generated with Claude Code