Skip to content

Classify UDF-wrapped and var-scalar stable expressions as TA lengths#54

Merged
luisleo526 merged 1 commit into
mainfrom
fix/stable-ta-length-udf-var
Jul 10, 2026
Merged

Classify UDF-wrapped and var-scalar stable expressions as TA lengths#54
luisleo526 merged 1 commit into
mainfrom
fix/stable-ta-length-udf-var

Conversation

@luisleo526

Copy link
Copy Markdown
Contributor

What

The stable-TA-length guard hard-rejected two bar-invariant shapes:

  1. A TA constructor length computed through a pure single-expression user-defined function — any UDF call was classified as series-valued, so e.g. ta.lowest(low[1], f_bars(mins)) with f_bars(m) => math.max(1, math.round(m*60/tfSec)) refused to transpile.
  2. A never-reassigned var scalar with a stable per-run initializer (e.g. var tfSec = timeframe.in_seconds()) — all var names were treated as mutable state.

The stability classifier and the reset-expression renderer now inline single-ExprStmt-body UDFs structurally (parameter substitution over the arithmetic/call grammar; cycle guard + depth cap at the shared choke-point, so recursive UDFs are refused without hanging), and never-reassigned top-level var/varip scalars with stable initializers register as stable derived expressions (no use-site inlining). Genuinely series-dynamic lengths (ternary over an ATR-derived ratio) are still rejected with the same error — pinned by a guard test and an end-to-end true-positive sentinel.

Gates (author + independent fresh-context R7, both green)

  • 3 RED tests fail pre-fix with Unsupported TA constructor length, pass post-fix; 4 conservative guards (series-dynamic, reassigned-var body, recursive, multi-statement) pass on both sides.
  • Full pytest 1473 passed / 1 skipped; corpus compile sweep 254 passed.
  • End-to-end: the false-positive exemplar transpiles and runs (89.5% match, 100% price parity); the true-positive sentinel still errors on its series-dynamic length.
  • Private validation full sweep (412): transpile-error inventory 8→7 (exactly the unblocked exemplar), remaining errors byte-identical, 0 tier moves.

🤖 Generated with Claude Code

The stable-TA-length guard hard-rejected two bar-invariant shapes:
a TA constructor length computed through a pure single-expression
user-defined function (any UDF call was treated as series-valued), and
a never-reassigned var scalar whose initializer is a stable per-run
expression (all var names were treated as mutable state).

The stability classifier and the reset-expression renderer now inline
single-ExprStmt-body UDFs structurally (parameter substitution over the
arithmetic/call grammar; cycle guard and depth cap at the shared
choke-point, so recursive UDFs are refused without hanging), and a
first pass registers never-reassigned top-level var/varip scalars with
stable initializers as stable derived expressions without inlining
their use-sites. Genuinely series-dynamic lengths (e.g. a ternary over
an ATR-derived ratio) are still rejected with the same error.

Note: block-form single-expression UDFs parse with is_single_expr set
false; the inliner keys off the body being exactly one expression
statement, not that flag.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@luisleo526 luisleo526 merged commit 097f499 into main Jul 10, 2026
9 checks passed
@luisleo526 luisleo526 deleted the fix/stable-ta-length-udf-var branch July 10, 2026 19:38
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