Skip to content

feat(Flyover): export a static QA atlas - #270

Open
kyleve wants to merge 15 commits into
mainfrom
codex/static-flyover-qa-atlas
Open

feat(Flyover): export a static QA atlas#270
kyleve wants to merge 15 commits into
mainfrom
codex/static-flyover-qa-atlas

Conversation

@kyleve

@kyleve kyleve commented Aug 14, 2026

Copy link
Copy Markdown
Owner

Posted by an AI agent on kve's behalf.

Summary

  • User-facing: add ./flyover export to generate a portable, network-free Where QA atlas from native simulator captures
  • User-facing: add ./flyover preview to serve an existing atlas, print a local or LAN URL, and shut down cleanly with Ctrl-C
  • User-facing: export Phone Light and Phone Dark when no --profile flags are supplied; explicit flags still select only the requested profiles
  • User-facing: present the catalog through a polished canvas, grouped list, command-palette search, route navigation, and immersive inspector
  • User-facing: support responsive phone and short-landscape layouts, touch-sized controls, pinch zoom, keyboard control, deep links, state/profile playback, and full-content review
  • User-facing: prevent accidental browser text selection and screenshot dragging while keeping search, titles, errors, and metadata copyable
  • Performance: load every visible screenshot, apply the six-image and 24-million-pixel targets only to optional offscreen preloads, and unload thumbnails while the inspector owns the image
  • Internal: keep export planning generic inside Flyover and use SnapshotKitTesting's serialized hosted capture pipeline
  • Internal: build every Where capture from one frozen, synthetic, in-memory WhereFlyoverWorld
  • Repository: require agents to commit and push each coherent verified change unless the user requests otherwise

Why

Flyover previously kept the native screen catalog inside the app. This change makes the same registered screens, states, routes, and native renders available as a disposable static artifact.

The refined web shell gives the catalog the hierarchy and interactions of a focused review tool. It preserves native Flyover concepts while adapting navigation, inspection, and density to desktop and mobile browsers.

Product behavior

  • The canvas consumes the manifest's group, screen, depth-band, and connector geometry. Initial framing matches native Flyover's first-group width fit and top-leading alignment.
  • The floating dock owns view selection, zoom, fitting, group navigation, and filters. Canvas and list positions survive view changes.
  • Search opens with / or Command-K. It finds groups, screens, states, and routes and moves focus to a visible result.
  • Cards expose native state choices and distinguish push and modal routes. Explicit route labels are preserved.
  • List mode presents the same catalog as compact grouped rows with responsive route summaries.
  • The inspector supports fit and actual-size modes. Full-content and two-axis captures use bounded, keyboard-accessible scrolling frames.
  • Atlas chrome, card labels, panel results, and screenshots do not create browser selections. Search text, inspector titles, error details, and metadata values remain selectable.
  • The URL hash preserves view, screen, state, and profile. Browser Back and Forward restore prior selections.
  • Mobile layouts use 44-point targets, responsive panels, focus containment, and pinch zoom. Short landscape layouts keep primary controls and content usable.
  • ./flyover export captures Phone Light followed by Phone Dark by default. Repeated --profile flags replace those defaults, preserve their first-occurrence order, and remove duplicates.
  • ./flyover preview validates the default export, selects a free port, and prints the local URL. --output selects another atlas, and --port selects a fixed port.
  • ./flyover preview --lan prints reachable network URLs for phones and other devices. It warns that LAN preview has no authentication or TLS.

Correctness and native parity

  • Route navigation opens the destination's default state, while previous/next screen navigation preserves each screen's selected state.
  • Depth zero is labeled Entry, matching native Flyover. Routes with filtered endpoints are hidden.
  • Snapshot-backed variants preserve sizing, readiness, settle, and hook behavior. A mixed sizing matrix remains unresolved until the app supplies an explicit export policy.
  • SnapshotKitTesting waits for the hosted key window, serializes capture access, and exits canceled work before it mutates hosted rendering state or publishes output.
  • The native Flyover Open Spans screen continues to use Periscope.shared. Web export receives the synthetic world's isolated log system, so export never reads process or user data.
  • The command validates output aliases and publish-time races, preserves the previous successful artifact on failure, and selects only the requested hosted export method.
  • Preview binds to loopback by default. It serves only validated shell files and manifest images, blocks path traversal and absolute request targets, and never logs untrusted request text.
  • Preview handles Ctrl-C without exception-based signal delivery, shuts down from outside the server loop, restores the prior signal handler, and propagates server-loop failures.
  • Preview verifies that manifest.js matches manifest.json. It also rejects unsupported markers, missing images, extra images, and symbolic links before it binds a port.
  • Canvas and list views assign eager sources to every visible screenshot. Fit and zoom actions refresh residency, while only optional offscreen list preloads use the soft budgets.

