Skip to content

R1-03: Core strong types - #2

Merged
aravgarg28 merged 1 commit into
mainfrom
task/R1-03-core-types
Jul 25, 2026
Merged

R1-03: Core strong types#2
aravgarg28 merged 1 commit into
mainfrom
task/R1-03-core-types

Conversation

@aravgarg28

Copy link
Copy Markdown
Owner

R1-03: Core strong types — Completion Report

Status: complete
Branch/PR: task/R1-03-core-types

What was built

src/core/include/microsim/core/types.hpp (+ types.cpp): the dimensioned value types and identifiers every later module depends on, encoding docs/numerics/NUMERIC_REPRESENTATION.md in the type system.

  • Value types: Price (int64 ticks), Qty (int64 lots), Cash (int64 minor units), SimTime/Duration (int64 ns), and Side (+ opposite, sign_of, to_cstr).
  • Identifiers: OrderId, TradeId, Seq (sequential, with first()/next() for the monotonic assigners), ClientOrderId, ParticipantId, InstrumentId — opaque handles that order and hash but carry no arithmetic.
  • Narrow operator sets: Price ± int → Price, Price − Price → int64 ticks, Qty ± Qty, Cash signed arithmetic, SimTime ± Duration → SimTime, SimTime − SimTime → Duration. Meaningless operations simply have no overload, so they are compile errors.
  • No implicit int conversions (explicit ctors, named accessors); std::format + ostream printing via integer scale math with unit tags (1003t, 50lot, -25mu, 500ns, order#42). Currency formatting (needs a tick size) is correctly deferred to R1-06 per the task's Excludes.

Acceptance criteria

  • All listed types present with the exact NUMERIC_REPRESENTATION §strong-types rules — pinned by static_assert (allowed-op result types + no-implicit-conversion) in test_types.cpp
  • static_assert suite for type rules — 14 static_asserts (result types, convertibility, size/triviality)
  • std::format/formatter printing via integer scale math — Format.* tests
  • Excludes respected — no Notional (needs instrument, R1-05), no string conversions (R1-06)
  • Unit tests: ops tables — Price/Qty/Cash/Time/Side/Ids/Format suites
  • Compile-fail tests for banned ops — 9 cases via try-style CTest targets (WILL_FAIL), plus a positive control

Verification output

$ cmake --preset debug && cmake --build --preset debug && ctest --preset debug
100% tests passed out of 30
Total Test time (real) = 6.62 sec

$ ctest --preset debug -R core.compile_fail
core.compile_fail.price_plus_qty ........... Passed   (banned op rejected)
core.compile_fail.price_plus_price ......... Passed
core.compile_fail.price_times_qty .......... Passed
core.compile_fail.implicit_int_to_price .... Passed
core.compile_fail.implicit_price_to_int .... Passed
core.compile_fail.qty_plus_cash ............ Passed
core.compile_fail.simtime_plus_simtime ..... Passed
core.compile_fail.qty_times_qty ............ Passed
core.compile_fail.cross_compare_cash_qty ... Passed
core.compile_fail.ok_control_runs .......... Passed   (positive control compiles+runs)

$ cmake --preset asan-ubsan && cmake --build --preset asan-ubsan && ctest --preset asan-ubsan
100% tests passed out of 30                  # no ASan/UBSan findings

$ (build core under -DMICROSIM_WERROR=ON)    # no warnings
$ ./scripts/format.sh --check                # clang-format 20.1.7: 44 files OK

Tests added

Test Covers Type
static_assert ×14 (test_types.cpp) allowed-op result types, no-implicit-conversion, size/triviality compile-time unit
Price.*, Qty.*, Cash.*, Time.*, Side.* arithmetic, ordering, sign/opposite unit
Ids.SequentialIdsIncreaseMonotonically, Ids.HashableAsMapKeys INV-9 ordering, map-key hashing unit
Format.StdFormatUsesUnitTags, Format.OstreamMatchesFormat formatter/ostream output unit
core.compile_fail.* ×9 + ok_control banned ops do not compile; positive control does compile-fail

Deviations / Questions

  1. Formatter output is unit-tagged raw integers, not currency. Human-readable currency needs the instrument's tick size, which is R1-05/R1-06 (the task's own Excludes). Price prints 1003t, Cash prints -25mu. This matches "printing via integer scale math" at the level available here; flagging so it's a conscious choice, not an oversight.
  2. Two small affordances beyond the literal type list, both spec-justified: Duration * int64 (latency composition needs base * n, LATENCY_MODEL.md) and sign_of(Side) (fill→position sign, used pervasively by accounting). Neither weakens the banned-op guarantees. Happy to remove if you'd rather keep the surface minimal.

