From 4f98f5f89d4724ac97809d6249c5c7e68c5637cc Mon Sep 17 00:00:00 2001 From: giles Date: Sat, 25 Apr 2026 08:54:00 +0000 Subject: [PATCH] hs: drain plan for blockers + Bucket E + F Tracks the path from 1277/1496 (85.4%) to 100%. Records each blocker's fix sketch, files in scope, and order of attack. Cluster #31 spec'd in detail for the next focused sit-down. --- plans/hs-blockers-drain.md | 96 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 plans/hs-blockers-drain.md diff --git a/plans/hs-blockers-drain.md b/plans/hs-blockers-drain.md new file mode 100644 index 00000000..94ba3baa --- /dev/null +++ b/plans/hs-blockers-drain.md @@ -0,0 +1,96 @@ +# HS conformance — blockers drain + +Goal: take hyperscript conformance from **1277/1496 (85.4%)** to **1496/1496 (100%)** by clearing the blocked clusters and the design-done Bucket E subsystems. + +This plan exists because the per-iteration `loops/hs` agent can't fit these into its 30-min budget — they need dedicated multi-commit sit-downs. Track progress here; refer to `plans/hs-conformance-to-100.md` for the canonical cluster ledger. + +## Current state (2026-04-25) + +- Loop running in `/root/rose-ash-loops/hs` (branch `loops/hs`) +- sx-tree MCP **fixed** (was a session-stale binary issue — restart of claude in the tmux window picked it up). Loop hinted to retry **#32**, **#29** first. +- Recent loop progress: ~1 commit/6h — easy wins drained, what's left needs focused attention. + +## Remaining work + +### Bucket-A/B/C blockers (small, in-place fixes) + +| # | Cluster | Tests | Effort | Blocker | Fix sketch | +|---|---------|------:|--------|---------|------------| +| **17** | `tell` semantics | +3 | ~1h | Implicit-default-target ambiguity. `bare add .bar` inside `tell X` should target `X` but explicit `to me` must reach the original element. | Add `beingTold` symbol distinct from `me`; bare commands compile to `beingTold-or-me`; explicit `me` always the original. | +| **22** | window global fn fallback | +2-4 | ~1h | `foo()` where `foo` isn't SX-defined needs to fall back to `(host-global "foo")`. Three attempts failed: guard (host-level error not catchable), `env-has?` (not in HS kernel), `hs-win-call` (NativeFn not callable from CALL). | Add `symbol-bound?` predicate to HS kernel **OR** a host-call-fn primitive with arity-agnostic dispatch. | +| **29** | `hyperscript:before:init` / `:after:init` / `:parse-error` events | +4-6 | ~30m (post sx-tree fix) | Was sx-tree MCP outage. Now unblocked — loop should retry. 4 of 6 tests need stricter parser error-rejection (out of scope; mark partial). | Edit `integration.sx` to fire DOM events at activation boundaries. | + +### Bucket D — medium features + +| # | Cluster | Tests | Effort | Status | +|---|---------|------:|--------|--------| +| **31** | runtime null-safety error reporting | **+15-18** | **2-4h** | **THIS SESSION'S TARGET.** Plan node fully spec'd: 5 pieces of work. | +| **32** | MutationObserver mock + `on mutation` | +10-15 | ~2h | Was sx-tree-blocked. Now unblocked — loop hinted to retry. Multi-file: parser, compiler, runtime, runner mock, generator skip-list. | +| **33** | cookie API | +2 (remaining) | ~30m | Partial done (+3). Remaining 2 need `hs-method-call` runtime fallback for unknown methods + `hs-for-each` recognising host-array/proxy collections. | +| 34 | event modifier DSL | +6-8 | ~1-2h | `elsewhere`, `every`, count filters (`once`/`twice`/`3 times`/ranges), `from elsewhere`. Pending. | +| 35 | namespaced `def` | +3 | ~30m | Pending. | + +### Bucket E — subsystems (design docs landed, multi-commit each) + +Each has a design doc with a step-by-step checklist. These are 1-2 days of focused work each, not loop-fits. + +| # | Subsystem | Tests | Design doc | Branch | +|---|-----------|------:|------------|--------| +| 36 | WebSocket + `socket` + RPC Proxy | +12-16 | `plans/designs/e36-websocket.md` | `worktree-agent-a9daf73703f520257` | +| 37 | Tokenizer-as-API | +16-17 | `plans/designs/e37-tokenizer-api.md` | `worktree-agent-a6bb61d59cc0be8b4` | +| 38 | SourceInfo API | +4 | `plans/designs/e38-sourceinfo.md` | `agent-e38-sourceinfo` | +| 39 | WebWorker plugin (parser-only stub) | +1 | `plans/designs/e39-webworker.md` | `hs-design-e39-webworker` | +| 40 | Real Fetch / non-2xx / before-fetch | +7 | `plans/designs/e40-real-fetch.md` | `worktree-agent-a94612a4283eaa5e0` | + +### Bucket F — generator translation gaps + +~25 tests SKIP'd because `tests/playwright/generate-sx-tests.py` bails with `return None`. Single dedicated generator-repair sit-down once Bucket D is drained. ~half-day. + +## Order of attack + +In approximate cost-per-test order: + +1. **Loop self-heal** (no human work) — wait for #29, #32 to land via the running loop ⏱️ ~next 1-2 hours +2. **#31 null-safety** — biggest scoped single win, dedicated worktree agent (this session) +3. **#33 cookie API remainder** — quick partial completion +4. **#17 / #22 / #34 / #35** — small fiddly fixes, one sit-down each +5. **Bucket E** — pick one subsystem at a time. **#39 (WebWorker stub) first** — single commit, smallest. Then **#38 (SourceInfo)** — 4 commits. Then the bigger three (#36, #37, #40). +6. **Bucket F** — generator repair sweep at the end. + +Estimated total to 100%: ~10-15 days of focused work, parallelisable across branches. + +## Cluster #31 spec (full detail) + +The plan note from `hs-conformance-to-100.md`: + +> 18 tests in `runtimeErrors`. When accessing `.foo` on nil, emit a structured error with position info. One coordinated fix in the compiler emit paths for property access, function calls, set/put. + +**Required pieces:** + +1. **Generator-side `eval-hs-error` helper + recognizer** for `expect(await error("HS")).toBe("MSG")` blocks. In `tests/playwright/generate-sx-tests.py`. +2. **Runtime helpers** in `lib/hyperscript/runtime.sx`: + - `hs-null-error!` raising `'' is null` + - `hs-named-target` — wraps a query result with the original selector source + - `hs-named-target-list` — same for list results +3. **Compiler patches at every target-position `(query SEL)` emit** — wrap in named-target carrying the original selector source. ~17 command emit paths in `lib/hyperscript/compiler.sx`: + add, remove, hide, show, measure, settle, trigger, send, set, default, increment, decrement, put, toggle, transition, append, take. +4. **Function-call null-check** at bare `(name)`, `hs-method-call`, and `host-get` chains, deriving the leftmost-uncalled-name (`'x'` / `'x.y'`) from the parse tree. +5. **Possessive-base null-check** (`set x's y to true` → `'x' is null`). + +**Files in scope:** +- `lib/hyperscript/runtime.sx` (new helpers) +- `lib/hyperscript/compiler.sx` (~17 emit-path edits) +- `tests/playwright/generate-sx-tests.py` (test recognizer) +- `tests/hs-run-filtered.js` (if mock helpers needed) +- `shared/static/wasm/sx/hs-runtime.sx` + `hs-compiler.sx` (WASM staging copies) + +**Approach:** target-named pieces incrementally — runtime helpers first (no compiler change), then compiler emit paths in batches (group similar commands), then function-call/possessive at the end. Each batch is one commit if it lands +N tests; mark partial if it only unlocks part. + +**Watch for:** smoke-range regressions (tests flipping pass→fail). Each commit: rerun smoke 0-195 and the `runtimeErrors` suite. + +## Notes for future sessions + +- `plans/hs-conformance-to-100.md` is the canonical cluster ledger — update it on every commit. +- `plans/hs-conformance-scoreboard.md` is the live tally — bump `Merged:` and the bucket roll-up. +- Loop has scope rule "never edit `spec/evaluator.sx` or broader SX kernel" — most fixes here stay in `lib/hyperscript/**`, `tests/`, generator. If a fix needs kernel work, surface to the user; don't merge silently. +- Cluster #22's `symbol-bound?` predicate would be a kernel addition — that's a real cross-boundary scope expansion.