Architecture

  • Flyover owns stable web identities, export policies, profiles, manifest data, image planning, and the dependency-free static shell.
  • SnapshotKitTesting owns PNG rendering through its existing host window, capture lock, readiness hooks, settle policies, and size limits.
  • WhereUI owns the stable ID adapter, named variants, synthetic world, catalog, and hosted export entry point.
  • The shell uses relative local assets only. It does not use fetch, packages, remote fonts, analytics, or external scripts.
  • The preview server uses Python's standard library. It adds no package or runtime dependency beyond the Python 3 requirement already used by the root tools.

Measured Where artifact

phone-light currently exports 5 groups, 50 screens, 108 states, 41 routes, and 108 PNGs. The checked artifact is 75,029,681 bytes and represents 456,924,582 native-scale pixels. A browser check loaded all 50 visible cards after Fit All and all three visible rows in the current list viewport.

Compatibility

The feature is DEBUG-only and test-only. It changes no production data, backup, persistence, or release runtime behavior. schemaVersion: 1 remains the artifact boundary.

Testing

  • ./test --everything — 2,005 iOS tests and 50 snapshot tests passed on the final atlas tree
  • ./test --only 'WhereUISnapshotTests/WhereFlyoverWebExportTests/exportsHostedSmokeAtlas()' — exact two-screen, two-profile hosted PNG matrix passed
  • ./test FlyoverTests SnapshotKitTestingTests WhereUITests — 606 focused tests passed during atlas review
  • ./test FlyoverTests — 54 tests passed after adding visible-image residency, selection-policy, and two-profile default coverage
  • python3 -m unittest discover -s Tools/Tests -p 'test_*.py' — 76 tests passed
  • bash Shared/Flyover/Tools/Tests/flyover_test.sh — default and explicit profile selection, production residency paths, and the web selection policy passed
  • Preview lifecycle stress — 10 consecutive startup, request, and Ctrl-C shutdown cycles passed
  • ./shellcheck
  • ./swiftformat --lint
  • JavaScriptCore syntax parse of Shared/Flyover/Web/assets/app.js
  • git diff --check
  • ./flyover export --output /tmp/where-flyover-codex --profile phone-light — 50 screens, 108 states, 41 routes, 108 valid PNGs
  • ./flyover preview --output /tmp/where-flyover-codex — served the 50-screen, 108-image atlas from the printed loopback URL
  • Browser validation — Canvas Fit All loaded 50 of 50 visible cards; list mode loaded 3 of 3 visible rows
  • Browser validation — atlas and top-layer dialog chrome computed to user-select: none; intentional copy surfaces computed to text; all screenshots used draggable="false"
  • Manual iPhone Simulator review of canvas, list, viewport inspector, and full-content inspector; separate short-landscape responsive review

/// Throws when a settle phase cannot produce a trustworthy capture.
@MainActor
func reportIfUnsettled(
func throwIfUnsettled(

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review focus: this deliberately changes unsettled and starved captures from recorded test issues followed by image generation into typed throws. assertSnapshots still records the thrown error, while the new hosted PNG caller stops immediately and cannot publish that image. Cancellation now follows the same path through CancellationError.

@kyleve kyleve closed this Sep 1, 2026
Make the atlas canvas-first with a compact floating dock, command-palette navigation, grouped list rows, and an immersive screenshot inspector. Preserve manifest and deep-link compatibility while keeping secondary review tools available in focused panels.\n\nValidation:\n- ./flyover export --output /tmp/where-flyover-codex --profile phone-light\n- ./test FlyoverTests\n- bash Shared/Flyover/Tools/Tests/flyover_test.sh\n- ./swiftformat --lint\n- JavaScriptCore syntax parse
@kyleve kyleve reopened this Sep 3, 2026
Resolve the command-runner extraction while preserving Flyover export progress. Adapt accessibility preparation to main's throwing settle behavior.
Run the Flyover shell self-test when its module fixture is present. Keep extracted test-runner contract fixtures independent of module-specific files.
)
}

private var profileSize: CGSize {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this duplicated from anywhere?

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.

1 participant