refactor(mapgen-studio): centralize ORPCError data cast, drop dead success fallbacks, and narrow router to contract-derived type#1615
Merged
Conversation
This was referenced Jun 12, 2026
refactor(studio): decompose App.tsx non-React corpus into feature modules and shared utilities
#1608
Merged
Merged
Owner
Author
|
Railway preview (MapGen Studio): not provisioned for this PR. Policy (Graphite stacks): previews are created only for the top-of-stack PR by default.
Debug: |
This was referenced Jun 12, 2026
This was referenced Jun 12, 2026
Merged
mateicanavra
force-pushed
the
design/data-model
branch
from
June 12, 2026 20:44
3350c75 to
89b15ea
Compare
mateicanavra
force-pushed
the
design/rigor
branch
from
June 12, 2026 20:44
de1471c to
51da19a
Compare
Owner
Author
Merge activity
|
mateicanavra
changed the base branch from
design/data-model
to
graphite-base/1615
June 12, 2026 21:10
Pure rigor + cleanup, no behavior change (mapgen-studio-rigor):
- Add one shared typed `readErrorData<T>()` accessor in src/lib/orpc.ts that
narrows the thrown `ORPCError.data` (typed `unknown`, no contract errorMap) to
`Partial<T> | undefined`, and use it in features/civ7Setup/api.ts and
features/runInGame/api.ts in place of the scattered inline
`(err.data ?? undefined) as { … }` casts. Per-field runtime guards unchanged,
so the produced failure envelopes are byte-identical.
- Drop the dead `?? new Date().toISOString()` (observedAt) and `?? ""` (directory)
fallbacks on the civ7Setup success returns; civ7.setupConfig / civ7.savedConfigs
declare those fields REQUIRED on their success output. The error-path observedAt
(which may legitimately be absent) keeps its guard.
- Narrow createStudioRouter / StudioRouter from `AnyRouter` to the contract-derived
`Router<StudioContract, Record<never, never>>` (initial context fully provided by
the injected ManagedRuntime). Annotated, not inferred, so the tsup DTS emit stays
portable (no TS2742); RPCHandler still accepts it.
- Intentional "why" comments on the new accessor and the router narrowing.
Verify: bun run check (mapgen-studio + studio-server tsc clean); bun run build
(vite + worker-bundle + studio-server DTS) ; bun run test (138 green); dev server
renders with no console errors; openspec validate mapgen-studio-rigor --strict.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
mateicanavra
force-pushed
the
design/rigor
branch
from
June 12, 2026 21:12
51da19a to
38b20e4
Compare
This was referenced Jun 12, 2026
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.

This PR centralizes and tightens the type-precision around the oRPC failure-translation seam in Mapgen Studio, with no behavior or wire-format changes.
Shared
readErrorData<T>()accessorA new
readErrorData<T>()function is added tosrc/lib/orpc.tsthat narrowsORPCError.data(typedunknownbecause the contract declares noerrorMap) toPartial<T> | undefined. Bothfeatures/civ7Setup/api.tsandfeatures/runInGame/api.tspreviously duplicated the same inline(err.data ?? undefined) as { … }cast to recover side fields (observedAt,details) from thrown errors. They now use the shared accessor instead, while keeping their existing per-field runtime guards unchanged, so produced failure envelopes are byte-identical.Dead success-path fallbacks removed
fetchCiv7SetupConfigandfetchCiv7SavedSetupConfigsapplied?? new Date().toISOString()and?? ""fallbacks toobservedAtanddirectoryon their success returns. Since theciv7.setupConfigandciv7.savedConfigscontract output schemas declare these fields as required, the fallbacks could never fire and falsely implied the fields might be absent. They are removed. The error-pathobservedAt, which legitimately may be absent, continues to flow throughreadErrorDataand its runtime guard.Router type narrowed from
AnyRouterto contract-derivedRouter<StudioContract, …>createStudioRouterwas annotated: AnyRouter, discarding theStudioContractpinning the effect-orpc router carries. It is now annotated asRouter<StudioContract, Record<never, never>>(the initial context is fully provided by the injectedManagedRuntime). Inferring the rawEnhancedRouter<…>return type was rejected because it references effect-orpc internals and would trip TS2742 in the emitted declarations.StudioRouteris updated toReturnType<typeof createStudioRouter>, andRPCHandlercontinues to accept it sinceAnyRouteris its lower bound.