cat / goq
clone

turns a linux box into a private steam streaming appliance: plug in, tap your key, play from another computer

fix/architecture-review-findings
goq / docs / public-alpha-uat.md
public-alpha-uat.md 12.3K rendered
1# Public-alpha release-candidate UAT23Issue #6 is a hardware acceptance gate, not a unit-test checkbox. This guide4turns operator observations and diagnostics into a bounded evidence bundle for5one published Sigil asset set, one published Portal asset set, and one immutable6`vVERSION` tag. The harness validates supplied evidence; it does not run the7hardware exercise, infer observations, or claim that the gate passed.89Use the actual release candidates from a clean checkout of the exact tag. `HEAD`,10a branch name, a locally rebuilt binary, a different DMG, or a moving ref is not11accepted even if its source is equivalent. Initialization and verification must12run on macOS because the Portal DMG is assessed with the platform security tools.13They also require an authenticated GitHub CLI with network access to the public14`FelineStateMachine/goq` repository; downloaded or mirrored files cannot be used15as an offline substitute for the published release identity checks.1617## 1. Initialize the bundle1819Choose an absolute path on an encrypted operator-controlled volume. Do not put20the evidence bundle in the repository or on the shared host.2122```bash23uat_dir="$PWD-private/goq-uat-rc1"24./scripts/public-alpha-uat.sh init \25 --evidence-dir "$uat_dir" \26 --release-tag v0.1.0-rc.1 \27 --sigil-archive /absolute/path/sigil-v0.1.0-rc.1-linux-glibc2.17-x86_64.tar.gz \28 --sigil-bin /absolute/path/to/sigil \29 --portal-assets /absolute/path/to/portal-v0.1.0-rc.1-assets30```3132`init` creates a mode `0700` directory and an atomic, mode `0600`, tab-separated33`manifest.tsv`. It records the resolved 40-character tagged commit, release tag,34the hashes of the signed Sigil archive/checksum/signature/public key, the exact35Sigil payload hash, all three Portal asset hashes, creation time, and the36evidence freshness window. The default window is seven days;37`--max-age-seconds` can set 3600 through 2592000 seconds.3839Before creating the bundle the harness performs all of these fail-closed checks:4041- `refs/tags/vVERSION` resolves exactly to the clean checkout's `HEAD`.42- GitHub's `FelineStateMachine/goq` tag ref resolves to that same 40-character43 commit, including through an annotated-tag chain, and the release carrying44 that exact tag is published, non-draft, and marked as a prerelease.45- The published release contains exactly the expected six Sigil and Portal46 filenames. Every supplied file's size and SHA-256 must equal GitHub's uploaded47 asset metadata; a locally valid or identically named substitution is rejected.48- `scripts/verify-sigil-release.sh` validates the archive, checksum, detached49 Minisign signature, source commit, and product contents against the reviewed50 repository key at `release/sigil-minisign.pub`.51- The supplied installed/tested `sigil` executable is byte-for-byte identical52 to `payload/release/sigil` inside that verified archive.53- The Portal directory contains exactly `Portal-VERSION-arm64.dmg`, its54 `.dmg.sha256`, and `Portal-VERSION-arm64.json`.55- `scripts/verify-portal-release.py assets` validates those three assets against56 the same clean exact tag.57- `gh attestation verify` validates all three Portal files against the exact58 `FelineStateMachine/goq/.github/workflows/portal-release.yml` signer workflow,59 `refs/tags/vVERSION`, tagged source commit, and GitHub-hosted runner boundary.60- `scripts/verify-macos-portal-signature.sh` validates the DMG, Developer ID61 signature, hardened runtime, notarization ticket, staple, Gatekeeper result,62 bundle identity/version, arm64-only executable, containment boundary, and the63 exact Apple TeamIdentifier pinned in `release/portal-apple-team-id.txt`.6465If the reviewed Sigil key is still the `unconfigured` sentinel, Minisign or66macOS verification tools are unavailable, the Apple TeamIdentifier pin is67invalid, the GitHub API or attestations cannot be verified, the macOS verifier68is absent, or any verification cannot run, initialization fails. There is no69candidate, offline, or test bypass in the UAT command.7071The bundle format is intentionally append-only at the command boundary. To72replace a mistaken record, initialize a new bundle. Do not edit the manifest or73normalized records.7475## 2. Evidence envelope7677Every input is a mode `0600` regular file at an absolute path. It begins with78these fields, copied from `manifest.tsv` where applicable:7980```text81uat_schema=goq-public-alpha-evidence-v282evidence_kind=controller83observed_at_unix=176000000084git_commit=0123456789abcdef0123456789abcdef0123456785release_tag=v0.1.0-rc.186sigil_sha256=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef87portal_sha256=abcdef0123456789abcdef0123456789abcdef0123456789abcdef012345678988```8990Use a current `date +%s` taken when that exercise finishes. An input is rejected91when a required field is missing, duplicated, stale, future-dated, or bound to92anything other than the initialized release candidates.9394Do not include node IDs, host/peer IDs, invitations, secrets, private keys, or95identity seeds. The harness rejects recognizable secret-bearing fields before96normalizing the allowlisted keys, caps each source at 1 MiB, and rejects97symlinks and group/other-writable inputs.9899Record an observation only after its exercise has genuinely completed:100101```bash102chmod 600 /absolute/path/to/controller.evidence103./scripts/public-alpha-uat.sh record \104 --evidence-dir "$uat_dir" \105 --kind controller \106 --file /absolute/path/to/controller.evidence107```108109Supported kinds are `cold-boot`, `controller`, `mouse`, `soak`,110`network-direct`, `network-relay`, `reconnect`, `second-client`, and the111optional `loopback-preflight`.112113## 3. Required hardware exercises114115Append the listed kind-specific fields after the common envelope. `pass` means116the operator actually observed that result with the initialized release117candidates.118119### Physically headless cold boot120121Disconnect every display, remove any interactive SSH session, cold boot the122Bazzite host, and wait before making the first SSH connection. Run the existing123read-only inventory check with `--cold-boot`. Its output may be used directly124after the common envelope; unrecognized inventory fields are omitted during125normalization.126127```bash128ssh tank@umpc 'cd /path/to/goq && ./scripts/bazzite-inventory.sh --cold-boot' \129 >> /absolute/path/to/cold-boot.evidence130```131132The evidence must contain:133134```text135cold_boot_result=pass136cold_boot_failure_count=0137cold_boot_insufficient_count=0138headless_connector_state=ok139gaming_autologin_session=ok140sigil_host_enabled=enabled141sigil_host_active=active142gamescope_pipewire_node=ok143gamescope_before_first_ssh=ok144sigil_unit_before_first_ssh=ok145sigil_ready_before_first_ssh=ok146```147148`gaming_autologin_session=ok` means logind reported an active, local session149for the gaming user whose exact PAM service name ends in `-autologin`, such as150`sddm-autologin` or `gdm-autologin`; an SSH or manual desktop login does not151qualify.152153This proves Gamescope and Sigil became ready before first SSH, not merely that154they were running after an operator repaired the boot.155156### Physical controller and neutral release157158Attach a physical controller to the Portal client and control an actual game159for at least five minutes. Exercise every named control class. Disconnect or160end the session while controls are active and observe the host returning both161buttons and axes to neutral.162163```text164physical_controller_attached_to_portal=pass165actual_game_controlled=pass166controller_coverage=abxy,dpad,sticks,triggers,shoulders,start-back167neutral_release_on_disconnect=pass168neutral_buttons=pass169neutral_axes=pass170session_seconds=300171```172173### Mouse buttons in Gamescope/an actual game174175Pointer motion or hover changes are insufficient. In a bounded target slug,176observe at least five attempts and confirm both buttons are consumed by the177Gamescope target application or actual game:178179```text180target_application=actual-game181left_click_consumed=pass182right_click_consumed=pass183consumption_observed_in_target=pass184click_attempts=10185```186187### Sustained A/V and resource soak188189Run an uninterrupted session for at least 3600 seconds and collect at least 60190samples. Report measured percentiles, not estimates:191192```text193duration_seconds=3600194samples=60195capture_fps_p50=59.8196presentation_fps_p50=59.2197frame_interval_p95_ms=20198hitch_p99_ms=40199video_queue_p95_frames=1200decode_queue_p95_frames=1201audio_queue_p95_ms=50202av_skew_p95_ms=30203max_queue_age_p95_ms=45204cpu_p95_percent=50205gpu_p95_percent=70206rss_p95_mib=512207transport_drops=2208frontend_drops=3209audio_drops=0210latency_first_window_p95_ms=30211latency_last_window_p95_ms=33212disconnects=0213```214215The fail-closed bounds are: capture and presentation p50 at least 55 fps;216frame interval p95 at most 25 ms; hitch p99 at most 50 ms; video and decoder217queues p95 at most two frames; audio queue and maximum queue age p95 at most218100 ms; A/V skew p95 at most 50 ms; CPU p95 at most 90%; GPU p95 at most 95%;219RSS p95 at most 2048 MiB; and zero disconnects. Last-window latency p95 must be220no more than 120% of the first window and may grow by no more than 5 ms. Drop221counts remain visible evidence rather than being silently discarded.222223### Direct and difficult-NAT relay paths224225These are separate records and separate sessions of at least ten minutes. Do226not relabel an ordinary direct connection as a relay exercise.227228`network-direct`:229230```text231path_mode=direct232nat_scenario=ordinary233session_seconds=600234rtt_p50_ms=10235rtt_p95_ms=20236input_ack_p95_ms=30237presentation_latency_p95_ms=60238packet_loss_percent=0.1239```240241`network-relay` uses the same timing fields with:242243```text244path_mode=relay245nat_scenario=difficult246```247248Both records reject packet loss over 5%. The relay run must be forced or249observed under the documented difficult-NAT setup and confirmed as relayed by250Portal diagnostics.251252### Reconnect and second-client admission253254Perform at least ten reconnects with the exact candidates. Each must restore255the intended session state and resume from a keyframe:256257```text258reconnect_cycles=10259reconnect_successes=10260reconnect_failures=0261state_preserved=pass262keyframe_recovery_p95_ms=900263```264265Keyframe recovery p95 must not exceed 2000 ms.266267While the authorized primary session remains playable, attempt a second client268at least three times:269270```text271second_client_attempts=3272second_client_rejections=3273authorized_primary_uninterrupted=pass274rejection_reason=active-client275```276277## 4. Optional loopback preflight278279The existing loopback proof is useful preflight evidence, but it does not280replace any physical gate. Run it from the exact committed tree using release281mode. Its output includes an operationally sensitive `node_id`, so remove that282line before ingestion and add the common envelope:283284```bash285./scripts/loopback-proof.sh --profile release \286 | sed '/^node_id=/d' \287 >> /absolute/path/to/loopback-preflight.evidence288chmod 600 /absolute/path/to/loopback-preflight.evidence289```290291The normalized record requires:292293```text294loopback_proof=ok295profile=release296host_sha256=<same value as sigil_sha256>297active_client_rejection=ok298reconnect_cycles=3299cleanup=ok300```301302The harness ingests the output by value and never mutates the Bazzite host.303304## 5. Verify and retain305306Verification requires the exact same signed asset sets and tested Sigil307executable again. It reruns every release, Minisign, and macOS platform check;308it also reruns the live GitHub release/tag/digest and Portal provenance checks.309Stored hashes alone are not sufficient:310311```bash312./scripts/public-alpha-uat.sh verify \313 --evidence-dir "$uat_dir" \314 --sigil-archive /absolute/path/sigil-v0.1.0-rc.1-linux-glibc2.17-x86_64.tar.gz \315 --sigil-bin /absolute/path/to/sigil \316 --portal-assets /absolute/path/to/portal-v0.1.0-rc.1-assets317```318319Success prints `public_alpha_uat=pass` plus the release tag, commit, artifact hashes, and320required gate count. Verification rejects missing records, expired timestamps,321changed tags, wrong artifacts, modified normalized evidence, unsafe modes,322symlinks, unpublished or non-prerelease releases, mismatched remote asset323digests, invalid Portal attestations, and unexpected bundle files.324325That output means the supplied bundle satisfies the machine-checkable contract.326It is not evidence that an exercise occurred unless the inputs came from the327real operator run. Preserve the verified directory read-only as release328evidence, separately from publish credentials and product artifacts.329330Run the fixture suite before changing the contract:331332```bash333shellcheck scripts/public-alpha-uat.sh scripts/tests/public-alpha-uat.sh334./scripts/tests/public-alpha-uat.sh335```