Skip to content

Sensitivity's dimensional formula matches neither V/Pa nor A/Pa, and the .NET generator emits the operator the C++ projection refuses #216

Description

@matt-edmondson

The metadata

Semantics.SourceGenerators/Metadata/dimensions.json:

"name": "Sensitivity",
"symbol": "M⁻¹ L⁻¹ T² I",
"dimensionalFormula": { "mass": -1, "length": -1, "time": 2, "electricCurrent": 1 },
"availableUnits": ["VoltPerPascal"],
"integrals": [ { "other": "Pressure", "result": "ElectricPotential" } ]

Its only unit is VoltPerPascal, symbol V/Pa (units.json:890-893). Working the exponents out:

M L T I
declared −1 −1 2 1
V/Pa — what the unit says 0 3 −1 −1
A/Pa — what CLAUDE.md says is declared −1 +1 2 1

The declared vector is neither. CLAUDE.md's own account ("declared as A/Pa, M⁻¹L⁻¹T²I") is itself inconsistent — A/Pa has length +1, not −1.

The relationship then computes Sensitivity × Pressure = L⁻² I, against ElectricPotential = M L² T⁻³ I⁻¹.

Checking every integrals / derivatives / dotProducts / crossProducts entry in the file: exactly four are dimensionally false, matching the set CLAUDE.md documents. Three are the rotational/angle cluster, which is structurally unfixable and correctly explained. This is the fourth, and it is not.

What ships

The C++ projection refuses it — Semantics.Cpp/QuantityVocabulary.cs:216-222, asserted by Semantics.Cpp.Test/CppQuantityGeneratorTests.cs:190-203.

The .NET generator has no dimensional check at all. SEM001 verifies only that names resolve; there is no exponent arithmetic anywhere in Semantics.SourceGenerators. So the operator is emitted into committed generated source:

// Semantics.Quantities/Generated/…/QuantitiesGenerator/Sensitivity.g.cs:123
public static VoltageMagnitude<T> operator *(Sensitivity<T> left, Pressure<T> right) =>
    VoltageMagnitude<T>.Create(left.Quantity * right.Quantity);

A caller writing sensitivity * pressure gets a VoltageMagnitude back — type-checked, and silently wrong by a factor carrying units of m⁻⁵·kg⁻¹·s⁴·A².

Why it matters

The point of the type system is that a dimensionally wrong product does not compile. Here it does, and yields a named quantity.

It also means the two projections of one metadata file disagree about what the vocabulary contains — at exactly the place the library promises they do not.

Suggested fix

Two separable pieces:

(a) Fix the metadata. This is a physics call between:

  • V/Pa — {"length": 3, "time": -1, "electricCurrent": -1}, matching the declared unit and making the relationship true; or
  • A/Pa — {"mass": -1, "length": 1, "time": 2, "electricCurrent": 1}, which requires both the unit and the relationship to change.

The symbol string needs updating either way, and CLAUDE.md's description of the bug needs its sign corrected.

(b) Port the exponent check to the .NET generator as a new SEM00x, so the two sides cannot diverge again. The arithmetic already exists in Semantics.Cpp/DimensionVector.cs; today a false relationship is caught only if it happens to reach the C++ projection.

Part (b) is the more durable half — (a) fixes one entry, (b) makes the next one impossible to miss.

Activity

  1. matt-edmondson commented on Sep 11, 2026

    @matt-edmondson
    ContributorAuthor

    Triage

    Priority: High Effort: Medium

    What needs to be done: Sensitivity's declared dimensional formula matches neither its own unit (V/Pa) nor the A/Pa reading CLAUDE.md describes (which is itself internally inconsistent about the sign). The C++ projection catches this and refuses to emit the Sensitivity × Pressure = ElectricPotential operator, but the .NET generator has no dimensional-consistency check at all, so it emits the operator into committed generated source — a type-checked but dimensionally false physics relationship that silently ships.

    Suggested next steps / acceptance criteria:

    • (a) Physics decision + metadata fix: pick the correct formula for Sensitivity — either V/Pa with {length: 3, time: -1, electricCurrent: -1} (matches the declared unit, makes the relationship true) or A/Pa with {mass: -1, length: 1, time: 2, electricCurrent: 1} (requires changing the unit too) — and correct the symbol string and CLAUDE.md's description to match. This step needs a maintainer/physics call before implementation, not just a code change.
    • (b) Port the exponent-consistency check from Semantics.Cpp/DimensionVector.cs into the .NET generator as a new SEM00x diagnostic, so this class of divergence is caught at generation time for every relationship, not just the ones that happen to reach the C++ projection.

    Blockers / dependencies: Part (a) is blocked on a physics decision (which of the two formulas is correct) — flag for maintainer input. Part (b) is independent and can proceed without waiting on (a); it's the more durable fix since it prevents the next such error from being invisible on the .NET side.


    Generated by Claude Code

  2. matt-edmondson commented on Sep 21, 2026

    @matt-edmondson
    ContributorAuthor

    Both halves of this have already landed on main

    I picked this up to implement part (b) — the triage note says it is unblocked and independent — and found that both (a) and (b) are already done. Verified against main at cf10208:

    (a) The metadata is fixed, and the V/Pa reading won. Semantics.SourceGenerators/Metadata/dimensions.json now declares:

    "name": "Sensitivity",
    "symbol": "L³ T⁻¹ I⁻¹",
    "dimensionalFormula": { "length": 3, "time": -1, "electricCurrent": -1 }

    That is exactly the first of the two options this issue proposed, and it matches the declared VoltPerPascal unit. The relationship is now dimensionally true — working the exponents out from the current file:

    M L T I
    Sensitivity 0 3 −1 −1
    Pressure 1 −1 −2 0
    product 1 2 −3 −1
    ElectricPotential 1 2 −3 −1

    The product and the declared result agree on every axis. So the emitted Sensitivity<T> * Pressure<T> => VoltageMagnitude<T> operator is no longer the dimensionally false one described here — it is correct now, which is why it is still present in the committed generated source.

    (b) The exponent check is in the .NET generator, as SEM008. AnalyzerReleases.Unshipped.md registers it as "Reports a relationship whose declared result does not follow from the dimensions of its operands, or whose signed value cannot land in a magnitude result." The arithmetic was not re-implemented — DimensionVector and QuantityVocabulary moved into a shared Semantics.Vocabulary project, which Semantics.SourceGenerators.csproj compiles in as source (<Compile Include="..\Semantics.Vocabulary\*.cs" />), so the two projections now run the same check rather than only the C++ side having one. Emission is driven by the vocabulary, so no operator is generated for a refused relationship.

    The documentation was updated too, so there is no stale sign left to correct: CLAUDE.md:146-150 records the fix and the L³ T⁻¹ I⁻¹ formula, Semantics.Vocabulary/README.md:13-14 explains the SEM001/SEM003-only history, and docs/migration-guide-5.0.md:124-125 notes this relationship specifically.

    Nothing in the acceptance criteria is outstanding, so I am closing this as completed rather than opening a no-op PR. Please reopen if the physics call between V/Pa and A/Pa was meant to go the other way — that is the one thing I took as settled by the committed metadata rather than verified independently.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions