Skip to content

SY-4138: Prepare Spatial Types for Strongly Typing Visualizations#2280

Merged
emilbon99 merged 18 commits intorcfrom
sy-4138-prepare-oracle-generated-spatial-primitives-for-strongly
May 1, 2026
Merged

SY-4138: Prepare Spatial Types for Strongly Typing Visualizations#2280
emilbon99 merged 18 commits intorcfrom
sy-4138-prepare-oracle-generated-spatial-primitives-for-strongly

Conversation

@emilbon99
Copy link
Copy Markdown
Contributor

@emilbon99 emilbon99 commented Apr 29, 2026

Issue Pull Request

Linear Issue

SY-4138

Description

Adds a numeric built-in constraint to Oracle for primitive-constrained generics (T extends numeric = float64). TypeScript emits a function-form schema (<T extends numeric.Value = number>(t?: z.ZodType<T>) => z.object({...})) plus a value-typed generic interface (Bounds<T extends numeric.Value = number>). Go, C++, Python, and proto substitute the default primitive and emit non-generic concrete types — these languages can't express a number | bigint constraint, so they collapse to the default. Analyzer rejects numeric constraints without a numeric default.

Companion fixes in the TS emitter:

  • lo.CamelCase replaced with a smart helper that preserves trailing acronym runs (ClientXY → clientXY, EntityID → entityID), parallel to the existing Go acronym list. Standalone acronyms (XY → xy) and non-acronym names are unchanged.
  • numeric.Value is auto-imported from @synnaxlabs/x (or @/numeric from inside the x package), mirroring the existing record.Unknown pattern. Adds export * from "@/numeric" to x/ts/src/index.ts so external consumers can resolve the namespace.
  • anypb import in the generated Go translator is now gated on having non-defaulted type-params, fixing an unused-import error for fully-defaulted generics like Bounds.

The new infrastructure is then used to migrate the spatial primitive set (Bounds, XY, ClientXY, StickyXY, Viewport, Dimensions, locations, directions, alignment, sticky units, etc.) from hand-written types in x/ts/src/spatial/base.ts to Oracle-generated types.gen.ts, types.gen.go, types.gen.h, and spatial.proto. The hand-rolled boundsZ constant becomes a function (boundsZ()) — call sites in pluto, console, and x/ts are updated accordingly. NumberCouple and CrudeBounds stay as TS-only constructs because tuples and unions of struct + tuple aren't expressible in Oracle.

Basic Readiness

  • I have performed a self-review of my code.
  • I have added relevant, automated tests to cover the changes.
  • I have updated documentation to reflect the changes.

Greptile Summary

This PR migrates the spatial primitive set from hand-written TypeScript to Oracle-generated code (types.gen.ts, types.gen.go, types.gen.h, spatial.proto), adds a numeric built-in constraint for primitive-constrained generics, and ships companion fixes to the TS emitter (camelCase acronym-preserving helper), the Go PB plugin (IsOptionalStruct soft-optional fix, gated anypb import), and the pluralizer (StickyXYStickyXYs). The previous bugs flagged in review comments — StickyXY nil-pointer round-trip, wrong *Xies plural forms, and zero-value optional struct serialization — are addressed by using pointer types (Root *CornerLocation, Units *StickyUnits) with omitempty tags and conditional translator paths.

Confidence Score: 5/5

Safe to merge — all previously flagged bugs are addressed, no new P1/P0 issues found.

The three previously flagged P1 issues (StickyXY nil-pointer round-trip, wrong *Xies plural forms, zero-value optional struct serialization) are all resolved. No remaining P1 or P0 findings. All renamed public APIs are consistently updated across every call site in pluto, console, and x/ts. New code paths are covered by well-structured tests.

No files require special attention.

Important Files Changed

