# Reproduction

The packaged way (recommended) — from the project (or a consumer) root:

    mix live_interaction_contracts.test                    # harness + fuse + ledger
    mix live_interaction_contracts.test --suite cursor
    mix live_interaction_contracts.test --suite combobox
    mix live_interaction_contracts.ledger

The raw way (how the spikes were developed) is below. Fixtures now live under `priv/`.


Prereqs: Elixir 1.20 / OTP 28, Node with Playwright + browsers installed
(`npx playwright install chromium firefox webkit`). All apps bind 127.0.0.1 only.

## Conformance harness (delegation ledger)
    cd priv/harness
    LV_SPEC=1.2.5 elixir app.exs           # port 4123
    node suite.mjs                          # -> harness/results.json
    node ledger.mjs                         # -> ../delegation-ledger.{json,md}

## Multi-version drift check
    cd priv/harness
    PORT=4125 VERSIONS_OUT=versions-alt.json LV_SPEC="~> 1.1.0" elixir app.exs
    PORT=4125 node suite.mjs                # compare against results-1.2.5.json
    # LV_SPEC also accepts: github:phoenixframework/phoenix_live_view#main  |  path:/abs/checkout

## Cursor rebind spike (client tier)
    cd priv/cursor-spike
    elixir app.exs                          # port 4126
    node spike.mjs                          # -> cursor-spike/results.json
    node focus3.mjs                         # aria-activedescendant vs roving focus

Kill a stuck server: kill $(lsof -nP -t -iTCP:<port> -sTCP:LISTEN)

## Combobox integration spike (Delegation × Cursor × Channel)
    cd priv/combobox-spike
    elixir app.exs                          # port 4127
    node spike.mjs                          # -> combobox-spike/combobox-results.json
    # deterministic async ordering via server query/release gate; guard flag toggles
    # server-side monotonic guard (construction) vs client version-stamp (convention)

## CI fuse (local)
    cd priv/harness
    node ci-assert.mjs            # exits non-zero on green regression / red-turned-green
    node ledger.mjs               # regenerates ../delegation-ledger.{json,md}

## CI (GitHub Actions)
    .github/workflows/conformance.yml
    # Tier 1 stable = blocking gate; Tier 2 main/edge = scheduled early-warning fuse.
    # PR: reduced browser matrix (ONLY_BROWSER=chromium); release/schedule: full matrix.

## Consumer install (hex package dry-run — executed 2026-07-07, all green)

    # 1. build + unpack the package (what hex would ship)
    mix hex.build
    tar -xf live_interaction_contracts-*.tar -C /tmp/hexpkg
    tar -xzf /tmp/hexpkg/contents.tar.gz -C /tmp/lic_pkg

    # 2. scratch consumer app depends on the UNPACKED PACKAGE (not the repo):
    #    {:phoenix, "~> 1.8"}, {:phoenix_live_view, "~> 1.2"},
    #    {:live_interaction_contracts, path: "/tmp/lic_pkg"}
    #    plus a module that imports and renders <.popover>.
    mix deps.get && mix compile
    # -> _build/dev/phoenix-colocated/live_interaction_contracts/index.js
    #    must list all five hooks (Popover/Menu/Tooltip/Select/Combobox) — zero manual wiring.

    # 3. run the packaged conformance suite FROM the consumer app
    #    (proves priv fixtures ship complete; playwright comes from the
    #    package's own package.json)
    (cd /tmp/lic_pkg && npm i)
    mix live_interaction_contracts.test --suite tooltip   # 8/8, all engines

    # Real consumers install from Hex and use deps/live_interaction_contracts
    # in place of /tmp/lic_pkg; everything else is identical.
