Part of #80. Surfaced while implementing #122.
Problem
The TS conformance errors-baseline runner matches on (line, TSnnnn) tuples. But the runner type-checks via TypeChecker.CheckWithRecovery, and that path drops the TsCode: RecordTypeError maps the caught exception to an internal DiagnosticCode enum and calls DiagnosticCollector.AddError(code, message, location) — which constructs a Diagnostic with TsCode = null. The canonical TSnnnn carried on the exception (ex.Diagnostic.TsCode, e.g. "TS2322") is never propagated.
Consequence: only tests that expect zero errors can currently Pass. Any negative test produces diagnostics with null TsCode, which are excluded from baseline matching (by design, see Diagnostics/Diagnostic.cs), so the actual set is effectively empty and never matches a non-empty expected set.
This is why #122 (model call/construct signatures on object types) produced no baseline movement despite being correct — verified directly: with TsCode propagated, assignmentCompatWithConstructSignatures becomes a perfect match and flips to Pass, and assignmentCompatBetweenTupleAndArray also flips.
The catch — it unmasks pre-existing false positives
Simply propagating TsCode (one-line change in RecordTypeError + an optional tsCode param on AddError/AddWarning) is correct but regresses the committed baseline, because it surfaces latent false positives that were previously hidden behind null codes. Observed in the current subset (each a test expecting zero errors that then fails):
nullAssignableToEveryType, undefinedAssignableToEveryType — SharpTS flags var b: number = null etc.; TS treats null/undefined as assignable to everything under non-strict (strictNullChecks off), which is what these baselines assume.
assignmentCompatWithObjectMembers2, assignmentCompatWithObjectMembers3 — s = t between two identically-shaped classes; SharpTS uses nominal class typing (per CLAUDE.md) while TS compares structurally here.
intersectionIncludingPropFromGlobalAugmentation — TS2698/TS2339 false positives (separate gap).
Net with naive propagation in the current subset: +2 passes, −5 (unmasked) ⇒ baseline goes down. Hence it must not ship alone.
Scope (do together to keep the baseline green)
- Propagate
TsCode through the recovery path (RecordTypeError → AddError/AddWarning → Diagnostic.TsCode).
- Fix (or scope/skip) the unmasked false positives so the baseline is net-positive:
- non-strict
null/undefined assignability (likely the biggest lever; gate on a strict-null-checks flag that defaults off to match the conformance baselines),
- structural compatibility for identically-shaped classes where TS expects it,
- the intersection-augmentation case.
- Regenerate the baseline; confirm net new passes and zero regressions.
Payoff
Unlocks measurable conformance for every negative test — the entire point of the errors-baseline runner. #122's modeling (and #123's, once landed) becomes visible the moment this lands. Without it, correct type-checking work shows as no movement.
Part of #80. Surfaced while implementing #122.
Problem
The TS conformance errors-baseline runner matches on
(line, TSnnnn)tuples. But the runner type-checks viaTypeChecker.CheckWithRecovery, and that path drops theTsCode:RecordTypeErrormaps the caught exception to an internalDiagnosticCodeenum and callsDiagnosticCollector.AddError(code, message, location)— which constructs aDiagnosticwithTsCode = null. The canonicalTSnnnncarried on the exception (ex.Diagnostic.TsCode, e.g."TS2322") is never propagated.Consequence: only tests that expect zero errors can currently Pass. Any negative test produces diagnostics with null
TsCode, which are excluded from baseline matching (by design, seeDiagnostics/Diagnostic.cs), so the actual set is effectively empty and never matches a non-empty expected set.This is why #122 (model call/construct signatures on object types) produced no baseline movement despite being correct — verified directly: with
TsCodepropagated,assignmentCompatWithConstructSignaturesbecomes a perfect match and flips to Pass, andassignmentCompatBetweenTupleAndArrayalso flips.The catch — it unmasks pre-existing false positives
Simply propagating
TsCode(one-line change inRecordTypeError+ an optionaltsCodeparam onAddError/AddWarning) is correct but regresses the committed baseline, because it surfaces latent false positives that were previously hidden behind null codes. Observed in the current subset (each a test expecting zero errors that then fails):nullAssignableToEveryType,undefinedAssignableToEveryType— SharpTS flagsvar b: number = nulletc.; TS treatsnull/undefinedas assignable to everything under non-strict (strictNullChecksoff), which is what these baselines assume.assignmentCompatWithObjectMembers2,assignmentCompatWithObjectMembers3—s = tbetween two identically-shaped classes; SharpTS uses nominal class typing (per CLAUDE.md) while TS compares structurally here.intersectionIncludingPropFromGlobalAugmentation— TS2698/TS2339 false positives (separate gap).Net with naive propagation in the current subset: +2 passes, −5 (unmasked) ⇒ baseline goes down. Hence it must not ship alone.
Scope (do together to keep the baseline green)
TsCodethrough the recovery path (RecordTypeError→AddError/AddWarning→Diagnostic.TsCode).null/undefinedassignability (likely the biggest lever; gate on a strict-null-checks flag that defaults off to match the conformance baselines),Payoff
Unlocks measurable conformance for every negative test — the entire point of the errors-baseline runner. #122's modeling (and #123's, once landed) becomes visible the moment this lands. Without it, correct type-checking work shows as no movement.