# F13 — Step Limit + `meta.caller` (+5 → 100%) Five tests currently timeout or produce wrong values due to two root causes: step budget exhaustion and a missing `meta` implementation. ## Tests | # | Suite | Test | Failure | |---|-------|------|---------| | 198 | `hs-upstream-core/runtime` | `has proper stack from event handler` | wrong-value: `meta.caller` returns `""` instead of an object with `.meta.feature.type = "onFeature"` | | 200 | `hs-upstream-core/runtime` | `hypertrace is reasonable` | TIMEOUT (15s, step limit) | | 615 | `hs-upstream-expressions/in` | `query template returns values` | TIMEOUT (37s, step limit) | | 1197 | `hs-upstream-repeat` | `repeat forever works` | TIMEOUT (step limit) | | 1198 | `hs-upstream-repeat` | `repeat forever works w/o keyword` | TIMEOUT (step limit) | --- ## Root cause A — Step limit (tests 200, 615, 1197, 1198) The runner sets `HS_STEP_LIMIT=200000`. Every CEK step consumed by any expression in a test — including the double compilation warm-up guard blocks that appear before the actual DOM test — counts against this shared budget. ### `repeat forever` (1197, 1198) The loop body terminates in exactly **5 iterations** (`if retVal == 5 then return`). This is bounded, not infinite. The step budget is exhausted before the loop runs because two `eval-expr-cek` compilation warm-up calls each consume tens of thousands of steps. Fix: each warm-up guard compiles and discards a HS function definition. Those calls are defensive (wrapped in `guard` that swallows errors). We do NOT need to run the compiled code — the warm-up's purpose is just to ensure the compiler doesn't crash, not to consume steps. The step counter should not tick during compilation (compilation is a pure transform, not evaluation). If that's impractical to gate, raise `HS_STEP_LIMIT` to `2000000` (10×). ### `hypertrace is reasonable` (200) Defines `bar()` → calls `baz()` → throws. Simple call chain. The "hypertrace" in the test name implies the HS runtime trace recorder is active during the test. If trace recording is on globally, every CEK step generates a trace entry allocation. Fix: confirm whether trace recording is always-on in the test runner and disable it by default (trace should only be on when explicitly requested). Alternatively raise step limit. ### `query template returns values` (615) Uses `<${"p"}/>` — a CSS query selector built from a template string. Takes 37 seconds. Likely the template selector evaluation triggers repeated DOM scanning or expensive string construction per step. Fix: profile with `hs_test_run verbose=true` to identify which step is slow. If it's a regex compilation per-call, cache it. If step limit only, raise to 2M. ### Unified fix: raise `HS_STEP_LIMIT` to `2000000` The simplest fix that unblocks all four timeout tests. In `tests/hs-run-filtered.js`, change the default step limit. Per-test overrides can still be set via `HS_STEP_LIMIT` env var for debugging. If the `query template` test is still slow at 2M steps (37s × 10 = 370s, which would be unacceptable), that test needs a separate performance fix — cache the compiled regex/query from the template string rather than rebuilding it on every access. --- ## Root cause B — `meta.caller` not implemented (test 198) The HS `meta` object is available inside any function call. It exposes: - `meta.caller` — the calling context object - `meta.caller.meta.feature.type` — the HS feature type of the caller (e.g. `"onFeature"` when called from an `on click` handler) Test script: ``` def bar() log meta.caller return meta.caller end ``` Triggered via `on click put bar().meta.feature.type into my.innerHTML`. Expects `"onFeature"` in innerHTML. Currently gets `""`. ### What `meta` needs `meta` is a dict-like object injected into every function's execution context at call time. Minimum fields for this test: ``` meta = { :caller :element } ``` `meta.caller.meta.feature.type` must return `"onFeature"` when called from an `on` event handler. The feature type string `"onFeature"` is already used internally (event handler features are tagged with this type). ### Implementation In `lib/hyperscript/runtime.sx`, at the point where a HS `def` function is called: 1. Build a `meta` dict: ``` {:caller calling-context :element current-element} ``` where `calling-context` is the current runtime context dict (which includes its own `:meta` field with `:feature {:type "onFeature"}` for event handlers). 2. Bind `meta` in the function's execution env. 3. Ensure event handler contexts carry `{:meta {:feature {:type "onFeature"}}}`. This is an additive change — nothing currently uses `meta`, so no regression risk. --- ## Implementation checklist ### Step A — Raise step limit 1. In `tests/hs-run-filtered.js`, change default `HS_STEP_LIMIT` from `200000` to `2000000`. 2. Run tests 1197–1198: `hs_test_run(start=1197, end=1199)` — expect 2/2. 3. Run test 615: `hs_test_run(start=615, end=616)` — expect 1/1 or note if still too slow. 4. Run test 200: `hs_test_run(start=200, end=201)` — expect 1/1. ### Step B — `meta.caller` (test 198) 5. `sx_find_all` in `lib/hyperscript/runtime.sx` for where `def` functions are called / where event handler contexts are constructed. 6. Add `meta` dict construction at call time; bind in function env. 7. Ensure `on` handler context carries `{:meta {:feature {:type "onFeature"}}}`. 8. Run test 198: `hs_test_run(start=198, end=199)` — expect 1/1. ### Step C — Query template performance (if still slow after step A) 9. Profile `hs_test_run(start=615, end=616, step_limit=2000000, verbose=true)`. 10. If the CSS template query `<${"p"}/>` rebuilds on every call, add a memoize cache keyed on the template result string. 11. Rerun — expect < 5s. ### Step D — Full suite verification 12. Run all ranges with raised step limit: - `hs_test_run(start=0, end=201, step_limit=2000000)` - `hs_test_run(start=201, end=616, step_limit=2000000)` - `hs_test_run(start=616, end=1200, step_limit=2000000)` - `hs_test_run(start=1200, end=1496, step_limit=2000000)` 13. Confirm all previously-passing tests still pass. 14. Commit: `HS: raise step limit to 2M + meta.caller for onFeature stack (+5)` --- ## Risk - **Step limit raise:** May make test suite slower overall (more steps to exhaust before timeout). But if tests pass quickly the limit is never reached. The 37s query-template test is the only real concern — if it genuinely needs 2M steps × (time per step), it needs a performance fix too. - **`meta.caller`:** Additive binding in function scope. Zero regression risk. The only complexity is constructing the right shape for the calling context chain — but since only one test exercises this and the shape is simple, the risk is low.