Notes for reviewer

  • Start at the class comment blocks in types.hpp — each states its allowed/banned operations in prose next to the code.
  • The compile-fail harness (tests/CMakeLists.txt, microsim_add_compile_fail) is the interesting infra: each banned op is an EXCLUDE_FROM_ALL target a CTest builds and expects to fail; ok_control builds normally so a broken harness fails loudly rather than passing vacuously.
  • CI note: this PR's checks will only run once R1-02 (the CI workflow) is on main — currently blocked on the workflow OAuth scope (see the R1-02 status). Locally verified on macOS/AppleClang 17 under debug + asan-ubsan + -Werror.

@aravgarg28 aravgarg28 mentioned this pull request Jul 25, 2026
4 tasks
@aravgarg28
aravgarg28 force-pushed the task/R1-03-core-types branch 2 times, most recently from a663002 to 5756ce9 Compare July 25, 2026 01:21
Introduces the dimensioned value types and identifiers that every
later module builds on, encoding docs/numerics/NUMERIC_REPRESENTATION.md
in the type system:

- Price (int64 ticks), Qty (int64 lots), Cash (int64 minor units),
  SimTime/Duration (int64 ns), Side, and opaque identifiers OrderId,
  TradeId, Seq (sequential, with next()/first()), ClientOrderId,
  ParticipantId, InstrumentId.
- Operator sets are deliberately narrow: Price +/- int -> Price,
  Price - Price -> int64 ticks, Qty +/- Qty, Cash signed arithmetic,
  SimTime +/- Duration and SimTime - SimTime -> Duration. Meaningless
  operations do not exist as overloads, so they are compile errors.
- No implicit conversions to/from raw integers (explicit ctors and
  named accessors only); ids hash and order for map keys and the
  monotonicity invariants (INV-9).
- std::format formatters and ostream operators print via integer scale
  math with unit tags (1003t, 50lot, -25mu, 500ns, order#42); currency
  formatting that needs a tick size is deferred to R1-06.

Tests: static_asserts pin allowed-op result types and the
no-implicit-conversion rules; runtime tests cover arithmetic,
ordering, ids, and formatting; nine compile-fail tests prove the
banned operations (Price+Qty, Price+Price, Price*Qty, implicit int<->
Price, Qty+Cash, SimTime+SimTime, Qty*Qty, cross-type compare) do not
compile, with a positive control proving the harness discriminates.

Verified: 30/30 tests pass under debug and asan-ubsan; -Werror clean;
clang-format (pinned 20.1.7) clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@aravgarg28
aravgarg28 force-pushed the task/R1-03-core-types branch from 5756ce9 to 5637ef4 Compare July 25, 2026 01:25
@aravgarg28
aravgarg28 merged commit 6858456 into main Jul 25, 2026
5 checks passed
@aravgarg28
aravgarg28 deleted the task/R1-03-core-types branch July 25, 2026 01:28
aravgarg28 added a commit that referenced this pull request Jul 27, 2026
Introduces the dimensioned value types and identifiers that every
later module builds on, encoding docs/numerics/NUMERIC_REPRESENTATION.md
in the type system:

- Price (int64 ticks), Qty (int64 lots), Cash (int64 minor units),
  SimTime/Duration (int64 ns), Side, and opaque identifiers OrderId,
  TradeId, Seq (sequential, with next()/first()), ClientOrderId,
  ParticipantId, InstrumentId.
- Operator sets are deliberately narrow: Price +/- int -> Price,
  Price - Price -> int64 ticks, Qty +/- Qty, Cash signed arithmetic,
  SimTime +/- Duration and SimTime - SimTime -> Duration. Meaningless
  operations do not exist as overloads, so they are compile errors.
- No implicit conversions to/from raw integers (explicit ctors and
  named accessors only); ids hash and order for map keys and the
  monotonicity invariants (INV-9).
- std::format formatters and ostream operators print via integer scale
  math with unit tags (1003t, 50lot, -25mu, 500ns, order#42); currency
  formatting that needs a tick size is deferred to R1-06.

Tests: static_asserts pin allowed-op result types and the
no-implicit-conversion rules; runtime tests cover arithmetic,
ordering, ids, and formatting; nine compile-fail tests prove the
banned operations (Price+Qty, Price+Price, Price*Qty, implicit int<->
Price, Qty+Cash, SimTime+SimTime, Qty*Qty, cross-type compare) do not
compile, with a positive control proving the harness discriminates.

Verified: 30/30 tests pass under debug and asan-ubsan; -Werror clean;
clang-format (pinned 20.1.7) clean.
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.

1 participant