Skip to content

fix(z3linq): DateTime round-trip — UTC ticks both ways (port of endjin#95) - #26

Merged
jsboige merged 4 commits into
mainfrom
fix/14445-datetime-ticks
Sep 4, 2026
Merged

jsboige merged 4 commits into
mainfrom
fix/14445-datetime-ticks

Conversation

@jsboige

@jsboige jsboige commented Sep 3, 2026

Copy link
Copy Markdown

Port of endjin#95 (their endjin#56/endjin#83) for CoursIA #14445 — two DateTime domain defects:

  1. Write: ToFileTimeUtc() counts from 1601-01-01 and throws ArgumentOutOfRangeException for anything earlier — no pre-1601 instant could be written. Encode as UTC ticks instead (ToUtcTicks).
  2. Read: FromFileTime decodes to LOCAL time (Kind=Local) while the write path encoded UTC — the same theorem answered differently on every machine, and the read-back carried the machine's offset. Read back as new DateTime(ticks, DateTimeKind.Utc) (ToDateTime), with a checked range guard naming the symbol (Z3's integer is unbounded; t.D > DateTime.MaxValue is satisfiable).

Two-step red/green proof (per #14445 acceptance amendment) — both runs on this fork's CI:

CI plumbing on this branch (required to make the pipeline able to run tests at all):

  • build.ps1: $SkipTest was true — the pipeline's Test job was a silent success that never ran dotnet test; now false. $SkipAnalysis = $true.
  • build.yml: compilePhaseTasks: 'Build' — the covenant SBOM tool pinned by Endjin.RecommendedPractices.Build 1.5.0+ (covenant 0.12.0, net6.0-only) dies with exit 150 on current runners; upstream endjin fixed this by migrating to ZeroFailed.
  • build.yml: runsOn: windows-latest — the last nuget.org Microsoft.Z3 (4.12.2) ships win-x64/osx-x64 natives only; on Linux the wrapper binds the ancient system libz3 and every context-creating test dies with EntryPointNotFoundException: Z3_enable_concurrent_dec_ref. Upstream consumes the GitHub-release 5.1.0 package via a pinned local feed instead.

The Kind assertion fails on a UTC runner too (FromFileTime marks Local unconditionally); the Ticks assertion adds the non-UTC discrimination. A ToUniversalTime() comparison passes before the fix and measures nothing — not used.

jsboige and others added 2 commits September 4, 2026 00:26
…tc Kind + Ticks read-back, out-of-range guard

Tests first, fix second: this commit alone must FAIL on CI (failing-before
proof per the #14445 acceptance amendment).

Co-Authored-By: Claude-Code <noreply@anthropic.com>
The pipeline never ran tests ($SkipTest = $true made the Test job a
silent success) and the Analysis phase died with exit code 150 because
Endjin.RecommendedPractices.Build 1.5.0+ pins covenant 0.12.0, a net6.0
tool, while ubuntu-24.04 runners no longer ship the .NET 6 runtime.
Skip analysis and enable dotnet test so the DateTime round-trip
regression (#14445) gets real red/green CI evidence.

See #14445
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

Test Results

87 tests   87 ✅  3s ⏱️
 1 suites   0 💤
 1 files     0 ❌

Results for commit 6eab957.

♻️ This comment has been updated with latest results.

…x natives

On ubuntu-24.04 the managed wrapper bound to the system libz3 (4.8.x)
and every context-creating test died with EntryPointNotFoundException
for Z3_enable_concurrent_dec_ref. The last nuget.org Microsoft.Z3
release ships win-x64/osx-x64 natives only; windows-latest resolves the
package's own libz3.dll, matching local dev machines. Upstream endjin
instead consumes the GitHub-release 5.1.0 package through a pinned
local feed.

See #14445
…rded read-back

Port of endjin#95 adapted to the 4.12.2 snapshot:

- ExpressionVisitor.VisitConstant: a DateTime constant is now encoded as
  its UTC ticks (Kind-aware: Local values are normalized via
  ToUniversalTime() before encoding), instead of ToFileTime() which is
  undefined before 1601-01-01 and loses the Kind
- Theorem read-back (ConvertZ3Expression + ConvertScalarExpr): values
  for DateTime symbols are rebuilt with new DateTime(ticks,
  DateTimeKind.Utc); an out-of-range model value raises an
  OverflowException naming the symbol instead of letting the DateTime
  ctor throw a bare ArgumentOutOfRangeException

Red run (4 DateTime tests failing, all others green):
https://github.com/MyIntelligenceAgency/Z3.Linq/actions/runs/33862719891
Green run: see next commit's dispatch

See #14445
@jsboige
jsboige merged commit f0da578 into main Sep 4, 2026
7 checks passed
jsboige added a commit to jsboige/CoursIA that referenced this pull request Sep 4, 2026
…ort of endjin#95) (#14594)

Submodule bump e09dae6 -> 6eab957. Two DateTime domain defects fixed:

- write path: ToFileTimeUtc() throws for pre-1601 instants and loses the
  Kind; DateTime constants are now encoded as UTC ticks (ToUtcTicks,
  Local values normalized first)
- read path: FromFileTime decodes to machine-local time; model values
  for DateTime symbols are rebuilt as new DateTime(ticks, Utc) with a
  range guard raising OverflowException naming the symbol

Two-phase CI proof on the fork (per the acceptance amendment):

- RED (tests-only state) -- exactly 4 failures, all DateTimeRoundTripTests,
  genuine assertions (Win32 FileTime out of range / Kind Local / missing
  guard), other 83 pass:
  https://github.com/MyIntelligenceAgency/Z3.Linq/actions/runs/33862719891
- GREEN (fix) -- 87/87:
  https://github.comMyIntelligenceAgency/Z3.Linq/actions/runs/33863182778

Fork PR: MyIntelligenceAgency/Z3.Linq#26
The branch also carries the CI plumbing required to run tests at all
($SkipTest was true, covenant tool dead, no linux natives in the last
nuget.org Microsoft.Z3) -- detailed in the fork PR body.

Closes #14445
jsboige added a commit that referenced this pull request Sep 4, 2026
…eaches the notebooks (#27)

The round-trip fix landed in the sources and its 87 tests, but not in the
artifact the notebooks actually load. `.deploy/*.dll` is git-tracked (e09dae6,
"commit .deploy DLLs for fresh-clone #r resolution") and 17 CoursIA notebooks
bind to it via `#r "../Z3.Linq/.deploy/Z3.Linq.dll"`. PR #26 changed
ExpressionVisitor.cs and Theorem.cs but did not rebuild that binary, so the
blob was byte-identical across the fix (83f9901 both sides) and every notebook
kept running the old file-time encoding.

Measured, with the control in both directions:

  symbol            deployed(old)   rebuilt(new)
  ToUtcTicks              0              1
  ToFileTimeUtc           1              0
  FromFileTime            1              0

Only Z3.Linq.dll changes: ExpressionUtils.dll, Microsoft.Z3.dll and libz3.dll
are byte-identical to what the pinned packages restore, which also rules out
spurious rebuild noise.

dotnet test Release: 87/87 passed, 0 failed (local, net8.0).

See #14445, jsboige/CoursIA#14169 (G5).
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