Skip to content

Latest commit

 

History

History
11 lines (9 loc) · 4.55 KB

File metadata and controls

11 lines (9 loc) · 4.55 KB

type-system — notes

Hand-written. ../harvested/type-system.md is what the documents say; this file is what the implementation found, and it wins. Each entry names the harvested entry it answers by that entry's stable key.

Conflicts

  • Static typing stack: the design wins — RBS signatures under sig/, gated by rbs validate and steep check, and no Sorbet anywhere in this repository. Resolves type-system/93dc79aa. The decisive fact is mechanical rather than aesthetic, and it is a library-versus-application one: Sorbet's sig blocks are executed by sorbet-runtime, so # typed: strict with runtime-checked signatures forces add_dependency "sorbet-runtime" into every gemspec that carries a sig — including dexpace-core, whose gemspec is asserted to contain zero add_dependency lines (SEAM-1, NFR-1). An application pays that dependency once; a zero-dependency core would be imposing it on every consumer, and NFR-11's "no constant outside Dexpace:: and a fixed stdlib allowlist in any public signature" would be violated by the T:: constants themselves. RBS is the opposite shape: signatures are data files, rbs and steep are development-only, and sig/ ships inside each gem so a consumer's own steep check sees it. What the SDK does instead: every public entity has an RBS signature (NFR-3); rbs validate plus steep check are blocking gates; Steep adoption is target-by-target in the Steepfile rather than a blanket ignore, because Steep on metaprogramming-heavy code produces false positives; the NFR-4 API lock is a diff of sig/**/*.rbs against the previous release tag, paired with a runtime surface snapshot because RBS cannot see Data.define's generated readers. What is lost and is not replaced: Sorbet's runtime sig enforcement — RBS is static only — so the styleguide's assertion-density rule is met by explicit raise preconditions in .build and at the wire boundary instead. The # typed: sigil is not written in any file here, and the Sorbet/StrictSigil cop is not part of this repository's cop set. The styleguide-amendment alternative (carving out zero-runtime-dependency gems to use RBS in place of Sorbet) was considered and not taken; this is recorded as an SDK deviation instead. review · docs/work/mvp/2026-09-05-ruby-sdk-v1-roadmap-design.md · high · sha:manual-roadmap-conflict-6
  • Closed domain sets are frozen Data value types with parse/of factories over a frozen table, not T::Enum. Resolves type-system/4a058b71. The rule was routed here by phase 0's design, which found it the one Sorbet-conditional typing rule with no replacement named. T::Enum is defined by sorbet-runtime, a third-party gem that would appear as an add_dependency in dexpace-core.gemspec — which SEAM-1/NFR-1 forbid and rake gates:gemspec_audit mechanically rejects — so the premise is absent rather than overruled, exactly as ../notes/type-system.md's first entry records for the wider Sorbet question. The rule's purpose is adopted in full and is load-bearing here: HTTP-9's idempotent set, HTTP-7's body-forbidden set and HTTP-33's protocol identifiers are closed sets, and none of them is a free-floating Symbol or String anywhere in this SDK. What the SDK does instead, per docs/sdk-design-ruby/04-domain-model-construction.md: each closed set is a Data.define type — Dexpace::Method, Dexpace::Protocol, Dexpace::Status — with private_class_method :new, a validating .build, a parse/of parse-constructor that is the only entry point taking raw input, and frozen constants for the recognised members (Method::GET, Protocol::HTTP_2, Status::OK). The boundary behaviour type-system/fb4216ca asks of MyEnum.deserialize is what .parse provides: it raises on an unrecognised identifier for Protocol (HTTP-33), and for Status it deliberately does not, because HTTP-10 requires construction to be total over the protocol's code range so a vendor code such as nginx's 499 or Cloudflare's 520–526 survives. Exhaustiveness, which T::Enum would have given the type checker, is instead an RBS union plus steep check at each fold site, with case/in's NoMatchingPatternError as the runtime backstop (design §5). The styleguide-amendment alternative (making chapter 3's closed-set rule read "a sealed value type, T::Enum where Sorbet is in use") was considered and not taken; this is recorded as an SDK deviation instead (phase 1). review · docs/work/mvp/phase1/2026-09-05-phase1-core-http-domain-model-design.md · high · sha:manual-phase1-closed-sets