Native types and migration#

The profile uses native scalars where their shared value domain preserves COGS meaning. JSON/XML structures, exact wire names and primitive JSON kinds remain unchanged. This is a breaking generated API and value-domain change from the earlier 2.0 prerelease generators. Regenerate clients and validate stored instances before replacing them.

S is 9007199254740991; D is 922337203685477 milliseconds. The normative wire/domain table is in Model Format.

All primitive mappings#

COGS

C#

Python (both flavors)

TypeScript

Change and remaining requirement

boolean

bool

bool

boolean

Unchanged.

string

string

str

string

XML 1.0 text; scalar lengths; CR preserved.

language

string

str

string

BCP 47 syntax unchanged.

anyURI

string

str

string

C# Uri becomes string; exact RFC 3986 spelling.

int

int

int

number

Int32 unchanged; integral exponent forms accepted.

long

long

int

number

Signed 64-bit narrows to -S..S.

unsignedLong

ulong

int

number

Unsigned 64-bit narrows to 0..S.

nonNegativeInteger

long

int

number

Formerly unbounded; now 0..S.

nonPositiveInteger

long

int

number

Formerly unbounded; now -S..0.

negativeInteger

long

int

number

Formerly unbounded; now -S..-1.

positiveInteger

long

int

number

Formerly unbounded; now 1..S.

decimal

decimal

Decimal

number

Wrapper removed; exact bounded interchange domain.

float

float

float

number

Binary32 rounding everywhere; positive zero.

double

double

float

number

Binary64; positive zero.

dateTime

DateTimeOffset

datetime

Date

Wrapper removed; UTC instants at milliseconds.

date

DateOnly

date

string

Wrapper removed; years 0001–9999, no offset.

time

TimeOnly

time

string

Wrapper removed; local microseconds, no offset.

duration

TimeSpan

timedelta

number

Wrapper removed; elapsed milliseconds bounded by D.

gYearMonth

GYearMonth

GYearMonth

GYearMonth

Structured year/month/optional zone retained.

gYear

GYear

GYear

GYear

Structured year/optional zone retained.

gMonthDay

GMonthDay

GMonthDay

GMonthDay

Structured month/day/optional zone retained.

gDay

GDay

GDay

GDay

Structured day/optional zone retained.

gMonth

GMonth

GMonth

GMonth

Structured month/optional zone retained.

cogsDate

CogsDate

CogsDate

CogsDate union

Five existing arms; native scalar payloads.

langString

LangString

LangString

LangString

Language/text record retained.

Scalar migration#

Replace new CogsDecimal("1.25") with 1.25m in C#, with Decimal("1.25") in Python, and with 1.25 in TypeScript. Delete bigint suffixes on eligible TypeScript integer literals: 42n becomes 42. C# arbitrary-integer fields become long. An old value such as 9007199254740993 must be corrected by its owner or modeled as textual information under a separately versioned model; automatic rounding is invalid.

Replace lexical dateTime wrappers with timezone-aware native instants: DateTimeOffset.Parse("2024-02-29T12:00:00Z"), datetime(2024, 2, 29, 12, tzinfo=timezone.utc), or new Date("2024-02-29T12:00:00Z"). Local dates use DateOnly/date or the TypeScript string "2024-02-29"; local times use TimeOnly/time or "12:34:56.123456". TypeScript Date is not used for these local values because it would invent an instant or discard microseconds.

Replace CogsDuration("PT1.5S") with TimeSpan.FromMilliseconds(1500), timedelta(milliseconds=1500), or 1500 milliseconds. The wire still contains "PT1.5S". Calendar durations such as P1M have no context-free elapsed equivalent; choose a model-level calendar representation or determine an elapsed value using explicit application context. Submillisecond values are rejected instead of truncated.

Partial Gregorian helpers remain because a full date cannot preserve an absent year/month/day or an optional timezone. C# and Python CogsDate wrappers now contain native scalar arms. TypeScript uses a plain tagged union, for example { Date: "2024-02-29" }. LangString remains a two-field record.

Interchange and construction#

Accepted numeric values survive ordinary JavaScript parsing and writing with their defined COGS value. JSON.stringify(container) delegates to the wire representation; ItemContainer.fromObject(JSON.parse(text)) accepts valid input. Use fromJson on untrusted text: after JSON.parse rounds an invalid decimal token or overwrites a duplicate key, an object reader cannot recover that evidence. The text reader retains tokens long enough to reject these cases, including float tokens that would change binary32 value through double rounding. Use a stable binary32 spelling for such a JSON input. Float decimal spelling may change while its binary32 value is preserved. XML continues to accept direct XSD binary32 lexical conversion.

Python uses a JSON adapter to write Decimal as a number and parse decimal tokens exactly. Standard json.dumps does not serialize Decimal itself. JavaScript arithmetic remains binary floating point; 0.1 + 0.2 is not exact decimal addition. Native C#/Python arithmetic can also produce out-of-profile scale or precision, which writers reject. COGS never repairs an exactness conflict by silent decimal rounding.

Direct construction and assignment use native language APIs. Pydantic also checks strict field types and assignments. Serialization checks primitive domains; schema/COGS instance validation enforces model cardinality and facets. Native Pydantic dumps and schemas describe Python fields, not the reference graph.

All XML string/path/stream writers preserve carriage returns by character references. Identification retains its exact spelling; UTC and other lexical canonicalizations apply only to the relevant primitive values.

Migration procedure#

  1. Validate source models and stored JSON/XML with the new CLI. Numeric and temporal facet values must themselves lie in the new domains.

  2. Resolve rejected values explicitly. The corpus under conformance/instances/migration retains old wide-domain values as rejection tests, not successful generation evidence.

  3. Regenerate all packages, update native construction/assignment calls, and validate every interchange boundary.

  4. Compare semantic values, concrete types, ordering and reference identity. Decimal trailing zeros, UTC offsets and duration decomposition may change.

Platform basis#

The profile intersects documented limits from Python 3.11 datetime, Python Decimal, C# numeric types and ECMAScript numbers and dates. The decimal admission rule is stricter than any single platform’s numeric range. The duration limit uses TimeSpan’s signed tick range rounded inward to whole milliseconds.