Filename Overview
oracle/plugin/ts/types/types.go Adds IsPrimitiveConstrainedGeneric emitter path, numeric.Value auto-import, and smart camelCase helper that preserves trailing acronym runs (ClientXY→clientXY, EntityID→entityID); all lo.CamelCase call sites replaced consistently.
oracle/plugin/go/pb/pb.go Gates anypb import on non-defaulted type params and fixes IsOptionalStruct to use isHardOptional, preventing soft-optional struct fields from being nil-guarded in generated translators.
x/go/spatial/types.gen.go Generates new spatial types; StickyXY uses pointer fields (*CornerLocation, *StickyUnits) with omitempty tags, correctly addressing previous JSON/msgpack serialization and translator nil-pointer bugs.
x/go/spatial/pb/translator.gen.go Adds translators for all new spatial types; StickyXYToPB/FromPB correctly nil-checks *CornerLocation and *StickyUnits pointer fields; ClientXYsToPB and StickyXYsToPB have correct plural names.
x/ts/src/spatial/types.gen.ts Generates TS types for all spatial primitives; boundsZ correctly emitted as a generic function; clientXYZ named with uppercase XY preserving the acronym.
x/go/pluralize/pluralize.go Fixes -y pluralization to use uppercase-Y check (StickyXY→StickyXYs) instead of all-caps check, correctly handling mixed-case acronym-terminated names.
x/ts/src/spatial/base.ts Reduced to a re-export of types.gen.ts plus the TS-only NumberCouple constructs; clean removal of hand-rolled types.
oracle/analyzer/analyzer.go Adds validateTypeParams that rejects numeric-constrained type params without a default or with a non-numeric default; well-tested.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["schemas/spatial.oracle"] --> B["Oracle Code Generator"]
    B --> C["x/ts/src/spatial/types.gen.ts\n(boundsZ as generic fn, clientXYZ, stickyXYZ, ...)"]
    B --> D["x/go/spatial/types.gen.go\n(StickyXY with *CornerLocation, *StickyUnits)"]
    B --> E["x/go/spatial/pb/translator.gen.go\n(StickyXYsToPB, ClientXYsToPB, ...)"]
    B --> F["x/go/spatial/pb/spatial.proto"]
    B --> G["x/cpp/spatial/types.gen.h"]
    C --> H["x/ts/src/spatial/base.ts\n(re-exports types.gen + NumberCouple)"]
    H --> I["bounds / xy / direction / location / sticky modules"]
    I --> J["pluto / console call sites\n(boundsZ(), xyZ, xZ, cornerZ)"]
Loading

Comments Outside Diff (2)

  1. x/go/spatial/types.gen.go, line 183-200 (link)

    P2 JSON/msgpack key mismatch between Go and TypeScript for ClientXY and SignedDimensions

    Oracle generates snake_case JSON tags for Go (client_x, client_y, signed_width, signed_height), while the TypeScript schemas use camelCase (clientX, clientY, signedWidth, signedHeight). Protobuf JSON encoding auto-converts snake_case to camelCase, so proto-mediated round-trips are fine. However, any direct Go JSON/msgpack serialisation of these types (e.g. persisted config files or REST payloads) would produce keys that TypeScript consumers cannot decode without explicit field-name remapping.

  2. arc/go/types/pb/translator.gen.go, line 471-520 (link)

    P1 KindSignedNumericConstant removed from KindToPB while still active in the type system

    KindSignedNumericConstant was removed from the KindToPB/KindFromPB switch in this PR, but the kind is still defined in arc/go/types/types.gen.go and actively used in arc/go/types/type.go, arc/go/analyzer/constraints/unify.go, and arc/go/compiler/expression/compiler.go. The function SignedNumericConstraint() returns Type{Kind: KindSignedNumericConstant}, and it can appear as a Constraint on type-parameter variables.

    TypeToPB calls KindToPB(r.Kind) unconditionally before building the proto object (line 104), and recursively calls itself for r.Constraint (line 136). Any code path that calls TypeToPB with a type whose Kind or Constraint.Kind is KindSignedNumericConstant will hit the default case and return an error. If function parameter types that carry a SignedNumericConstraint() reach the proto serialization layer, serialization of those params will silently fail at runtime.

Reviews (9): Last reviewed commit: "Merge branch 'rc' of https://github.com/..." | Re-trigger Greptile

@emilbon99 emilbon99 changed the title SY-4138: Add Numeric Constraint to Oracle and Migrate Spatial Types SY-4138: Prepare Spatial Types for Strongly Typing Visualizations Apr 29, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 29, 2026

Codecov Report

❌ Patch coverage is 87.73006% with 20 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.27%. Comparing base (f3339dd) to head (9234436).
⚠️ Report is 1 commits behind head on rc.

Files with missing lines Patch % Lines
oracle/plugin/ts/types/types.go 75.71% 15 Missing and 2 partials ⚠️
x/ts/src/spatial/types.gen.ts 90.90% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##               rc    #2280      +/-   ##
==========================================
+ Coverage   64.26%   64.27%   +0.01%     
==========================================
  Files        2178     2178              
  Lines      110399   110493      +94     
  Branches     8289     8300      +11     
