Skip to content

SELD-R2 PR 3: the interaction runtime (rt-interaction.ts), the per-assignment interaction table and its host check - #237

Open
thejackshelton wants to merge 9 commits into
masterfrom
claude/native-interaction-runtime-evd0n6
Open

thejackshelton wants to merge 9 commits into
masterfrom
claude/native-interaction-runtime-evd0n6

Conversation

@thejackshelton

@thejackshelton thejackshelton commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Jack · project thread

SELD-R2 PR 3, the interaction runtime (binding spec docs/goals/milestone-2-proof/notes/T064-seld-r2-spec.md R6, R7, R8, R12, R15, R16). Based on master, not stacked. PR 1 (#136, the compiler part) is on master; the runtime parts never landed.

Before: :hover, :active, :focus and :focus-visible compile to per-assignment interaction states, but nothing can select a state on a device, so every interaction rule is refused on iOS and Android.

After: the runtime that selects them exists as one translated implementation (TypeScript reference, Swift and Kotlin from the translator), with the per-assignment interaction table and a host check proving every state lands on its per-case program. No support claim and no profile row change: the native refusal stays until PR 4 adds the UIKit/Android glue and the device-traces lane. Nothing on device runs it yet.

What changed

  • packages/layout/src/rt-interaction.ts (new, translated root, R12): the R6 event rules over compiled tables. Pointer move/exit, mouse press/release (focus at press), touch press/release/cancel (a tap never hovers, R1; focus at release; a control that consumes the touch changes no focus, P7), keys (a non-meta key turns focus-visible on, P9; keyboard focus for P6e), the Android hover-exit deferral (R15), app-setter remaps and layout re-hits (P11), and CSS.forcePseudoState. interactionCombo/interactionState are the R7 index arithmetic. Eleven plants, all in InteractionFaults.
  • packages/dragon/src/lower/interaction-program.ts (new, R7): per app assignment, the tables from its partition plus one StateDelta per interaction state over the state program's base. The states are a second level, never more assignments in the 64-cap table. It imports @dragon/layout for types only, as ua.test requires of the compiler core.
  • packages/parity/src/interaction-runtime.ts (new): InteractionRuntime, the TypeScript reference the generated runtime will follow. It calls onChange after each committed change and onInteractionChange(fromApp, from, toApp, to) at most once per step, when (app, state) changed (R16, ANIM-b2's style-change hook).
  • internal.ts: exports, plus interactionLevelInput (per element: touchConsumesTap for input[type=range], keyboardInput for text fields and textarea, R8).
  • packages/parity/src/interaction-cases.ts (new): the host check. For every interaction fixture, direction and backend:
    • every (app, state) program equals its per-case program;
    • a derived trace (move, press, release, keys, hover-exit and press, taps, cancel, every forced pseudo-class, app setters) runs on InteractionRuntime with rt-hit on the live program;
    • at every step, the matches equal what the R6 rules give. The rules are computed from the partition's own elements with focusTargetOf, not from rt-interaction.ts;
    • the state equals what those matches resolve to in the partition's dimensions;
    • the live node records equal that state's per-case program.
  • Translator (generate.ts, corpus.ts, new corpus-interaction.ts, harness.ts): rt-interaction is an engine root, and a new interaction corpus suite follows animator. It has 21 lines and 732 steps over three synthetic table sets: hand scripts per rule plus seeded walks. The suite is built in code, so it has no committed input. native-swift/native-kotlin take the suite list from the corpus.
  • parity/src/targets.ts: one corpusSuites line declaring p1/interaction.

Outside the spec

  • packages/translate/test/p1-floor.json: interaction appended to order, with count 21 (append-only floor).
  • packages/translate/test/translate.test.ts: the suite-list comment only.
  • R6's relayout re-hit runs once per step at the same step. A layout change caused by an interaction state re-hits once, so a hover that moves its own box cannot loop.

Plants

  • Host trace check: tapSetsHover, hoverWithoutAncestors, forcedSetsAncestors, focusOnNonFocusable, activeWithoutAncestors, activeStaysAfterRelease and hoverExitOnPress are each caught.
  • packages/layout/test/rt-interaction.test.ts catches all eleven on synthetic tables. That includes focusVisibleOnPointer, focusAtTouchPress, rangeTapFocuses and hoverNotRecomputedAfterLayout, which no compiled fixture can reach before FORM-a: no focusable element or range compiles yet.

Left for PR 4

UIKit and Android glue, the generated native machine's second-level table (the emit/runtime/state.ts hunk waits for #203, #214, #196 and #231, which all edit that file), the Chrome trace capture and report (R2, R14), the device-traces lane, profile rows, and lifting nativeInteractionRefusals.

What passed

All on the final head 4a41f7ecc, which is the regen commit on top of the master merge fe4957438 (#232, #233):

  • checks workflow green.
  • pnpm ci:test-files --once (run 37940112467) PASSED. Results:
    • interaction-runtime: 9
    • chrome-ports: 13
    • registry-claims: 8
    • device-vectors: 8
    • rt-interaction-suite: 7
    • rt-vectors: 9
    • translate: 16
    • native-swift: 1
    • native-kotlin: 1
  • Regen through pnpm ci:regen only (run 37928077369). Nothing was regenerated locally.
  • Locally: pnpm typecheck, pnpm layout:subset, and the platform-free tests rt-interaction, ua, dragon registry-claims and interaction.
  • Correctness review (Claude, since Macroscope is at its monthly limit, so its checks show skipped). Two Medium findings were fixed:
    • the R16 hook could fire more than once per step;
    • it compared states across different apps, so it now takes (fromApp, from, toApp, to).
      The Low notes are covered under Plants and Outside the spec.
  • Earlier CI failures were fixed and explained in PR comments:
    • ua.test: the runtime moved out of the compiler core;
    • chrome-ports: the element.cc range was registered in docs/ports.json.

🤖 Generated with Claude Code

https://claude.ai/code/session_019gAHotrCwxo86PAgtrhRUT


Generated by Claude Code

claude added 2 commits October 9, 2026 07:27
…ted-subset root (R1, R6, R8, R15)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019gAHotrCwxo86PAgtrhRUT
…reference with the R16 hook, the host check, and rt-interaction as a translated root with its corpus suite

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019gAHotrCwxo86PAgtrhRUT
@thejackshelton thejackshelton self-assigned this Oct 9, 2026
…ompiler core imports @dragon/layout for types only); one onChange and at most one R16 event per step, naming both (app, state) pairs; every trace group must reach an element

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019gAHotrCwxo86PAgtrhRUT

Copy link
Copy Markdown
Contributor Author

checks failed on 02e1edb in packages/dragon/test/ua.test.ts (dependency boundaries): lower/interaction-program.ts imported @dragon/layout for values, and the compiler core may import it for types only. This PR caused it. The fix is committed as 5f6b6b9 (not yet pushed): InteractionRuntime moves to packages/parity/src/interaction-runtime.ts, and the core keeps type-only imports. It also carries the Medium findings from the Claude correctness review: one R16 event per step, naming both (app, state) pairs. ua.test, the interaction host check and the layout runtime tests pass locally. It waits to push until the CI regen run 37900595408 on 02e1edb finishes, because a push during the run would abort it.


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

checks failed on 5f6b6b9 in packages/parity/test/chrome-ports.test.ts. rt-interaction.ts and its test cite Blink element.cc:8057-8058, but docs/ports.json did not list either file. This PR caused it. The fix is committed locally (not yet pushed) and adds the cited range 8036-8058 and both files as class A references (reference use only, no port). chrome-ports passes locally (13/13). It goes out once regen run 37907827785 on 5f6b6b9 finishes, since a push during the run would abort it.


Generated by Claude Code

github-actions Bot and others added 6 commits October 9, 2026 10:07
Commands: pnpm regen --skip lanes-host --skip tw-sweep (macos-26) and pnpm regen --only lanes-host (xcode-27), alternated
to a fixed point, then pnpm regen --only tw-sweep (macos-26).
Base: 5f6b6b9
Run: https://github.com/compiled-run/dragoncss/actions/runs/37907827785
…8058 (SetFocused) as a class A reference

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019gAHotrCwxo86PAgtrhRUT
…on-runtime-evd0n6: GitHub reported the PR conflicting; no source conflicts, generated files regenerate on CI

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019gAHotrCwxo86PAgtrhRUT
Commands: pnpm regen --skip lanes-host --skip tw-sweep (macos-26) and pnpm regen --only lanes-host (xcode-27), alternated
to a fixed point, then pnpm regen --only tw-sweep (macos-26).
Base: 4489cf5
Run: https://github.com/compiled-run/dragoncss/actions/runs/37916744596
…on-runtime-evd0n6: GitHub reported the PR conflicting; no source conflicts, generated files regenerate on CI

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019gAHotrCwxo86PAgtrhRUT
Commands: pnpm regen --skip lanes-host --skip tw-sweep (macos-26) and pnpm regen --only lanes-host (xcode-27), alternated
to a fixed point, then pnpm regen --only tw-sweep (macos-26).
Base: fe49574
Run: https://github.com/compiled-run/dragoncss/actions/runs/37928077369

This branch has not been deployed

No deployments
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.

2 participants