Skip to content

Temporal: make the rule-version axis load-bearing (in-language versioning); reject in-heap EVAL UNDER COMMIT #912

Description

@mengwong

Summary

The multi-axis TemporalContext runtime shipped, but the rule-version axis is write-only. tcRuleValidTime / tcRuleVersionTime / tcRuleEncodingTime / tcRuleCommit are stamped by EVAL UNDER RULES EFFECTIVE AT (and re-stamped per stepped day by the interval builtins), yet no reader consumes them, so EVAL UNDER RULES EFFECTIVE AT is pure bookkeeping — the evaluator still runs the single in-memory rule set regardless of the axis. tcRuleCommit is only ever Nothing.

This is the tracking issue for making the rule-version axis genuinely load-bearing, and for recording the design decision (which rejects the old git-backed vision).

What already works (on unstable)

  • 8-axis TemporalContext + 4 EvalClause variants (UnderValidTime, AsOfSystemTime, UnderRulesEffectiveAt, UnderRulesEncodedAt); applyEvalClauses pure.
  • EVAL AS OF SYSTEM TIME is load-bearing (TODAY/NOW read tcSystemTime).
  • Interval builtins EVER/ALWAYS BETWEEN, WHEN LAST/NEXT, VALUE AT (day-stepping; each day re-applies [UnderValidTime d, UnderRulesEffectiveAt d]).
  • The T6 WHNFWhen context-fingerprint cache (thunk-leak fix, Local declarations #58) and PR#80 exception-unwind context restore — these turn out to be exactly the two preconditions any axis reader needs, and they already ship.

Decision

Make the rule-validity axis load-bearing in-language; keep git out of the evaluator heap.

  1. Phase 0RULES EFFECTIVE DATE, a nullary DATE builtin that reads tcRuleValidTime through an instrumented reader (new crRuleValidTime fingerprint axis). Rule versioning becomes ordinary L4: IF DATE_SERIAL RULES EFFECTIVE DATE AT LEAST DATE_SERIAL (Date 1 1 2024) THEN 9 ELSE 7. (spike done + verified — see linked issue.)
  2. Phase 1 — semantics hardening: finalize the unset-axis fallback, delete the latent tcRuleEncodingTime coercion bug, add RETROACTIVE TO sugar, trace/provenance polish.
  3. Phase 2 — authoring surface: @effective / @repealed / @label decorators on same-named DECIDEs, desugared at check time into one visible dispatcher over RULES EFFECTIVE DATE (no runtime dispatch value, no EvalState table, no hidden name-mangling). Each arm keeps its own source range + amending-instrument label for citations, NLG/TNR anchors, and diffability.
  4. Phase 3 — encoding-history counterfactuals as driver-level tooling (l4 diff-eval + a jl4-service deployment-version compare endpoint): two fully independent compile+eval passes diffed at the JSON boundary. No evaluator changes, nothing crosses a heap.

Permanently rejected: in-heap EVAL UNDER COMMIT

Splicing a separately-compiled module's References/constructors/entityInfo into a live evaluation is rejected on code-verified grounds:

  • imports resolve through project:/<name>.l4 (Import/Resolution.hs), so two snapshots collide on URIs and unique supplies → silent wrong-type dispatch;
  • the single caller-side entityInfo cannot describe historical constructors (cross-version values break both directions);
  • CONSIDER branches silently mis-select on sameResolved mismatch (worse than an error);
  • a published construct would mean different things per deployment config — disqualifying for an audit-grade legal SOR.

Any future revival must first solve URI namespacing and cross-version value marshalling — treat those as hard gates.

Why in-language wins

Design doc

Full reconciliation, per-approach kill-shots, phased plan with file:line insertion points, and the spike design live in specs/todo/TEMPORAL-RULE-VERSION-DESIGN.md (branch mengwong/temporal-rule-version, pending PR into unstable). The three older specs (TEMPORAL_EVAL_SPEC.md, TEMPORAL_PRELUDE_MACROS.md, TEMPORAL-MASTER.md) have been updated to mark the git-backed vision superseded.

Open questions (see design doc §6)

  • Unset-axis fallback: localized system-day vs tcValidTime-first vs hard error (leaning valid-time-first, for consistency with the interval builtins' per-day stamping).
  • Collapse tcRuleVersionTime into tcRuleValidTime vs give them distinct meanings.
  • Cache granularity under multi-decade day-stepping (regime-interval ReadObs refinement if a perf golden hurts).
  • Disposition of UNDER RULES ENCODED AT (warn "bookkeeping only" vs deprecate until Phase 3).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions