fix(datetime): consistent timezone view; feat(migrate): auto-load models - #55
Merged
Merged
Conversation
Two independent changes. DateTime component accessors were inconsistent about timezone: `hour` and `minute` returned UTC while `year`/`month`/`day`/`second`/`format`/`to_string` used the local zone, so composing parts of one value could print a wall time that never existed. `Value::DateTime(i64)` becomes `Value::DateTime(i64, bool)`, where the bool is a display/component view (`false` = process-local, `true` = UTC). Every component accessor now reads the same view. `.utc()` returns a same-instant value whose components are UTC, `.local()` switches back; equality, ordering, `to_unix` and `to_iso` ignore the flag and compare by instant. Static `DateTime.utc()` returns "now" in the UTC view, other constructors stay local. Breaking for code relying on bare `.hour()`/`.minute()` being UTC outside a UTC timezone. `soli db:migrate` now auto-loads `app/models` and `app/services` as an interpreter preamble, so data migrations can call `User.create(...)` or iterate `User.all()` without explicit imports. The walk is recursive and top-down (files before subdirectories, alphabetical) so a base class at an equal-or-shallower depth is defined first, matching `soli serve`. This holds on every backend: the SoliDB and SQL runners are separate code paths, and both load the preamble. Engine migrations load engine models the same way, and `db:seed` drops its hand-rolled non-recursive copy in favour of the shared helper. The preamble loop itself is now one `run_preamble_files` used by the test runner, seeds, and both migration runners. Also documents that `Duration.humanize` is magnitude-only — it never appends " ago", even for negative `Duration.between` results; `time_ago` is the relative-past phrasing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
solisoft
pushed a commit
that referenced
this pull request
Aug 26, 2026
…t 241 Two things that made the fuzz job red for reasons unrelated to the code under test. LeakSanitizer. cargo-fuzz builds with AddressSanitizer, which enables LSan too, and nothing set ASAN_OPTIONS. These targets exist to catch panics, stack overflows and UB in the surfaces that take untrusted input — not to audit allocation lifetimes. The interpreter is `Rc<RefCell<…>>`-based, so a closure capturing its defining environment forms a reference cycle that LSan correctly calls an unreachable "direct leak"; it is bounded and harmless in a process that exits. On PR #55 that failed the job *after* a completely clean fuzz — `Done 72817 runs in 21 second(s)`, then 446 bytes in 36 allocations — so every PR touching a fuzzed path inherited a red X that had nothing to do with its diff. Leak detection is now off for the fuzz step. The backtick guard in `template_parse_render` predates this and was partly justified by the same LSan behaviour; its other reason — rendering a backtick tag runs `sh -c <fuzzer bytes>` on the host — stands on its own, so the guard stays and the comment now says why. Unwrap ratchet. The regression tests added in the previous commit pushed `src/template` from 241 to 244 `.unwrap()`/`.expect()` calls and failed `scripts/lint_unwraps.sh`. The ratchet is meant to move in one direction, so the tests were rewritten to not need them (`let Ok(…) else`, and comparing against `Ok("ADA".to_string())`) rather than raising the baseline. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two independent changes.
DateTime component accessors were inconsistent about timezone:
hourandminutereturned UTC whileyear/month/day/second/format/to_stringused the local zone, so composing parts of one value could print a wall time that never existed.Value::DateTime(i64)becomesValue::DateTime(i64, bool), where the bool is a display/component view (false= process-local,true= UTC). Every component accessor now reads the same view..utc()returns a same-instant value whose components are UTC,.local()switches back; equality, ordering,to_unixandto_isoignore the flag and compare by instant. StaticDateTime.utc()returns "now" in the UTC view, other constructors stay local.Breaking for code relying on bare
.hour()/.minute()being UTC outside a UTC timezone.soli db:migratenow auto-loadsapp/modelsandapp/servicesas an interpreter preamble, so data migrations can callUser.create(...)or iterateUser.all()without explicit imports. The walk is recursive and top-down (files before subdirectories, alphabetical) so a base class at an equal-or-shallower depth is defined first, matchingsoli serve. This holds on every backend: the SoliDB and SQL runners are separate code paths, and both load the preamble. Engine migrations load engine models the same way, anddb:seeddrops its hand-rolled non-recursive copy in favour of the shared helper. The preamble loop itself is now onerun_preamble_filesused by the test runner, seeds, and both migration runners.Also documents that
Duration.humanizeis magnitude-only — it never appends " ago", even for negativeDuration.betweenresults;time_agois the relative-past phrasing.