# HS Conformance — Bucket F Plan Based on a full suite run on 2026-04-26. Current score: **~1297/1489 covered** (~87%). Skipped from runs: tests 197–200 (hypertrace, slow), 615 (slow), 1197–1198 (repeat-forever timeouts). **⚠ Updated 2026-04-26:** The hs-loop completed significant Bucket D work before being stopped. `hs-f` branches from `loops/hs` HEAD which already includes: - MutationObserver mock + `on mutation` dispatch (+7) → **Group 4 likely done** - Cookie API partial (+3/5) → **Group 5 partially done** - `elsewhere`/`from elsewhere` + count filters (+7) → **Group 3a/3c partially done** - Namespaced `def` (+3) → already done - SourceInfo E38 (+4) + WebWorker E39 (+1) → already merged **The Bucket F agent must run `hs_test_run` on each group's suite before implementing, to verify what's actually still failing. Skip any group that already passes.** Total remaining failures: ~193. Broken into groups below. --- ## Group 0 — Bucket E payoff (~47 tests, will land automatically) These are already implemented or in-flight on Bucket E branches. Once merged they close ~47 tests. | Suite | Tests | Status | |-------|------:|-------| | `hs-upstream-core/tokenizer` | 17 | E37 in progress | | `hs-upstream-socket` | 16 | E36 in progress | | `hs-upstream-fetch` | 8 | E40 in progress | | `hs-upstream-core/sourceInfo` | 4 | E38 done, not yet merged | | `hs-upstream-worker` | 1 | E39 done, not yet merged | | E37 string interpolation bug | 1 | E37 | **Do not plan these — they resolve when Bucket E merges.** --- ## Group 1 — Null safety reporting (+7) **Suite:** `hs-upstream-core/runtimeErrors` **Failures:** 7 tests, all "Expected `'#doesntExist' is null`, got ``" **What's needed:** When a command like `put`, `increment`, `decrement`, `default`, `remove`, `settle`, `transition` receives a null element (e.g. `#doesntExist`), HS must throw a structured null-safety error with the element reference in the message. The null check + error format is already designed in Bucket D #31 (cluster 31 of `hs-conformance-to-100.md`). **Estimate:** +7. Straightforward — null guard at command dispatch entry. --- ## Group 2 — `tell` semantics (+3) **Suite:** `hs-upstream-tell` **Failures:** - `attributes refer to the thing being told` — Expected `bar`, got `` - `your symbol represents the thing being told` — Expected `foo`, got `` - `does not overwrite the me symbol` — assertion fail **What's needed:** Inside a `tell X` block, `you`/`your` must resolve to X, attribute refs must resolve against X, and `me` must retain its original value (not be rebound to X). Currently `tell` rebinds `me` instead of introducing a separate `you` binding. **Estimate:** +3. Scoping fix in the `tell` command handler. --- ## Group 3 — `on` event handler features (+19, skip-list) **Suite:** `hs-upstream-on` **34 tests on skip-list.** Prioritise tractable subsets: ### 3a — Event filtering by count (+6) - `can filter events based on count` - `can filter events based on count range` - `can filter events based on unbounded count range` - `can mix ranges` - `on first click fires only once` - `multiple event handlers at a time are allowed to execute with the every keyword` The `on (N)`, `on (N to M)`, `on first`, `every` modifiers. Parser + runtime counter state per handler. ### 3b — `finally` blocks (+6) - `basic finally blocks work` - `async basic finally blocks work` - `exceptions in finally block don't kill the event queue` - `async exceptions in finally block don't kill the event queue` - `finally blocks work when exception thrown in catch` - `async finally blocks work when exception thrown in catch` `on … catch … finally` analogous to JS try/catch/finally. Needs a finally-frame in the CEK machine (similar to dynamic-wind). ### 3c — `elsewhere` modifier (+2) - `supports "elsewhere" modifier` - `supports "from elsewhere" modifier` `on click elsewhere` = click outside the element. Needs a global listener + target exclusion check. ### 3d — Exception events (+3) - `rethrown exceptions trigger 'exception' event` - `uncaught exceptions trigger 'exception' event` - `can catch exceptions thrown in hyperscript functions` - `can catch exceptions thrown in js functions` When an unhandled exception escapes an `on` handler, HS must dispatch an `exception` CustomEvent on the element. ### 3e — Element removal cleanup (+2) - `listeners on other elements are removed when the registering element is removed` - `listeners on self are not removed when the element is removed` Cleanup hook via MutationObserver watching for element removal. ### Deferred (skip-list, complex): - `can be in a top level script tag` — requires script tag re-initialisation - `can ignore when target doesn't exist` — target null guard - `can handle an or after a from clause` — parser edge case - `each behavior installation has its own event queue` — behavior isolation --- ## Group 4 — MutationObserver / `on mutation` (+10) **Suite:** `hs-upstream-on` (mutation subset, skip-list) **Tests:** - `can listen for attribute mutations` - `can listen for attribute mutations on other elements` - `can listen for childList mutations` - `can listen for general mutations` - `can listen for multiple mutations` - `can listen for multiple mutations 2` - `can listen for specific attribute mutations` - `can pick event properties out by name` - `can pick detail fields out by name` - `attribute observers are persistent (not recreated on re-run)` (hs-upstream-when) **What's needed:** MutationObserver mock in the test runner (`hs-run-filtered.js`) + `on mutation` command in the parser/runtime. Already prototyped in Bucket D #32. **Estimate:** +10. --- ## Group 5 — Cookie API (+5) **Suite:** `hs-upstream-expressions/cookies` All 5 tests untranslated. Cookie read/write as an expression: `cookies.name`, `set cookies.name to val`, `cookies.name is undefined`. Needs `document.cookie` mock in runner + cookie-expression parse path. **Estimate:** +5. Self-contained. --- ## Group 6 — Block literals (+4) **Suite:** `hs-upstream-expressions/blockLiteral` All 4 untranslated. Syntax: `[x | x + 1]` — an inline lambda. Used as a first-class value passable to `map`, `filter` etc. - `basic block literals work` - `basic identity works` - `basic two arg identity works` - `can map an array` **Estimate:** +4. Parser addition + runtime callable wrapping. --- ## Group 7 — Async logical operators (+5) **Suite:** `hs-upstream-expressions/logicalOperator` Promise-aware `and`/`or`: - `and short-circuits when lhs promise resolves to false` - `or short-circuits when lhs promise resolves to true` - `or evaluates rhs when lhs promise resolves to false` - `should short circuit with and expression` - `should short circuit with or expression` **What's needed:** `and`/`or` must await promise operands before short-circuiting. Currently they evaluate eagerly without awaiting. **Estimate:** +5. Async await integration in logical operator eval. --- ## Group 8 — `evalStatically` (+3) **Suite:** `hs-upstream-core/evalStatically` - `throws on math expressions` - `throws on symbol references` - `throws on template strings` `_hyperscript.evaluate(src, {}, { throwErrors: true })` must throw synchronously for expressions with side-effects or unresolved symbols. Currently the static evaluator doesn't gate on `throwErrors`. **Estimate:** +3. Flag-gated error throw path. --- ## Group 9 — Parse error API (+6) **Suite:** `hs-upstream-core/parser` + `hs-upstream-core/bootstrap` - `basic parse error messages work` - `fires hyperscript:parse-error event with all errors` - `parse error at EOF on trailing newline does not crash` - `_hyperscript() evaluate API still throws on first error` - `fires hyperscript:before:init and hyperscript:after:init` (bootstrap) - `hyperscript:before:init can cancel initialization` (bootstrap) **What's needed:** - Parser must emit a `hyperscript:parse-error` CustomEvent on `document` when compilation fails, with the error list as detail. - `hyperscript:before:init` / `hyperscript:after:init` lifecycle events dispatched around element initialization. - `before:init` can cancel (return false / `event.preventDefault()`). **Estimate:** +6. Event dispatch hooks in the bootstrap/init path. --- ## Group 10 — `as` expression conversions (+8) **Suite:** `hs-upstream-expressions/asExpression` Currently 30/42 = 12 failures. Tractable subset: - `converts a NodeList into HTML` — NodeList → outerHTML join - `converts strings into fragments` — string → DocumentFragment - `converts elements into fragments` — element → DocumentFragment - `converts arrays into fragments` — array of elements → DocumentFragment - `converts array as Set` — array → Set (dedup) - `converts object as Map` — object → Map - `can accept custom conversions` — `as MyType` via registered converter - `can use the a modifier if you like` — `as a Number` synonym Two already-broken non-skip failures: - `converts a complete form into Values` — Expected `dog`, got `` - `converts multiple selects with programmatically changed selections` — Expected `cat`, got `dog` **Estimate:** +8 for the tractable subset. Custom converters and Map/Set require runtime additions. --- ## Group 11 — Miscellaneous runtime bugs (+12) Small scattered failures, each 1–3 tests: | Suite | Failure | Likely cause | |-------|---------|-------------| | `hs-upstream-put` | `properly processes hyperscript` ×3 (got 40, expected 42) | Off-by-one in `put ... before/after` reprocessing | | `hs-upstream-put` | `waits on promises` | Promise await missing from put target eval | | `hs-upstream-js` | `can return values to _hyperscript` | JS block return value not threaded back | | `hs-upstream-js` | `can do both of the above` | Same | | `hs-upstream-js` | `handles rejected promises without hanging` | Rejected promise in js block uncaught | | `hs-upstream-set` | `set waits on promises` | Same as put | | `hs-upstream-set` | `can set into indirect style ref 3` | Indirect style ref path bug | | `hs-upstream-hide` | `retain original display` | `none` vs `block` display tracking | | `hs-upstream-toggle` | `toggle for fixed time` | Timed toggle assertion timing | | `hs-upstream-transition` | `initial value` | `initial` keyword not restoring computed value | | `hs-upstream-expressions/arrayLiteral` | `objects with _order` | `_order` internal key leaking into equality check | | `hs-upstream-core/bootstrap` | 4 bugs | Event handler bugs in reinit, cleanup, respond | | `hs-upstream-expressions/closest` | `where clause` | `where` consumed by `closest` instead of outer | | `hs-upstream-core/scoping` | 2 bugs | Pseudo-possessive, built-in variable clash | **Estimate:** +12 once individually triaged. --- ## Group 12 — Formerly "hard floor" — now in scope Initial assessment was wrong — these are medium difficulty, not genuinely hard. All 16 are worth attempting. | Suite | Tests | Actual difficulty | What's needed | |-------|------:|-------------------|---------------| | `hs-upstream-breakpoint` | 2 | **Trivial** | No-op parser command + generator translation. Design: `plans/designs/f-breakpoint.md` | | `hs-upstream-expressions/logicalOperator` (unparenthesized error) | 2 | Low | Parser strictness: `1 + 2 + 3` should throw "ambiguous operator precedence" | | `hs-upstream-core/security` | 1 | Medium | `_hyperscript.config.disableScripting = true` guard at `hs-activate!` time | | `hs-upstream-expressions/asExpression` (Date, custom dynamic) | 3 | Medium | `as a Date` → `new Date(val)`; custom converters via `_hyperscript.addType` registry | | `hs-upstream-on` (remaining skip-list) | ~8 | Medium | Script tag reinit (MutationObserver on `