# Packed Section acceptance

This gate exercises the package tarball and the real CLI-installed Sections in
Chromium, Firefox and WebKit, with React 18 and 19. It is an executable acceptance
contract, not a record of a completed run. Use the CI artifact to establish the
result for a particular source revision. No measured results are embedded here.

The consumer is created outside the repository. Package imports, stylesheet
imports, React imports and every bundle input must resolve inside that consumer;
a symlink back to repository runtime code fails the gate. Installed files must
match the tested registry byte for byte. Local JPEG responses come from the
fixture server, including a response held until after hydration and a separate
404 response. The fixture never fetches media from the public gallery.

## What is asserted

- The existing integrated page hydrates, executes every installed enhancement,
  preserves independent page styles, remains reachable without JavaScript and
  under either reduced-motion control, and returns resources to its empty-route
  baseline after repeated unmounts. A failed tracker leaves its sibling and kit
  working.
- After StickySteps enhances, one-shot computed-style and accessibility-write
  faults stop its controller. A throwing observer disposer cannot block the
  remaining cleanup. Computed static layout, keyboard focus visibility, removed
  accessibility restrictions, one report, disconnected observation, harmless
  queued callbacks and a successful explicit remount are checked. The Node
  controller test also directly counts motion unsubscription and gallery tracker
  release, including synchronous attachment failure. The existing round-14 gate
  remains in place; it has not been replaced by this gate.
- Three 1200 by 900 JPEGs decode; StickySteps fits its candidate, visibly changes
  first and last scenes and excludes only inactive media from focus. The held
  image stays pending through hydration and motion changes, then decodes when
  released. A 404 cannot hide the surrounding copy or links. The fixture's
  images carry `width` and `height` attributes, as CMS and `next/image` output
  does: a pending image with no declared dimensions has no box, and the static
  layout cannot keep reachable what has no area.
- After activation, StickySteps, TimelineScrub and CaseStudyRail receive
  200-word descriptions and 120-character titles. Measured overflow releases
  the stages into flow, all copy and focus targets are reachable, and shortening
  the copy or changing motion cannot clear the flow latch. Explicit remount
  reevaluates the short content. TimelineScrub has no title field, so its title
  is a block span in the supported `text` ReactNode.
- StickySteps changes from three steps to one, zero and three, starting at its
  last scene. Remaining media cannot retain an obsolete scene restriction.
- Long content is checked at a 320 by 900 viewport and with actual computed
  text sizes doubled at desktop width. Geometry, hit testing and focused links
  must demonstrate reachability and no horizontal page overflow.
- OS reduce/restore and page reduce/auto run while an image is pending and after
  activation. Consecutive page calls in the same JavaScript task must synchronize
  DOM accessibility before React renders. Only an eligible lease enhances again.

Missing-CSS, failed boot and terminal-watchdog coverage remains in the existing
browser invariants. Run those gates alongside packed acceptance. These checks
do not establish a manual screen-reader audit or physical-device performance.

## Local execution

Use the repository's Node version and build generated registry output first:

```sh
npm ci
npm run demo:sync
npm ci --prefix demo/bench/harness
npx --prefix demo/bench/harness playwright install chromium firefox webkit
SCROLLVARS_ACCEPTANCE_DIR=/tmp/scrollvars-acceptance npm run test:packed
```

Pass `-- chromium` to select Chromium only. Without a browser, `npm test` checks
the controller faults, copy lengths, JPEG dimensions, packed CLI byte parity,
isolated consumer build, SSR markup and evidence persistence. It cannot prove
layout, decoding, hydration, focus or browser resource release. Run
`npm run test:react18`, `npm run test:e2e` and `npm run test:browsers` as the
companion regression gates. Finish source changes with `npm run demo:sync` and
verify another sync changes no generated bytes.

`SCROLLVARS_TARBALL=/absolute/path/package.tgz` selects a previously packed
artifact. Otherwise the harness packs into a temporary directory and removes it
afterward. The release workflow passes its pack-step path both to acceptance
and to `npm publish`; it does not repack after acceptance.

## Reading evidence

CI uploads `packed-acceptance-<browser>-<attempt>` for each browser job and
`packed-acceptance-release-<attempt>` for release, using an always-run artifact
step. Files live outside the disposable consumer. Locally, the harness prints
the result path; use `SCROLLVARS_ACCEPTANCE_DIR` to choose it.

`result.json` contains runtime-produced fields:

| Field | Meaning |
| --- | --- |
| `status` | `running`, `failed` or `passed`; only `passed` is a completed green gate |
| `sourceCommit`, `sourceDirty` | Actual checkout HEAD and whether the checkout had uncommitted files |
| `ciCommit`, `ciRunUrl`, `ciRunAttempt` | CI event attribution; null locally; a PR merge checkout can differ from its source branch |
| `packageVersion` | Source package version, checked against the selected tarball |
| `tarballSha512` | SHA-512 of tested tarball bytes, in npm integrity format |
| `registrySha256` | SHA-256 of the registry whose CLI output was installed |
| `reactVersions`, `browserVersions`, `nodeVersion` | Actual loaded runtime versions; each browser entry identifies its React version |
| `checks` | Named assertions with success or the original failure stack |
| `startedAt`, `finishedAt` | Run timestamps; a missing finish indicates interruption |

Results are checkpointed before setup and after each check. A setup failure may
leave versions or hashes absent; that is incomplete evidence. A job that never
reaches acceptance may have no artifact, and its upload step warns accordingly.
A dirty local result identifies its base commit and exact package/registry
hashes but is not evidence for the clean committed revision.

Browser assertion failures also save HTML, a screenshot and JSON containing
computed geometry, accessibility state, hydration errors and resource counts.
If diagnostic capture itself fails, its `.error.txt` preserves that error without
replacing the original assertion. A launch or install failure can only supply
the failure stack. Compare the hashes when relating a result to a tarball;
temporary consumer paths are diagnostic locations, not durable artifact IDs.
