Skip to content

test(ios-snapshot): cover the runner-presented interactive pipeline #2974

Description

@thymikee

Complete #2754 step 2: cover the runner-presented interactive pipeline

Deletion-first acceptance

This is part of #2803's simplify-and-shrink initiative. Before production simplification, name the production mechanism, duplicated decision, state, fallback, forwarding layer, or public/internal interface this change removes. Compare deletion and inlining against extraction. Moving the same state into another file is not a deletion case.

Every PR reports baseline/final SHAs; added, deleted and net production lines; test/fixture/documentation changes separately; and the exact mechanisms removed. Use a rename-aware diff (git diff --numstat -M BASE...HEAD) and account for all affected production paths, including destination packages. Moving tests out of production files, generated output, formatting churn, and moving code elsewhere are not production-code deletion. Preserve readable code; no compressed formatting to hit a number.

Default for simplification work: net production reduction. A required behavior-preserving size split may be line-neutral. Growth needs an explicit, quantified explanation of the correctness or type guarantee it buys, why deletion/inlining cannot achieve it, and what old mechanism is removed; it is not automatically acceptable because ownership looks cleaner. If the only benefit is relocating fields or adding a wrapper, defer the change. Required regression tests and a minimal correctness fix are allowed to grow without inventing unrelated deletion to offset them.

For this test/characterization task, name the uncertainty or regression gap resolved instead of a production deletion. Expected production behavior delta is zero; report test/harness growth separately.

Priority and scope gate

Early regression protection, not a promised cheap cleanup. This is test/harness work and may add code; report its size separately rather than offsetting or obscuring production growth. It earns its place by detecting the missing runner-presented interactive regression. Keep production snapshot semantics unchanged, and scope/routing changes to the demonstrated test gap.

Problem and existing ownership

This is a bounded continuation of #2754 step 2, tracked under architecture umbrella #2803. It does not reopen the scroll-membership policy. Parent-edge ownership and the surveyed same-frame pass-through already landed through #2758; eligibility parity followed in #2759. TextView is already a green regression from #2740. Do not present those fixes as missing work or create a competing policy issue.

Verified against origin/main at 5712a3552e209c9c853bc1f42cb3e007f1213139: scripts/ios-snapshot-differential.test.ts:30 filters out authored interactive cases; packages/capture-kit/src/ios-snapshot-engine/conformance-harness.ts:16–26 fixes interactiveOnly to false; properties.test.ts:107–130 exercises projection membership through stage: 'acquired' only. The existing presented-input case validates a malformed quality payload, not the complete Swift-presentation/host-compaction composition. ADR 0026 explicitly records this remaining coverage.

Intended design

Extend the existing conformance harness to run the actual Swift presenter and pass its output through the existing TypeScript stage: 'presented' adapter before semantic compaction/publication. Keep the current acquired-input arm and shared fixture corpus. The test-only case shape should explicitly choose the input route and permit interactive requests:

type DifferentialRoute = 'acquired' | 'runner-presented';
// Existing case fields remain, including projection, scope, depth and fold policy.
// interactiveOnly becomes boolean; route names which real composition is tested.

Compare the stages on claims they share. Raw membership can preserve original source identity, while semantic compaction may delegate several sources to one representative. Assert source membership and valid representatives through the existing semantic index; do not require literal output-array equality, unchanged indexes, or a full-node superset after compaction. Do not add a second membership ledger or implement #2754's separate typed-ejection-disposition work here.

Implementation and acceptance

  1. Inventory currently skipped authored cases and unsupported harness fields. Define explicit, justified runtime asymmetries; an unsupported case must not silently disappear from the runner arm.
  2. Extend Swift conformance decoding/output and the TypeScript adapter only as needed to invoke the production pipeline. Preserve unscoped quality evidence separately from the published scoped payload.
  3. Cover regular/raw/interactive requests, scope and depth, source representatives, and scroll-host parent relationships across both input routes. Include the captured Settings chrome and Safari same-frame wrapper shapes already reduced in runner-presentation.test.ts.
  4. Retain TextView as a green control. Plant an ancestor-ownership mutation that crosses a smaller WebView or paged Cell into the enclosing list; the runner-presented interactive arm must fail for the lost reachable rows. Restore production code and prove green. Also prove the legitimate same-frame Safari pass-through remains clipped correctly.

Before/after measures: report authored cases executed per route, interactive cases that were previously excluded, and mutation failures attributed to the new arm. Every source retained by the applicable policy must have a valid presented representative; unjustified loss fails without prohibiting valid semantic delegation. Existing captured baseline outputs remain unchanged. Keep deterministic seeds, failure artifacts, and the current differential time budget; report measured duration rather than increasing it preemptively.

Validation

Run pnpm exec vitest run --project unit-core packages/capture-kit/src/ios-snapshot-engine/properties.test.ts packages/capture-kit/src/ios-snapshot-engine/runner-presentation.test.ts, then pnpm test:ios-snapshot-differential for Swift package tests and the shared differential. Run repository-wide pnpm format and pnpm check:affected --run. If harness paths need routing changes, run pnpm check:affected:test and pnpm check:gate-manifest, planting a misrouted path/failure to prove selection. Preserve native obligations reported for any runner integration changes.

Scope and readiness

Ready as characterization and harness work; a useful prerequisite to later presentation refactors, not a dependency on those refactors. No universal scroll taxonomy, new clipping heuristics, node-count alarms, production semantic changes, or replacement of the two language implementations. Unexpected discrepancies require a separately scoped diagnosis. Expected effort: M; risk: low for production, medium for accidentally asserting equivalence between intentionally different stages.

For a fresh worktree run pnpm install --frozen-lockfile && pnpm build first. Read docs/agents/testing.md.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions