Repository navigation
Keep timestamps 64-bit through function and method parameters, integer array fields and array.from, and in a time input that is changed, copied or kept in a var - #322
Conversation
…d array fields Pine's int is 64-bit. Callable parameters, method parameters, UDT array fields and array literals built from time inputs were lowered to 32-bit C++ int, truncating epoch-millisecond values. Their storage and arguments now keep the wide integer type when the value can be an epoch time. Adds emission rows, boundary rows and engine-run rows for each shape, with pins for the shapes that must stay narrow. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The method form `arr.push(value = x)` is refused with "wrong number of arguments" because the keyword argument of an array method call is dropped before lowering; that is a separate gap from timestamp field width. Remove that value from the timestamp storage rows and pin today's behaviour in a plainly named known-gap row, to be updated when the keyword binding is fixed. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
… array fields instead of refusing them A Pine int holds millisecond timestamps, but the generated C++ narrowed it to a 32-bit int in user-function parameters, typed int method parameters, array<int> fields of a user-defined type and array.from(input.time()). The value wrapped silently (gcc) or the build failed (clang). Timestamp-connected array<int> storage now follows one shared width plan: record fields, constructors, aliases, copies, typed parameters, results, tuple elements and history all use 64-bit elements together, where the earlier approach refused such fields with a static_assert in the generated C++ and so stopped scripts that TradingView accepts. Missing-value sentinels are translated when a value crosses an integer width, arithmetic after a wide boundary uses binary64 operands (TradingView's int is a binary64 value above 2**53, so exactness above that is not promised), and the native behaviour rows in tests/test_timestamp_int_width_native.py compare each case with a Pine reference computed in the same script. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…y, and fix the paths it missed The first version of the width plan widened slots that carry no timestamp (a same-spelled local of another function, a plain 32-bit method argument, a chart-builtin subtraction) and still narrowed a typed method parameter stored into a record field, the history of a field alias, and named-argument array writes. A loop-local array built from a timestamp also got a double element type next to an int64 initializer, which the C++ compiler refused where the old output built. The plan now resolves array element families and integer expressions in their lexical owner, declaration emission consumes that same plan, a field's provenance is recomputed when the scalar analysis grows, and the binary64 conversion is used only where a value crosses a widened boundary. Namespace array.push binds its named id and value arguments. Behaviour rows compare each result with a Pine reference computed without the path under test; rows for shapes that fail the same way on the old output (a destructured array tuple, a delayed persistent array) are not part of this change. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…visited along every path The reachability walks that decide whether a value comes from a widened source copied their visited set on every call. A value reached again through a sibling path was explored again, so a name reassigned many times, or a chain of values each built from the previous one twice, made the translator's work grow factorially or exponentially with the script and some scripts never finished. Each query now shares one visited set across all its paths. A repeated node has the same successors, so expanding it once gives the same yes-or-no answer; the set stays local to one query because the surrounding provenance scan can grow between queries. Declaration write lists and callable returns are keyed by their identity and specialization so another owner or call site stays a separate question. New rows translate and run the graphs that cannot finish on the old walk, and count walk calls at two sizes to show growth is linear, not factorial. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…iteral parameters, and keep a missing integer missing The wider timestamp handling resolved a function-local variable by its declaration but still read the old spelling-based name set for its series type, so an untyped local holding time, or a typed int local holding it, lost its 64-bit series; a block-local int that shadows a wide global no longer widened the destination of a product above int32, so the stored value became missing; a wide literal passed into an integer parameter was not recognised as a widened parameter, so the binary64 subtraction above 2**53 was exact int64 arithmetic instead; and a missing integer kept as a double NaN reached a 32-bit method parameter as zero. A callable-local series now follows its own declaration and writes, a shadow's operand bound follows its own writes before the existing magnitude bound is applied, a scalar parameter's emitted width is the boundary, and a stored double read is translated to the integer missing value when it crosses into a narrower integer parameter. Two tests that pinned a refusal of a script whose helper shares a spelling with another function's epoch local now assert the accepted, separately typed declarations, because that refusal went away with the spelling leak. One behaviour row read the first element of an array that is appended to on every bar; it now reads the last. New rows cover the function-local epoch history, the shadowed product and the same-named counter beside an epoch local. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…alue from its emitted storage, and cover a changed time input A plain local initialised from a read of a history parameter (previous = value[1]) borrowed the analyzer's integer type from the series inventory, which also lists parameters that have no local declaration, so a 64-bit history read was narrowed to 32 bits and the integer missing value was lost. The callable-local series type now requires an actual declaration, which keeps the widening of a local that holds an epoch and restores the na-aware fallback for the history read. A top-level value computed by a callable with a widened parameter was folded to an exact integer from its actual argument before the width was known, so a difference above 2**53 was exact instead of the binary64 value TradingView gives. Such folds are now dropped once the width inventories exist, following aliases through their declarations. New behaviour rows cover an input.time variable that is later changed (typed, untyped, var, copied, assigned late), and controls for the unchanged date-range shape; one row that hit a separate, older defect with a local named like a function now asks only about the epoch history. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…e rows independent of unrelated defects The behaviour rows for time-input variables now include a copy of an unchanged time input (typed, untyped and var), which also wrapped on the previous version, and a var time input compared with the bar time. The two rows for a non-var global that is changed compare the first bar only, because later bars also depend on a separate defect (a changed input-backed global is not restarted from its input on each bar), and the tuple row no longer shares a spelling with a user function, an older and separate defect. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…ger function locals, integer field reads, and arithmetic on values that were already 64-bit A translate-only comparison against a population of public scripts showed the wider timestamp handling also changed code that carries no timestamp: a bool function-local series was typed bool and an integer count local was typed int where the previous version used the double series, a read of an integer record field into an integer slot gained a conversion wrapper, and arithmetic on parameters, array elements and variables that were already 64-bit gained the binary64 form. The callable-local series lookup now decides only whether an integer local holds an epoch, the field-read conversion follows the actual argument bindings instead of any non-literal write, and the binary64 arithmetic is used only when a value crosses a boundary this change widened. New rows pin the previous text for each unrelated shape and fail on the version that changed it. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 4 advisory finding(s) below merit a look before merge.
Not checked: tests were not run; formal verification proved 0 of 35 changed function(s) (13 sampled, not proven, 22 not verified).
Formal verification. PR-changed functions: 13/35 verified (0 proven, 13 may-equivalent, 0 distinguished) · 22 not verified (12 unsupported, 10 over cap).
Not verified on this run: \_\_init\_\_ (unsupported), \_generate\_cpp (unsupported), \_emit\_func\_def\_body (unsupported), \_callable\_series\_local\_symbol (unsupported), \_expr\_returns\_wide\_int (unsupported), \_func\_int\_return\_uses\_wide\_history (unsupported), \_int\_arith\_bound (unsupported), \_is\_int64\_builtin\_init (unsupported), \_narrow\_int\_bound (unsupported), \_narrow\_int\_name\_info (unsupported), and 2 more; 10 changed function(s) beyond the cap and 0 skipped when the time budget ran out.
Graphify review — findings
Adds a whole-program pass, prepare_array_widths, that finds connected integer arrays (UDT fields, locals, parameters, return values, tuples, history) and promotes each connected group to int64 together, while unconnected small-int arrays keep their original C++. Declaration, constructor, parameter, result, tuple and history type emission now read this shared plan, so widths agree across callable boundaries without inserting conversions. The risk sits in the plan's inputs and consumers: spec_of types int64 builtin calls as plain int and a single for-in variable as the index rather than the element, and UDT struct emission may not apply the widened field slots.
Worth a look
- UDT struct emission ignores widened field slots from prepare_array_widths —
pineforge_codegen/codegen/base.py:5323· Escalate · medium- NOT verified (no proof, no reproducing execution) — needs human review
- int64 builtin calls are typed as plain
int—pineforge_codegen/codegen/array_field_width.py:187· Escalate · medium- NOT verified (no proof, no reproducing execution) — needs human review
- for-in over an array: a single loop variable is typed as the int index instead of the element —
pineforge_codegen/codegen/array_field_width.py:153· Escalate · medium- NOT verified (no proof, no reproducing execution) — needs human review
- Imported helper
timestamp_array_fieldsmay not exist in array_field_width —pineforge_codegen/codegen/base.py:5312· Escalate · medium- NOT verified (no proof, no reproducing execution) — needs human review
Review partial — this diff was larger than one review pass covers, so later files were not reviewed; some findings may be missing.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 4082 functions depend on the 999 functions this change touches.
Health — this change adds coupling hotspots:
- new:
prepare_array_widths()— 2 callers, 7 callees - new:
spec_of()— 2 callers, 6 callees
Verification — 4082 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 3325 function(s) in the blast radius were not formally verified this run
Cross-repo impact
Cross-repo impact
No cross-repo impact detected among the indexed peer repo(s).
1 peer repo(s) in this group are not yet indexed — cross-repo impact may be incomplete.
Cross-repo linkage is derived (SCIP-moniker matches are sound; name/contract matches are heuristic) and ADVISORY — it never affects this check's conclusion.
Docs that may be stale (advisory)
AGENTS.md§ File map (lines 152-335): references changed symbolsdeclaration,missingAGENTS.md§ Support contracts (lines 379-657): references changed symbolsdeclaration,missingAGENTS.md§ Known codegen quirks (read before changing) (lines 658-1116): references changed symbolsslotsCHANGELOG.md§ Pine translation and diagnostics (lines 1800-1840): references changed symbolsslotsCHANGELOG.md§ Values that came out silently wrong (lines 1894-1930): references changed symbolsdeclarationCLAUDE.md§ File map (lines 152-335): references changed symbolsdeclaration,missingCLAUDE.md§ Support contracts (lines 379-657): references changed symbolsdeclaration,missingCLAUDE.md§ Known codegen quirks (read before changing) (lines 658-1116): references changed symbolsslotsREADME.md§ Trace intermediate expressions (@pf-trace) (lines 419-448): references changed symbolstaildocs/PUBLIC_CONTRACT.md§ Optional compiled execution capabilities (lines 54-197): references changed symbolsmissing
…and 5 more.
Formal verification
Could not verify: Could not verify \_\_init\_\_.
The verifier did not have enough to check \_\_init\_\_, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
Could not verify: Could not verify \_generate\_cpp.
The verifier did not have enough to check \_generate\_cpp, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
No difference found (not proven): No behavior difference found in \_lower\_collection\_history (not a proof).
The verifier ran both versions of \_lower\_collection\_history on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: the synth_receiver tier. A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
Could not verify: Could not verify \_emit\_func\_def\_body.
The verifier did not have enough to check \_emit\_func\_def\_body, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
No difference found (not proven): No behavior difference found in \_array\_from\_element\_spec (not a proof).
The verifier ran both versions of \_array\_from\_element\_spec on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: the synth_receiver tier. A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
Could not verify: Could not verify \_callable\_series\_local\_symbol.
The verifier did not have enough to check \_callable\_series\_local\_symbol, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
No difference found (not proven): No behavior difference found in \_coerce\_int\_slot (not a proof).
The verifier ran both versions of \_coerce\_int\_slot on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: the synth_receiver tier. A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
No difference found (not proven): No behavior difference found in \_collection\_lvalue\_spec (not a proof).
The verifier ran both versions of \_collection\_lvalue\_spec on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: the synth_receiver tier. A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
No difference found (not proven): No behavior difference found in \_emitted\_value\_is\_double (not a proof).
The verifier ran both versions of \_emitted\_value\_is\_double on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: the synth_receiver tier. A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
No difference found (not proven): No behavior difference found in \_expr\_is\_int64\_builtin (not a proof).
The verifier ran both versions of \_expr\_is\_int64\_builtin on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: the synth_receiver tier. A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
Could not verify: Could not verify \_expr\_returns\_wide\_int.
The verifier did not have enough to check \_expr\_returns\_wide\_int, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: synthesized inputs (no suite coverage): POSSIBLE DIFFERENCE on 4 constructed input(s) — both versions returned but disagreed on the args (e.g. old=["list", [["int", "0"], ["int", "1"], ["set", [["tuple", []]]], ["none"]]], new=["list", [["int", "0"], ["int", "1"], ["set", [["tuple", [["str", "expr"], ["int", "140297618243432"], ["str", ""], ["none…]]], ["none"]]]); ADVISORY, unverified — a synthesized input may violate an unstated precondition, so this is NOT a sound refutation and does NOT gate the merge; confirm with a real test, or let carve/property refute on real inputs; property tier: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
Could not verify: Could not verify \_func\_int\_return\_uses\_wide\_history.
The verifier did not have enough to check \_func\_int\_return\_uses\_wide\_history, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
No difference found (not proven): No behavior difference found in \_func\_param\_int\_cpp\_type (not a proof).
The verifier ran both versions of \_func\_param\_int\_cpp\_type on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: the synth_receiver tier. A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
No difference found (not proven): No behavior difference found in \_infer\_type (not a proof).
The verifier ran both versions of \_infer\_type on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: the synth_receiver tier. A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
Could not verify: Could not verify \_int\_arith\_bound.
The verifier did not have enough to check \_int\_arith\_bound, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
Could not verify: Could not verify \_is\_int64\_builtin\_init.
The verifier did not have enough to check \_is\_int64\_builtin\_init, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
No difference found (not proven): No behavior difference found in \_na\_aware\_wide\_is\_double (not a proof).
The verifier ran both versions of \_na\_aware\_wide\_is\_double on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: the synth_receiver tier. A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
Could not verify: Could not verify \_narrow\_int\_bound.
The verifier did not have enough to check \_narrow\_int\_bound, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
Could not verify: Could not verify \_narrow\_int\_name\_info.
The verifier did not have enough to check \_narrow\_int\_name\_info, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
No difference found (not proven): No behavior difference found in \_param\_is\_integer\_scalar (not a proof).
The verifier ran both versions of \_param\_is\_integer\_scalar on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: the synth_receiver tier. A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
Could not verify: Could not verify \_series\_type\_for.
The verifier did not have enough to check \_series\_type\_for, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
Could not verify: Could not verify \_type\_for\_decl.
The verifier did not have enough to check \_type\_for\_decl, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
No difference found (not proven): No behavior difference found in \_type\_spec\_from\_expr (not a proof).
The verifier ran both versions of \_type\_spec\_from\_expr on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: the synth_receiver tier. A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
No difference found (not proven): No behavior difference found in \_udt\_array\_field\_target (not a proof).
The verifier ran both versions of \_udt\_array\_field\_target on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: the synth_receiver tier. A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
No difference found (not proven): No behavior difference found in \_udt\_receiver\_type\_name (not a proof).
The verifier ran both versions of \_udt\_receiver\_type\_name on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: the synth_receiver tier. A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
· 2 grounded finding(s) anchored inline below.
| return spec | ||
|
|
||
|
|
||
| def prepare_array_widths(gen): |
There was a problem hiding this comment.
prepare_array_widths()
fans out to 7 callees (efferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
| return declarations[(scope, expr.name)], owner | ||
| return declarations.get(("", expr.name)), None | ||
|
|
||
| def spec_of(expr, owner, seen=frozenset()): |
There was a problem hiding this comment.
spec_of()
fans out to 6 callees (efferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
Fixes #285
Fixes #321
A Pine
intholds millisecond timestamps (time,input.time(),timestamp()), but the generated C++ narrowed it to a 32-bitintin several places, so the value wrapped silently (gcc) or the build stopped (clang). This change keeps everyintthat carries a timestamp 64-bit.On the released version this declares
int x, so the selected timestamp wraps to a negative number. The same wrap happened for a time input kept in avarvariable, for a copy of a time input (observed = x), for the integer parameters of a user function fed frominput.time()(inWindow(s, e) => time >= s and time <= e), for a typedintparameter of a method that stores it in a field, for anarray<int>field of a user-defined type (b.stamps.unshift(time)), and forarray.from(input.time()).What changes
Cause. The generated type of an integer was chosen from the Pine type alone (
int), and only a few paths asked whether the value that reaches a slot can be a timestamp: an integer parameter, a method parameter, an array field, an array built byarray.from, a copy of a time input and a time input kept in a variable that is later written each took the 32-bit default.Change (
pineforge_codegen/codegen/:types.py,array_field_width.py,base.py,visit_call.py,visit_expr.py,visit_stmt.py,emit_top.py,collection_history.py). A value is wide when a timestamp can reach it, decided from the declaration and the writes of that variable (by declaration identity, never by the spelling of a name): a user-function parameter or a typed method parameter that receives one, anarray<int>field of a record (one 64-bit storage plan for the field, its constructors, aliases, copies, tuples and history), an array built byarray.from, a copy of one, and a variable that is written from one (changed, copied or kept invar). Missing values (na) are translated when a value crosses an integer width, and arithmetic on a value that crossed a boundary this change widened uses binary64, because TradingView'sintis a binary64 value above 2^53 (a subtraction at 2^53 + 17 gives 16, not 17): the target is "no 32-bit narrowing", not exact 64-bit integers above 2^53. Named arguments ofarray.push(value = ..., id = ...)now write the array. Scripts without a timestamp keep the C++ they had (see Verification). The walk that decides this visits each expression once per query, so its work is linear in the script (call-count tests pin it).A missing value that reaches one of these 64-bit slots stays missing: a floating-point na or a 32-bit integer na passed to a 64-bit integer parameter, stored into a 64-bit integer array element, or given to an int field of a user type in .new() becomes the 64-bit missing value (the previous version could store 0 for an int field given na).
No script that the previous version translated is now refused, and nothing was added to any refusal list.
Known limits (separate defects, not changed here)
varvariable declared frominput.time(...)and changed later is not restarted from its input on each bar (the generated code keeps accumulating the change), so only the first bar of the two native rows for that shape is compared; they are marked in the test file. This change fixes the width; the restart is a separate defect.intabove 2^53 is a floating-point value; exact integers there are not promised.Verification
var, copy-then-changed, a late assignment, avarinput compared with the bar time, function and method parameters, array fields,array.from, tuples, history). On main plus the earlier revision of these tests (7 changed test files), 93 tests fail and none outside those files; on this head all pass. The control rows for the usual date-range shape (time >= startTimewith a time input kept in an ordinary variable) pass on both. Eleven translation rows pin the text main emits for scripts without a timestamp (a bool or count function-local history, an integer record field read into an integer slot, arithmetic on values that were already 64-bit): they fail on the revision of this change that altered them and pass on main (run on main plus that one test file: all eleven pass).pineforge_codegen/andtests/.