ktsu.Semantics.Quantities
6.0.0
Prefix Reserved
dotnet add package ktsu.Semantics.Quantities --version 6.0.0
NuGet\Install-Package ktsu.Semantics.Quantities -Version 6.0.0
<PackageReference Include="ktsu.Semantics.Quantities" Version="6.0.0" />
<PackageVersion Include="ktsu.Semantics.Quantities" Version="6.0.0" />
<PackageReference Include="ktsu.Semantics.Quantities" />
paket add ktsu.Semantics.Quantities --version 6.0.0
#r "nuget: ktsu.Semantics.Quantities, 6.0.0"
#:package ktsu.Semantics.Quantities@6.0.0
#addin nuget:?package=ktsu.Semantics.Quantities&version=6.0.0
#tool nuget:?package=ktsu.Semantics.Quantities&version=6.0.0
ktsu.Semantics.Quantities
A metadata-generated, type-safe physical quantity system built on a unified vector model, with compile-time dimensional analysis, generated unit conversions and physics operators, and centralized physical constants.
ktsu.Semantics.Quantities is one package in the ktsu.Semantics family. If you use a single numeric storage type throughout a project, the alias packages ktsu.Semantics.Quantities.Double, .Float, and .Decimal let you drop the generic argument and write Mass instead of Mass<double>.
Introduction
ktsu.Semantics.Quantities gives you physical quantities as types, so a Force cannot be added to a Speed and multiplying a Mass by an AccelerationMagnitude yields a ForceMagnitude at compile time. Every quantity is generic over its numeric storage type (Mass<double>, Speed<float>, Length<decimal>), and all values are stored in SI base units.
The type surface is generated. A single source of truth, dimensions.json, drives a Roslyn incremental generator that emits the quantity records, their From{Unit} factories with built-in conversions, the cross-dimensional physics operators, and the physical constants. That is roughly 72 physical dimensions and over 200 generated quantity types, all committed to source so the project compiles without first running the generator.
Every quantity is a vector, and the dimensionality of its direction space is part of the type.
| Form | Meaning | Sign | Examples |
|---|---|---|---|
IVector0 |
magnitude only | always >= 0 |
Speed, Mass, Energy, Distance, Area |
IVector1 |
signed 1D | signed | Velocity1D, Force1D, Temperature |
IVector2 |
2D directional | per-component | Velocity2D, Force2D, Acceleration2D |
IVector3 |
3D directional | per-component | Velocity3D, Force3D, Position3D |
IVector4 |
4D directional | per-component | reserved (relativistic / spacetime) |
IVectorN.Magnitude() (for N >= 1) returns the matching IVector0 quantity.
Features
- Compile-time dimensional safety: illegal combinations do not compile, and cross-dimensional operators produce the correct result type.
- Generated unit conversions:
From{Unit}factories per declared unit (Mass.FromKilogram,Speed.FromMeterPerSecond,Length.FromFoot), converting to the SI base unit on construction, withIn(unit)to convert back. - Unified vector model:
IVector0throughIVector4, withMagnitude(),Dot,Cross,Normalize, and typed cross-quantity results (Displacement3D.Cross(Force3D)returnsTorque3D). - Construction-time invariants:
IVector0magnitudes are guarded non-negative, and quantities where zero is unphysical (Wavelength,Period,HalfLife) are guarded strictly positive. - Physical constants:
PhysicalConstantswith domain-grouped generic accessors that materialize into anyT : INumber<T>. - Generator diagnostics: metadata problems (
SEM001-SEM005) are caught at build time.
Installation
Package Manager Console
Install-Package ktsu.Semantics.Quantities
.NET CLI
dotnet add package ktsu.Semantics.Quantities
Package Reference
<PackageReference Include="ktsu.Semantics.Quantities" Version="x.y.z" />
For a project that uses one storage type everywhere, reference an alias package instead (or in addition) so you can omit the generic argument. See storage-type aliases.
Usage Examples
Basic Example: magnitudes and operators
using ktsu.Semantics.Quantities;
Mass<double> m = Mass<double>.FromKilogram(2.0);
Speed<double> v = Speed<double>.FromMeterPerSecond(3.0);
MomentumMagnitude<double> p = m * v; // Mass * Speed -> MomentumMagnitude
double kg = m.Value; // stored SI-base value
// arithmetic and comparison are inherited
Speed<double> faster = v + Speed<double>.FromMeterPerSecond(5.0);
bool ok = faster > v;
// construction-time guard: a negative magnitude throws ArgumentException
// Speed<double>.FromMeterPerSecond(-1.0);
Vector quantities
using ktsu.Semantics.Quantities;
Force3D<double> f = new() { X = 3.0, Y = 4.0, Z = 0.0 };
ForceMagnitude<double> mag = f.Magnitude(); // matching Vector0 quantity, value 5.0
Force3D<double> unit = f.Normalize();
Displacement3D<double> d = new() { X = 1.0, Y = 0.0, Z = 0.0 };
double work = (f.X * d.X) + (f.Y * d.Y) + (f.Z * d.Z); // signed work in joules, 3.0
Torque3D<double> torque = d.Cross(f); // typed cross: r x F = Torque, (0, 0, 4)
Momentum3D<double> impulse = f * Duration<double>.Create(2.0);
Force and displacement have no typed dot product. Work is signed, and Energy has only a magnitude
form, so the work comes back as a bare number. Wrap it with Energy<double>.FromJoule(Math.Abs(work))
if you only need its size. The 5.0 migration guide
explains why.
Physical constants
using ktsu.Semantics.Quantities;
// domain-grouped, materialized into the numeric type you ask for
double c = PhysicalConstants.Fundamental.SpeedOfLight<double>(); // 299_792_458 m/s
decimal R = PhysicalConstants.Chemistry.GasConstant<decimal>(); // 8.31446... J/(mol.K)
// generic accessors materialize into any T : INumber<T>
double g = PhysicalConstants.Generic.StandardGravity<double>(); // 9.80665
ForceMagnitude<double> weight = Mass<double>.FromKilogram(70.0) * AccelerationMagnitude<double>.Create(g);
API Reference
Hand-written runtime types
| Type | Description |
|---|---|
SemanticQuantity<TSelf, T> |
Arithmetic base. Create(T) factory, Quantity value, and inherited + - * / - operators. Divide by zero throws DivideByZeroException. |
PhysicalQuantity<TSelf, T> |
Abstract base for scalar quantities. Adds Value, Dimension, IsPhysicallyValid, comparison operators, and cross-dimension-aware CompareTo/Equals. |
IVector0<TSelf, T> |
Magnitude-only marker: Value, static Zero. Non-negative by construction. |
IVector1<TSelf, T> |
Signed single-axis: Value, static Zero. |
IVector2 / IVector3 / IVector4 |
Directional vectors with X/Y/Z/W, Length(), LengthSquared(), Dot, Distance, Normalize; IVector3 adds Cross. |
Vector0Guards |
EnsureNonNegative(value, name) and EnsurePositive(value, name), used by generated From{Unit} factories. |
UnitSystem |
enum classifying units (SIBase, SIDerived, Metric, Imperial, ...). |
StorageMath |
Sqrt, Cbrt, RootN and Hypot over any T : struct, INumber<T>, with no IRootFunctions<T> constraint, which decimal could not meet. Generated Length() and Distance() use them; an application computing a norm the generator does not emit can too. |
Generated quantity types
Each generated quantity is a partial record Name<T> where T : struct, INumber<T>. A typical IVector0 quantity such as Mass<T> exposes:
| Member | Description |
|---|---|
From{Unit}(T) |
e.g. FromKilogram, FromGram, FromPound. Converts to SI base and applies the guard. |
Create(T) |
Inherited base factory (value already in SI base units). |
Value |
The stored SI-base value. |
In(unit) |
Convert the value back to a specific unit. |
| typed operators | e.g. Mass * AccelerationMagnitude -> ForceMagnitude, Mass / Volume -> Density. |
Vector quantities (Force3D<T>, Velocity2D<T>, ...) implement the matching IVectorN and add Magnitude() (returning the corresponding *Magnitude Vector0 quantity), Dot, Cross, and typed cross-quantity results.
Factory names use the singular lemma of each unit name verbatim (FromMeterPerSecond, FromRevolutionPerMinute). There is no pluralization step.
PhysicalConstants
- Domain-grouped: nested static classes with generic accessors, for example
PhysicalConstants.Fundamental.SpeedOfLight<T>(),PhysicalConstants.ClassicalMechanics.StandardGravity<T>(),PhysicalConstants.Thermodynamics.WaterTriplePoint<T>(). Domain groups include Acoustics, AngularMechanics, Chemistry, ClassicalMechanics, FluidMechanics, Fundamental, NuclearPhysics, Optics, and Thermodynamics. - Generic:
PhysicalConstants.Generic.Name<T>()is a flat accessor over every constant, regardless of domain. - Each constant is parsed from its metadata literal straight into
Tand cached per closed generic type, so the package carries no arbitrary-precision dependency and no rounding happens through an intermediate representation.
Architecture
The system is metadata-driven. The single source of truth is Semantics.SourceGenerators/Metadata/dimensions.json (alongside units.json, magnitudes.json, conversions.json, domains.json, and logarithmic.json). A Roslyn incremental generator emits one record per quantity, a From{Unit} factory per declared unit, the cross-dimensional * / / / Dot / Cross operators declared in the metadata, and the PhysicalConstants surface. Logarithmic-scale quantities (decibels, cents, pH) are generated separately because they do not obey linear arithmetic.
Generated output is committed to Generated/, so the project compiles without first running the generator. For the full design and an end-to-end "add a dimension" walk-through, see:
Contributing
Contributions are welcome! Feel free to open issues or submit pull requests.
License
This project is licensed under the MIT License. See the LICENSE.md file for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages (8)
Showing the top 5 NuGet packages that depend on ktsu.Semantics.Quantities:
| Package | Downloads |
|---|---|
|
ktsu.Semantics.Quantities.Decimal
A comprehensive .NET library for replacing primitive obsession with strongly-typed, self-validating domain models across four pillars: semantic strings with 50+ validation attributes, polymorphic path handling, metadata-generated semantic quantities, and musical value types. The quantity system covers 60+ physical dimensions and 200+ generated types under a unified vector model, with compile-time dimensional safety, generated unit conversions and physics relationships, centralized physical constants, and optional per-storage-type alias packages. The music types provide type-safe pitches, intervals, scales and modes, chords with symbol parsing and voicing, keys with roman-numeral analysis, and rational durations and time signatures. Features factory-pattern and dependency-injection support for building robust, maintainable scientific and domain-specific applications. |
|
|
ktsu.Semantics.Quantities.Double
A comprehensive .NET library for replacing primitive obsession with strongly-typed, self-validating domain models across four pillars: semantic strings with 50+ validation attributes, polymorphic path handling, metadata-generated semantic quantities, and musical value types. The quantity system covers 60+ physical dimensions and 200+ generated types under a unified vector model, with compile-time dimensional safety, generated unit conversions and physics relationships, centralized physical constants, and optional per-storage-type alias packages. The music types provide type-safe pitches, intervals, scales and modes, chords with symbol parsing and voicing, keys with roman-numeral analysis, and rational durations and time signatures. Features factory-pattern and dependency-injection support for building robust, maintainable scientific and domain-specific applications. |
|
|
ktsu.Semantics.Quantities.Float
A comprehensive .NET library for replacing primitive obsession with strongly-typed, self-validating domain models across four pillars: semantic strings with 50+ validation attributes, polymorphic path handling, metadata-generated semantic quantities, and musical value types. The quantity system covers 60+ physical dimensions and 200+ generated types under a unified vector model, with compile-time dimensional safety, generated unit conversions and physics relationships, centralized physical constants, and optional per-storage-type alias packages. The music types provide type-safe pitches, intervals, scales and modes, chords with symbol parsing and voicing, keys with roman-numeral analysis, and rational durations and time signatures. Features factory-pattern and dependency-injection support for building robust, maintainable scientific and domain-specific applications. |
|
|
ktsu.ImGui.NodeEditor
A visual node editor for Dear ImGui built on ImNodes, with the graph kept away from the drawing: the engine owns nodes, links and layout and knows nothing about ImGui, while the renderer draws what it holds and the input handler turns interactions into requests the engine can accept or refuse. Nodes can be declared as ordinary types decorated with ktsu.NodeGraph attributes and instantiated by reflection, with connections checked against the rules that metadata declares. Optional force-directed layout settles the graph, and the view zooms from quarter to double scale. Every edit can be undone through a ktsu.UndoRedo history, keyboard commands follow a ktsu.Keybinding keymap, dragged nodes can snap to the grid, and labelled comment boxes group regions of the graph and carry their nodes when moved. |
|
|
ktsu.Schema
A .NET library for defining, managing, and editing data structure schemas with a rich type system, type-safe identifiers, and polymorphic JSON serialization. Define structured data models programmatically or visually and serialize them to .schema.json files, providing a metadata foundation for code generation, data validation, and tooling that needs to reason about your data structures. Ships with an accompanying Dear ImGui desktop editor for visual schema authoring. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 6.0.0 | 0 | 11/11/2026 |
| 5.12.1 | 2,288 | 10/12/2026 |
| 5.12.0 | 233 | 10/11/2026 |
| 5.11.6 | 192 | 10/10/2026 |
| 5.11.5 | 784 | 10/9/2026 |
| 5.11.4 | 172 | 10/9/2026 |
| 5.11.3 | 434 | 10/8/2026 |
| 5.11.2 | 488 | 10/6/2026 |
| 5.11.1 | 305 | 10/6/2026 |
| 5.11.1-pre.1 | 100 | 10/5/2026 |
| 5.11.0 | 462 | 10/2/2026 |
| 5.10.0 | 304 | 9/30/2026 |
| 5.9.0 | 198 | 9/29/2026 |
| 5.8.5 | 191 | 9/29/2026 |
| 5.8.4 | 494 | 9/29/2026 |
| 5.8.3 | 585 | 9/28/2026 |
| 5.8.2 | 204 | 9/28/2026 |
| 5.8.1 | 204 | 9/28/2026 |
| 5.8.0 | 299 | 9/25/2026 |
| 5.7.0 | 316 | 9/24/2026 |
## v6.0.0 (major)
Changes since v5.0.0:
- Return the exact floor from 3D and 4D Hypot for 32-bit and narrower integers [patch] (#538) (matt-edmondson)
- Drop the "." parent when DirectoryPath's / operators combine [patch] (#540) (matt-edmondson)
- Ignore a trailing dot in FullFileExtension, as FileExtension does [patch] (#544) (matt-edmondson)
- Make the README vector and identifier examples compile, and test them [patch] (#546) (matt-edmondson)
- Add a SessionStart hook for Claude Code cloud sessions (#483) (matt-edmondson)
- Reject undefined enum values in the Pitch, PitchClass and Section factories [patch] (#535) (matt-edmondson)
- Throw DivideByZeroException from Divide\<TResult\> on a zero divisor [patch] (#534) (matt-edmondson)
- Count a minor key's vii° and vii°7 as diatonic dominants [patch] (#529) (matt-edmondson)
- Interpolate MixOklab, Lerp and Gradient premultiplied, so a transparent end adds no color [minor] (#528) (matt-edmondson)
- Return the exact floor from Sqrt and Hypot for 64-bit and 128-bit integers (#524) (matt-edmondson)
- Order benchmark history by SemVer precedence, so a prerelease charts before its release (#523) (matt-edmondson)
- Add CompatibilitySuppressions.xml to Color, Cpp, Music and Strings.Identifiers [patch] (#519) (matt-edmondson)
- Darken rather than invert a color already darker than the background in AdjustForContrast [patch] (#509) (matt-edmondson)
- Name the starting directory "." in Parent and a bare file's directory [patch] (#504) (matt-edmondson)
- Return a POH from PH.ToPOH instead of a pOH dressed as a pH [major] (#496) (matt-edmondson)
- Return a DirectoryName from every directory type's Name [major] (Claude)
- Refuse a section header outside the documented grammar (Claude)
- Use [[ ]] in the chart render script (Claude)
- Keep benchmark history's write permission and checkout off untrusted runs (Claude)
- Fail a pull request whose benchmark charts drift from their history (#303) (Claude)
- Start benchmark history from the CI run that published a release (#320) (Claude)
- [major] Strings: WeakString can only be set through Create (#310) (Claude)
- Address code-quality findings: zero pattern, local exception counter, explicit Where (Claude)
- Use the specific MSTest assertions Sonar asks for (Claude)
- Use Path.Join for test fixture paths (Claude)
- [patch] Strings: TryCreate rejects without exceptions; validation attributes and the WeakString setter cached per type (#443, #444) (Claude)
- [patch] C++ prelude: a representation widens implicitly and narrows only explicitly (#451) (Claude)
- [patch] Quantities: overloads forward their base's relationship operators (#456) (Claude)
- [patch] Quantities: constants per field, decimal logs, positive guards, division by zero, scaled vector lengths, bounded roots (Claude)
- Drop a redundant ToString in a test (Claude)
- Map roman-numeral round-trip bodies with Select (Claude)
- Parse music charts strictly and write their bar lines where the bars are [minor] (Claude)
- Spell pentatonic keys against a seven-degree scale, weigh every chord tone in key inference, and detect augmented sixths [patch] (Claude)
- [minor] Color: CSS named colors, alpha-aware contrast, gamut-mapped Oklab mixes (Claude)
- Read C+7, Cmaj7sus4 and lead-sheet groups, voice extended inversions, and keep a chord's body in its roman numeral [patch] (Claude)
- [patch] Resolve dot segments in IsRoot, DirectoryPath.Parent and Depth; skip unrepresentable entries in GetContents (Claude)
- Strip all whitespace from a pasted card number or ISBN [patch] (matt-edmondson)
- Write the root README's progression example in chart syntax [patch] (Claude)
- Yield the empty entry after a trailing separator from the span Split [patch] (Claude)
- Take an odd root of an integer MinValue without recursing forever [patch] (Claude)
- Apply the Windows path character and length rules only on Windows [patch] (Claude)
- Report a [RegexMatch] timeout as a validation failure (matt-edmondson)
- Refuse zero, negative and non-finite input to QFactor (matt-edmondson)
- Reject ISMNs (979-0) as ISBN-13s (matt-edmondson)
- Return Min from NormalizedParameter.Denormalize for a NaN position (matt-edmondson)
- Resolve dot segments before taking an absolute directory's parent (Claude)
- Fold Interval.MinValue without negating it (Claude)
- Move the trailing-line check out of Section.TryParse (Claude)
- Drop a redundant ToString in the arrangement trailing-newline test (Claude)
- Refuse a section line after the progression instead of dropping it (Claude)
- Reject IBAN check digits 00, 01 and 99 (Claude)
- Reject a refused chord modifier even when another modifier follows it [patch] (Claude)
- Return false from Duration.TryParse when the reduced fraction overflows int [patch] (Claude)
- Move the bar-based blues tests to the end of FormTests (Claude)
- Detect a twelve-bar blues by bars, not chord count [patch] (Claude)
- Refuse a form with more distinct sections than letters [patch] (Claude)
- Treat a dotfile as having no extension in RemoveExtension and ChangeExtension [patch] (Claude)
- Keep rejected identifier values out of validation messages [patch] (Claude)
- Reject NaN in Vector0 guards with ArgumentException [patch] (Claude)
- [patch] Resolve . and .. before taking a relative directory's parent (Claude)
- [patch] Keep a path relative when its left operand is empty (Claude)
- [patch] Reject unbalanced or repeated UUID braces and parentheses (Claude)
- Name secondary dominant targets by the mode's own triad [patch] (Claude)
- Escape section labels so ToString round-trips through Parse [patch] (Claude)
- Stop Duration arithmetic from wrapping silently on int overflow [patch] (Claude)
- [minor] Simulate color vision deficiencies at any severity in Semantics.Color (Claude)
- Build expected paths with Path.Join in RelativePathMakeTests (Claude)
- [patch] Compute RelativePath.Make by comparing paths, not URIs (Claude)
- [patch] Keep NormalizedParameter.Normalize in [0, 1] for out-of-domain values and reject empty ranges (Claude)
- [patch] Accept only one declared SectionType name in a section header (Claude)
- [patch] Reject JWT segments outside the unpadded base64url alphabet (Claude)
- [patch] Stop [PrefixAndSuffix] letting the prefix and suffix overlap, and reject empty strings (Claude)
- [patch] Require the 978/979 Bookland prefix on an ISBN-13 (Claude)
- [patch] Spell the raised seventh above a flat seventh as #7, not a lowered tonic (Claude)
- Filter IBAN whitespace with Where instead of an if inside the loop (Claude)
- [patch] Anchor IBAN, UUID and ULID patterns at the true end, and strip all whitespace from an IBAN (Claude)
- [patch] Strip every trailing separator when canonicalizing a path (Claude)
- [patch] Title-case [IsTitleCase] values with invariant rules, not the thread culture (Claude)
- [patch] Stop Pitch octaves wrapping into range, and reject whitespace or '+' in the octave (Claude)
- [patch] Keep Tempo.TryParse from throwing, and reject infinite tempos and non-positive beats (Claude)
- [patch] Reject whitespace in [IsBase64] regardless of total length (Claude)
- [patch] Reject non-hex characters in Color.FromHex with ArgumentException (Claude)
- [patch] Name the aeolian mode once (Claude)
- [patch] Parse "minor" and "natural_minor" as the Aeolian mode (Claude)
- [patch] Spell fully and half-diminished sevenths as vii°7 and viiø7 (Claude)
- Count CRLF once without advancing the loop counter in CountLines (Claude)
- [patch] Count every line break in HasMinimumLines, HasMaximumLines and HasExactLines (Claude)
- Merge main into dependabot/nuget/MSTest.Sdk-4.4.1 (Claude)
- Use a collection expression for the refused subjects in UnkeepableRelationshipTests (Claude)
- Assert the Go fix from ktsu.Coder and sync the SDK's .gitignore (Claude)
- [patch] Skip empty split entries in a loop, and honour TrimEntries and combined options (Claude)
- [patch] Scale Milliliter from the litre, not from cubic metres (Claude)
- [patch] Search only the file name for FileExtension and FullFileExtension (Claude)
- [patch] Keep ".." segments that climb above the start in RelativeDirectoryPath.Normalize (Claude)
- Derive the difference-form offset rule from applyV0Guard instead of an eighth parameter (Claude)
- [minor] Keep Vector0 magnitudes non-negative through unary minus and scalar * and / (Claude)
- Convert temperature differences with the factor alone, without the scale offset [patch] (Claude)
- [minor] Keep the major third in a b5 chord unless a minor third is spelled (Claude)
- Parse CMaj7, CmMaj7 and C°7 as the sevenths they name [patch] (Claude)
- Move CI onto the shared ci-shared.yml pipeline (Claude)
- Match path containment case to the platform and accept paths directly under a root [patch] (matt-edmondson)
- Parse "ionian" as the major mode, so a parsed Ionian key equals C major [patch] (matt-edmondson)
- Say why the quality-word loop body is empty [patch] (Claude)
- Strip the quality words without the netstandard2.0-missing Replace overload [patch] (Claude)
- Read C69, Cadd11 and Cadd13 as added tones, and reject leftover text [patch] (Claude)
- Let AdjustForContrast darken on mid-tone backgrounds [patch] (Claude)
- Assert reflexivity against a second instance, not the same reference (Claude)
- Compare semantic strings ordinally, matching their ordinal Equals (Claude)
- Add KilometerPerSecond, the unit orbital state vectors are quoted in (Claude)
- Say why precision.json omits PreciseNumber, and what adding a storage type means [patch] (matt-edmondson)
- Parse dimmaj7 as a diminished-major seventh, not a dim7 (Claude)
- Build a vector in the unit the caller thinks in, not raw SI [minor] (matt-edmondson)
- Keep a path's equality and hash code stable when a derived property is read [patch] (Claude)
- Regenerate SpecificAngularMomentum3D after merging main [patch] (Claude)
- Merge remote-tracking branch 'origin/main' into claude/semantics-240-orbital-dimensions (Claude)
- State the double-precision cost of a logarithmic conversion in its own docs [patch] (matt-edmondson)
- Use Assert.IsLessThan for the negative-energy assertion [patch] (Claude)
- Answer vector magnitude and distance with the dimension, not a bare T [minor] (Claude)
- Add GravitationalParameter, SpecificEnergy and SpecificAngularMomentum [minor] (Claude)
- Ship the storage-type alias props in build/, not buildTransitive/ [patch] (matt-edmondson)
- Merge main into the strings and paths benchmark work (matt-edmondson)
- Fix whole-branch review findings in benchmark docs [patch] (matt-edmondson)
- Fix review findings: bullet count and heading nesting (matt-edmondson)
- Document the strings and paths benchmarks [patch] (matt-edmondson)
- Backfill the strings and paths histories (matt-edmondson)
- Seed the strings and paths histories at 5.3.4 (matt-edmondson)
- Record what the validation ladder actually measured (matt-edmondson)
- Redirect stdin from /dev/null in the subject loops (matt-edmondson)
- Measure three subjects per run (matt-edmondson)
- Fix strings XML doc to describe HashCode, not CompareTo (matt-edmondson)
- Describe the panel the strings chart actually draws (matt-edmondson)
- Explain the Create ratio's outlier size in the source, not just the report (matt-edmondson)
- Draw the strings and paths charts (matt-edmondson)
- Pair the path types against System.IO.Path (matt-edmondson)
- Declare the relative path specimen as a const (matt-edmondson)
- Make RelativeFile a const, not a suppressed readonly field (matt-edmondson)
- Measure the path types, building and operating (matt-edmondson)
- Fix Ordering baseline to match the culture-sensitive comparison it pairs against (matt-edmondson)
- Compare like with like in the string ordering pair (matt-edmondson)
- Pair the string types against hand-written validation (matt-edmondson)
- Chart GetHashCode rather than CompareTo for strings (matt-edmondson)
- Measure a semantic string after it exists (matt-edmondson)
- Correct the expected cost of the two string failure paths (matt-edmondson)
- Measure creating a semantic string across the validation ladder (matt-edmondson)
- Make the release chart renderer subject-aware (matt-edmondson)
- Plan the strings and paths benchmark work (matt-edmondson)
- Design the benchmark history and charts for strings and paths (matt-edmondson)
- State the strict-floor rule once, and pin it [patch] (Claude)
- Refuse to label scale degrees the roman numerals cannot spell [patch] (Claude)
- Read "C6/9" as a six-nine chord, not a slash bass [patch] (Claude)
- Split the root loop into its two disciplines [patch] (Claude)
- Make StorageMath public, and add Cbrt, RootN and Hypot [minor] (Claude)
- Seed the abstraction-cost pair across every release [patch] (Claude)
- Compile the abstraction-cost benchmark against pre-4.0 quantities [patch] (Claude)
- Chart the quantity wrapper's cost per release [patch] (Claude)
- Measure the quantity types against the bare storage type [patch] (Claude)
- Build the source generator once, not twice into one directory [patch] (Claude)
- Seed the chart with every release the suite can measure [patch] (Claude)
- Chart performance per release, and show it in the README [patch] (Claude)
- Gate Dependabot auto-merge on CI actually being green (Claude)
- Decide whose PR it is from the API, not the event payload [patch] (matt-edmondson)
- Assert the Python projection fix the pin caught [patch] (matt-edmondson)
- Merge Dependabot PRs when CI is green, not when nothing is required [patch] (matt-edmondson)
- Add a PreciseNumber storage-type alias package [minor] (Claude)
- [patch] Address code quality findings on the storage conversion fixes (Claude)
- [patch] Fix storage conversion regressions from exact factors (matt-edmondson)
- Decide relative path validity from the string, not the working directory [patch] (matt-edmondson)
- ci: adopt the consolidated .NET workflow [patch] (Claude)
- [minor] Convert units exactly for every storage type (matt-edmondson)
- Repair a doc comment my own edit garbled (Claude)
- Find out whether the quantities reach seven languages, not two (Claude)
- Report the dimension that has exponents when two claim a unit [patch] (Claude)