==========================================
+ Hits        70945    71023      +78     
- Misses      33385    33398      +13     
- Partials     6069     6072       +3     
Flag Coverage Δ
alamos-go 55.25% <ø> (ø)
alamos-ts 48.87% <ø> (ø)
arc-go 76.93% <ø> (ø)
aspen 67.89% <ø> (-0.36%) ⬇️
cesium 82.41% <ø> (+0.09%) ⬆️
client-py 85.91% <ø> (ø)
client-ts 90.18% <ø> (-0.01%) ⬇️
console 20.42% <100.00%> (ø)
core 68.61% <ø> (+0.01%) ⬆️
drift 39.05% <ø> (ø)
freighter-go 63.00% <ø> (ø)
freighter-integration 1.51% <ø> (ø)
freighter-py 79.96% <ø> (ø)
freighter-ts 73.87% <ø> (ø)
oracle 62.57% <83.33%> (+0.11%) ⬆️
pluto 55.69% <100.00%> (-0.05%) ⬇️
x-go 81.86% <100.00%> (+0.04%) ⬆️
x-ts 88.84% <94.64%> (-0.05%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

These pb.go and codec_gen_test.go changes were proto-descriptor reordering
noise unrelated to the spatial-types work. Reverting to keep the PR diff
focused.
These case "numeric" arms in constraintToGo, formatTypeParamsDecl, and
the test-fixture concrete-type helpers can't fire: the analyzer requires
every numeric-constrained type-param to have a numeric default, and
every Go-emitting call site filters through NonDefaultedTypeParams
before reaching these functions. The arms were added as completeness
hedges; remove them to keep the codebase to live paths only.
Comment thread x/go/spatial/pb/translator.gen.go
Comment thread x/go/spatial/pb/translator.gen.go Outdated
…b generator

A struct field declared with single "?" in oracle keeps its Go type as a
value, but the proto field is nullable on the wire. The generator was
calling the inner ToPB unconditionally, which errored on a zero-value
struct that contained string-enum fields (e.g. spatial.StickyXY.Root,
arc.ir.Function.Body). Route soft-optional struct fields through
OptionalFields with a zero-value guard in ToPB and a proto-pointer
nil-check in FromPB. The latent same-shape bug in ranger.Range.Color is
fixed by the same path.

Also fix the pluralize package so trailing acronym runs ending in Y
(StickyXY, ClientXY) pluralize as "+s" rather than mangling to "ies".
The previous all-uppercase shortcut only caught fully-acronym names.
Schema fields whose names start with a lowercase letter are now used
verbatim as the JSON / msgpack tag instead of being routed through
SnakeCase. snake_case stays snake_case (data_type) and camelCase stays
camelCase (clientX, signedWidth, targetKey), letting Go round-trip
directly with the TypeScript zod schemas, which use the schema field
name as the property key.

Names that begin with an uppercase letter (PascalCase, screaming-case,
single-letter caps) keep the existing lowercase-snake convention so
WASM -> wasm and OutputMemoryBases -> output_memory_bases are
unchanged. Only six fields across the codebase change tags
(spatial.ClientXY, spatial.SignedDimensions, ir.Transition.TargetKey,
ir.Member.NodeKey); none have shipped data to maintain compatibility
with.
…8-prepare-oracle-generated-spatial-primitives-for-strongly
…8-prepare-oracle-generated-spatial-primitives-for-strongly
Comment thread x/go/spatial/types.gen.go Outdated
Comment thread arc/go/ir/types.gen.go
Reverts commit 3bb7a60. The wire format is canonically snake_case across
every language; TypeScript bridges via x/ts caseconv at the boundary, so
preserving camelCase schema names verbatim in Go tags broke the convention
rather than aligning with it. jsonTagName now routes every field name
through SnakeCase regardless of how it is spelled in the schema.

This will flip the JSON / msgpack tags on the six fields the previous
commit touched (spatial.ClientXY.{clientX,clientY},
spatial.SignedDimensions.{signedWidth,signedHeight},
ir.Transition.targetKey, ir.Member.nodeKey) back to snake_case once oracle
sync regenerates the .gen.go files.
…8-prepare-oracle-generated-spatial-primitives-for-strongly
…8-prepare-oracle-generated-spatial-primitives-for-strongly
@emilbon99 emilbon99 merged commit 87abeab into rc May 1, 2026
53 checks passed
@emilbon99 emilbon99 deleted the sy-4138-prepare-oracle-generated-spatial-primitives-for-strongly branch May 1, 2026 17:52
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.

2 participants