Skip to content

Replace the local web dashboard with a native GTK4 OpenFrag app #48

Open

Description

@NtrpyDev

Goal

Replace the local browser dashboard with an installed native GTK4 desktop client before v1. Keep the daemon and recorder as background processes so capture and Game State Integration continue when the window is closed.

Settled architecture

One OpenFrag installation ships:

  • openfrag, the GTK4 desktop client for stats, setup, Doctor, Match evidence, Clip review, settings, and status.
  • openfragd, the private background service that owns SQLite, files, capture coordination, Game State Integration, imports, and mutations.
  • openfrag-recorder, the pinned supervised capture helper.

The desktop client communicates with the daemon through a private Unix domain socket. It never opens SQLite directly. Remove the browser launcher, embedded dashboard HTML, loopback TCP listener, and public HTTP-shaped product language.

Five-round decision: GTK4 versus Tauri

  1. Product fit: GTK4 wins because the requested product is genuinely native; Tauri remains a webview.
  2. Existing UI reuse: Tauri wins because it could reuse HTML, CSS, and JavaScript.
  3. Linux integration and accessibility: GTK4 wins through native widgets and desktop integration.
  4. Security boundary: GTK4 wins because it removes the browser renderer and localhost transport from the trusted UI path.
  5. Packaging and long-term ownership: GTK4 wins because OpenFrag is Linux-first and Rust-based, while Tauri adds a frontend toolchain plus a system webview dependency.

Winner: GTK4, four rounds to one. The short-term rewrite cost is accepted to avoid shipping a v1 interface already marked for replacement.

Required implementation

  1. Add a Rust GTK4 desktop binary with canonical application identity and one main window.
  2. Preserve domain logic below the UI. Expose typed daemon operations over a private, permission-restricted Unix socket.
  3. Implement setup, Doctor, Match and Rating evidence, stats, Clip preview/review/trim/export, Manual Flag status, capture status, errors, and empty/loading states.
  4. Keep capture and Game State Integration alive when the window closes. The app may activate or focus an existing window without starting a second daemon.
  5. Remove the embedded HTML dashboard, JavaScript, browser launch path, localhost API listener, and their packaging/runtime dependencies.
  6. Make every state keyboard accessible, screen-reader legible, deterministic under test, and safe with untrusted file names and imported content.
  7. Package the client, daemon, service, launcher, icons, desktop metadata, and recorder as one product in AUR, Fedora 43, and Fedora 44 channels. The removed generic binary tar channel is not a v1 target.
  8. Add focused widget/presenter tests, typed transport contract tests, accessibility-tree assertions, headless native journeys, and installed desktop smoke checks.
  9. Update the support matrix with real KDE Wayland and GNOME Wayland results.

Acceptance criteria

  • Launching OpenFrag opens a native desktop window, not a browser.
  • No shipped process listens on TCP for the UI.
  • Closing the window does not stop an enabled replay buffer or Game State Integration.
  • The client cannot mutate SQLite or media outside the daemon contract.
  • Every dashboard capability represented in v1 has an equal or stronger native workflow and automated proof.
  • Installed AUR, Fedora 43, and Fedora 44 packages contain and launch the same application identity.
  • PC1 and PC2 complete the native installed journey with explicit human observation.

Activity

  1. added
    wayfinder:taskTask ticket: manual work that unblocks the discussion
    on Jul 15, 2026
  2. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    User-authored placeholder assets supplied on 2026-07-15:

    • Icon: /home/glorg/Pictures/openfrag-icons/openfrag_icon.png, 512 x 512 RGBA, SHA-256 660579ff55d5f5a7cf2e84411fd45a544926210f2454fd9ff598249849779200
    • Banner: /home/glorg/Pictures/openfrag-icons/openfrag_banner.png, 1500 x 500 RGBA, SHA-256 652be5d4f5d480fa64f54035d22a5061422d526d34c88e86ddf1a50b327bef1f

    Preserve the originals and import their exact bytes for the native app and documentation. Any later redesign is a separate explicit decision. Do not silently overwrite or regenerate these files.

  3. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Five-round transport decision: bounded JSON frames vs binary frames

    The settled seam is one typed request and one typed response per private Unix-socket connection. Demo import passes an explicitly selected local path, and Clip preview returns a daemon-authorized path, so the transport does not need to carry large media payloads.

    1. Inspectability: bounded JSON wins because a local request can be audited without a protocol-specific decoder.
    2. Type safety: tie because both options use the same versioned Rust request and response enums.
    3. Framing safety: binary length prefixes are slightly simpler for arbitrary bytes, but bounded newline-delimited JSON is safe here because strings escape newlines and media bytes never cross this seam. Winner: bounded JSON.
    4. Performance: binary frames win on encoding size and CPU, though the expected control payloads are small.
    5. Compatibility and diagnosis: bounded JSON wins because protocol mismatches and diagnostics remain human-readable across package versions.

    Winner: bounded JSON, four rounds to one.

    The implementation will cap request and response frames, reject trailing or unknown data, create the runtime directory with private permissions, create the socket with mode 0600, verify the peer user, and handle one request per connection. The small external interface is Client::execute(Request) -> Reply; storage, imports, capture, and setup remain behind the daemon adapter.

  4. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Native vertical-slice progress:

    • Renamed the home surface from Tonight to Last Session in f7a566b.
    • Added typed clip summaries to the private Unix-socket protocol in 07f1689.
    • The daemon maps persisted clip records without exposing private media paths.
    • The GTK Clips page now renders empty and populated review-list states.
    • Verified cargo test -p openfrag --lib, cargo test -p openfrag-ipc, cargo test -p openfragd --test ipc_contract, and targeted Clippy with warnings denied.
    • Live native window was launched against a composed daemon and rendered the real setup state and placeholder banner.

    Ticket remains claimed. Clip editing, preview, trim, export, setup actions, diagnostics, match detail, Receipts, packaging, and native journey tests still remain before resolution.

  5. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Five-round setup mutation decision: broad form versus action enum

    The native client must invoke setup mutations without letting invalid field combinations become routine protocol states.

    1. Invalid-state prevention: the action enum wins because each variant carries only the fields that action accepts.
    2. Reuse of the existing daemon DTO: the broad form wins because it can be forwarded with almost no translation.
    3. Native UI dispatch: the action enum wins because each button constructs one explicit command instead of a string plus unrelated optional fields.
    4. Protocol evolution: the action enum wins because adding or changing an action forces exhaustive compiler errors in the client and daemon adapters.
    5. Security review and auditability: the action enum wins because consent, paths, and background preference are visible on the exact variants that use them.

    Winner: a dedicated setup action enum, four rounds to one. The daemon adapter will translate it into the existing internal setup request so domain logic remains unchanged.

  6. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Native Doctor progress:

    • e6eb4a2 exposes the daemon setup snapshot and renders every check and action in the GTK Doctor.
    • A five-round comparison selected a dedicated setup mutation enum over a broad optional-field form, four rounds to one.
    • 35b7b9f types every setup mutation and proves a real defer-GSI state change through daemon composition.
    • fd1a6b9 wires GTK controls, required-field validation, explicit consent confirmation, asynchronous socket I/O, and full Doctor rerendering.
    • A freshly linked target/debug/openfrag showed Last Session and reached Setup and Compatibility Doctor entirely by keyboard.
    • The live defer action changed the rendered GSI state to Not tested / deferred.
    • Closing the client window terminated the client while the same openfragd process remained alive.

    Ticket remains claimed. Match details and Receipts, complete Clip workflows, import, Manual Flag, accessibility-tree automation, dashboard removal, and packaging remain.

  7. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Five-round Match navigation decision: inline expansion versus dedicated evidence page

    1. Scanability: inline expansion wins because the user can peek without leaving the Match list.
    2. Information capacity: a dedicated page wins because player stats, Rating state, and many Receipts need stable space.
    3. Keyboard and screen-reader navigation: a dedicated page wins because it has one heading and predictable controls instead of changing row geometry.
    4. Receipt drill-down: a dedicated page wins because it can open evidence without nesting interactive controls inside a list row.
    5. Future growth: a dedicated page wins because round timelines and comparisons can grow without destabilizing the Match list.

    Winner: a dedicated Match evidence page, four rounds to one. The Match list remains a fast, single-action index, and selecting a row opens the evidence page inside the same native window.

  8. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Five-round Demo picker decision: FileChooserNative versus FileDialog

    1. Async GTK integration: FileDialog wins because its API is future-based and fits the nonblocking client workflow directly.
    2. Old GTK compatibility: FileChooserNative wins because it exists before GTK 4.10.
    3. Desktop portals: tie because both can delegate to the platform file chooser under supported desktops.
    4. API longevity: FileDialog wins because FileChooserNative is deprecated in current GTK.
    5. Supported v1 packages: FileDialog wins because Fedora 43, Fedora 44, and current Arch all satisfy GTK 4.10 or newer, so the older floor does not benefit a claimed v1 channel.

    Winner: FileDialog, three rounds to one with one tie. OpenFrag will raise its declared GTK feature floor to 4.10 and pass only the explicitly selected local Demo path to the private daemon.

  9. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Native evidence and import progress:

    • A five-round navigation comparison selected a dedicated Match evidence page over inline row expansion, four rounds to one.
    • 07710a6 adds typed Match detail and Receipt requests, dedicated GTK pages, loading states, back navigation, bounded imported evidence text, and typed not-found errors.
    • A five-round picker comparison selected GTK FileDialog over FileChooserNative, three rounds to one with one tie.
    • 963c9d2 raises the supported GTK floor to 4.10, opens a filtered native Demo picker, passes only the selected absolute path, rejects relative paths, non-Demo files, non-regular files, symlinks, and files over 2 GiB, and refreshes Matches after a completed import.
    • Demo reading and parsing run on blocking worker pools so neither the GTK event loop nor the daemon async socket executor is blocked.
    • Presenter, private protocol, real daemon composition, former API compatibility, targeted Clippy, and linked native binary checks pass.

    Ticket remains claimed. Clip preview and mutations, Manual Flag and diagnostics, browser-surface removal, accessibility automation, and native packaging still remain.

  10. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Five-round Manual Flag placement decision: Setup versus Last Session

    1. Setup clarity: Setup wins because portal approval and initial shortcut availability are configuration concerns.
    2. In-match reachability: Last Session wins because Manual Flag is a routine capture action after setup, not a configuration task.
    3. Status visibility: Last Session wins because capture, Game State Integration, and shortcut readiness belong beside current operating status.
    4. Error recovery: Last Session wins because a failed flag can show an immediate local error without sending the user back into setup.
    5. Accessibility and workflow separation: Last Session wins because configuration stays in Doctor while the primary operational action remains in the main tab order.

    Winner: Last Session, four rounds to one. Setup retains approval and repair actions; Last Session gains typed diagnostics, current capture status, and the Manual Flag action with a deterministic result or explicit error.

  11. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Native Manual Flag and status progress:

    • A five-round comparison selected Last Session over Setup for the operational Manual Flag action, four rounds to one.
    • 08b6ecc adds typed Diagnostics and Manual Flag requests and replies to the private Unix-socket protocol.
    • Last Session now shows replay capture, Game State Integration, and shortcut readiness, and exposes an accessible Manual Flag action with deterministic success or explicit error status.
    • The daemon no longer sends these operations through untyped JSON values.
    • Setup now reports a ready shortcut as ready instead of incorrectly asking for approval again.
    • Daemon tests now use an isolated temporary setup home instead of reading the developer account setup state.
    • The targeted presenter, protocol, daemon, socket, capture, import, and durable Clip suites passed, with 57 tests in the touched packages and warnings denied for the owned targets.

    Ticket remains claimed. Browser-surface removal, native accessibility journeys, installed packaging, and complete acceptance evidence still remain.

  12. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Five-round browser-surface removal decision: unreachable compatibility code versus complete deletion

    1. Migration speed: unreachable compatibility code wins because existing HTTP tests and handlers could remain unchanged.
    2. Security boundary: complete deletion wins because no dormant UI listener, multipart upload route, or media-serving handler remains available to reconnect accidentally.
    3. Test fidelity: complete deletion wins because tests must exercise the same typed Unix-socket contract the native client ships.
    4. Dependency surface: complete deletion wins because dashboard-only multipart, streaming, HTML, JavaScript, browser, and launcher dependencies can leave the product.
    5. Maintainability: complete deletion wins because every supported UI operation has one transport and one authoritative contract.

    Winner: complete deletion, four rounds to one. The official loopback Game State Integration endpoint remains a separate Valve-facing input; all desktop control moves exclusively through the private Unix socket.

  13. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Five-round reply framing decision: wrapper structs versus adjacent tagging

    The original internally tagged reply enum cannot serialize sequence newtypes such as Match and Clip collections. Both valid fixes preserve typed JSON and the one-frame socket boundary.

    1. Uniform wire shape: adjacent tagging wins because every reply becomes {result, data} regardless of whether its payload is a struct, list, or scalar.
    2. Flat human readability: wrapper structs win because successful struct fields can remain at the top level.
    3. Type overhead: adjacent tagging wins because it does not require a bespoke named wrapper for every collection and future scalar result.
    4. Serialization correctness: adjacent tagging wins because Serde supports every current enum payload shape directly.
    5. Evolution and testability: adjacent tagging wins because generic contract tests can round-trip every request and reply variant through the same envelope.

    Winner: adjacent tagging, four rounds to one. Replies will use a bounded {result, data} envelope, while errors remain typed payloads inside the same envelope.

  14. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Browser-surface removal progress:

    • A five-round comparison selected complete deletion over unreachable compatibility code, four rounds to one.
    • fc7fde7 removes the embedded HTML and JavaScript dashboard, all desktop HTTP routes, multipart upload and media streaming handlers, and their runtime dependencies.
    • Existing setup and durable Clip tests were rewritten against the private typed contract instead of deleted.
    • A protocol audit found that internally tagged collection replies could not serialize. A five-round comparison selected adjacent {result, data} framing, four rounds to one, and 80ebc47 fixes and round-trips collection frames.
    • 80ebc47 also removes Playwright, Node, the browser launcher, xdg-open, and the generic binary archive channel from product, CI, release, and test configuration.
    • AUR and COPR now build and install the native openfrag client alongside openfragd and the bundled recorder. The desktop entry launches openfrag directly.
    • Headless process smoke now proves the TCP listener exposes only Valve GSI routes and exercises every desktop operation through the permission-restricted Unix socket.
    • The staged installed MVP journey passes Demo import, Rating and Receipts, Manual Flag, Clip review, preview, trim, export, diagnostics privacy, and shutdown using the native product contract.
    • The optimized fast suite passes with four concurrent jobs in 61.28 seconds against a 120 second budget.
    • 48c14f0 pins the deterministic native-channel source archive at SHA-256 fc6ed0884f5bd7decf93d29b47d6623cbe57882049f957dd7ae938d04cb1fe14, and the AUR/COPR source verifier passes.

    Ticket remains claimed. Native accessibility-tree and headless window journeys, installed client launch proof, final package environments, and physical desktop observations still remain.

  15. 8 remaining items

  16. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Five-round decision: populated native acceptance harness

    Option A: extend the existing AT-SPI harness with a populated-state mode and an existing private socket
    Option B: create a second GUI test script dedicated to populated Matches and Clips

    1. Shared lifecycle correctness: A wins. D-Bus, Xvfb, AT-SPI registry, client close, and cleanup remain one audited implementation.
    2. Source isolation: B wins. Fresh-state and populated-state assertions live in smaller independent files.
    3. Suite speed: A wins. The installed MVP can reuse its already populated daemon and socket without another import/capture setup.
    4. Behavioral consistency: A wins. Both modes use the same keyboard, role, state, focus, timeout, and failure-reporting primitives.
    5. Maintenance risk: A wins. Changes to GTK startup or accessibility service discovery require one fix instead of two synchronized fixes.

    Winner: Option A, 4-1. The reusable harness will support fresh and populated modes; the complete installed journey will reuse its live private socket and assert Match, Receipt, Clip editor, export, and delete-confirmation controls.

  17. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Decision: GTK StackSidebar versus explicit grouped native navigation controls.

    Round 1, visual fit: explicit controls win because they reproduce the supplied left-aligned mock navigation directly.
    Round 2, dynamic-page behavior: explicit controls win because Match, Receipt, and Clip editor pages never become primary destinations or clear the navigation contract.
    Round 3, implementation size: StackSidebar wins because it requires less application code.
    Round 4, keyboard and assistive technology: explicit controls win because each destination exposes a stable toggle-button action and deterministic focus order.
    Round 5, acceptance reliability: explicit controls win because the same native actions work in fresh and populated AT-SPI journeys without test-only workarounds.

    Winner: explicit grouped native navigation controls, 4-1.

    Implemented evidence: supplied UI mocks now drive the native layout, Tonight remains renamed to Last Session, Match and Clip rows expose explicit native buttons, transient evidence/editor pages stay out of primary navigation, and the installed acceptance journey traverses populated Match, Receipt, Clip editor, and delete confirmation state against a live external daemon. Fresh and populated accessibility journeys pass, the installed MVP journey passes, and the optimized fast suite passes in 10.52s with four jobs.

  18. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Decision: install the supplied icon through the freedesktop hicolor theme versus reference a package-private absolute asset path.

    Round 1, desktop compatibility: hicolor wins because the desktop entry can use the canonical application ID on KDE, GNOME, and other freedesktop shells.
    Round 2, native package conventions: hicolor wins because both Arch and Fedora expect application icons under the shared theme hierarchy.
    Round 3, per-user installation: hicolor wins because the same hierarchy works under XDG_DATA_HOME without rewriting the desktop Icon field.
    Round 4, upgrade and uninstall ownership: hicolor wins because every channel can replace and remove one canonical file while preserving user data.
    Round 5, verification: hicolor wins because package-root and staged lifecycle checks can compare exact bytes and mode at the same relative path.

    Winner: the standard hicolor application path, 5-0.

    Implemented evidence: the 512x512 supplied icon now ships through static, AUR, and RPM channels; source archives include it; release authority checks require it; all upgrade and removal verifiers cover it; the previously undefined full Linux asset-verifier command was removed. Full Linux asset verification passes, deterministic AUR/COPR source verification passes, and the four-job fast suite passes in 9.15s.

  19. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Documentation structure decision, five rounds.

    Option A was a single comprehensive README. Option B was a concise README that routes users by intent into installation, first-run, troubleshooting, architecture, support, testing, contribution, and security documents.

    1. Orientation: B wins because a new user sees the product and the first action without crossing implementation detail.
    2. Task completion: B wins because each procedure can state prerequisites, commands, expected results, and recovery in one place.
    3. Maintenance: A wins narrowly because one file has fewer links and version seams to maintain.
    4. Audience separation: B wins because users, contributors, package maintainers, and release reviewers do not need the same depth.
    5. Release honesty: B wins because qualification state and unpublished-package boundaries stay prominent without burying the product overview.

    Winner: intent-routed documentation, 4-1. The README is now the stable entry point, and every new local link passes a repository-wide target check.

  20. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Clean-package dependency decision, five rounds.

    Option A was to maintain a second hand-written dependency list inside the container verifier. Option B was to install the dependency declarations from PKGBUILD and the RPM spec.

    1. Package fidelity: B wins because the clean build consumes the same dependency contract users and builders receive.
    2. Review simplicity: B wins because a dependency changes in one authoritative recipe instead of two lists.
    3. Container minimalism: A wins because a curated verifier list can omit runtime-only packages.
    4. Failure meaning: B wins because a missing or invalid recipe dependency fails the package gate instead of being masked by verifier-only packages.
    5. Distribution conventions: B wins because Arch arrays and RPM BuildRequires remain native inputs to their own package managers.

    Winner: recipe-driven dependency installation, 4-1. The verifier will source the trusted PKGBUILD arrays and use Fedora builddep on the checked-in spec before building.

  21. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Recorder root-boundary decision, five rounds.

    Option A allows only the side-effect-free --version query before the recorder root refusal. Option B keeps every argument behind the root refusal and makes each build or package verifier switch users for version inspection.

    1. Runtime safety: tie because neither option permits capture as root.
    2. Package inspection: A wins because package scripts, inventory tools, and administrators can identify a binary without GPU or capture access.
    3. Upstream-diff size: A wins because it is one narrow early-exit condition in the internal fork.
    4. Verifier isolation: B wins because the recorder itself has no root exception at all.
    5. Cross-channel consistency: A wins because Arch, RPM, staged install, and checksum validation all use the same harmless version contract regardless of caller UID.

    Winner: root-safe version inspection, 3-1 with one tie. Capture and every other command continue to fail for effective UID 0.

  22. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Shared-drive source-mode decision, five rounds.

    Option A was to build archives only from git archive at committed HEAD. Option B was to copy the selected working-tree bytes and then normalize each file to its Git index mode.

    1. Mode correctness: tie because both derive executable bits from Git rather than the NTFS/FUSE mount.
    2. Dirty-tree diagnosis: B wins because a developer suite continues to package the bytes under test instead of silently packaging older committed bytes.
    3. Implementation size: A wins because Git performs archive generation directly.
    4. Path selection and submodule handling: B wins because the existing explicit source allowlist and pinned recorder copy remain unchanged.
    5. Release determinism: tie because both produce normalized tar metadata and byte-identical clean-commit archives.

    Winner: copy bytes then normalize Git modes, 2-1 with two ties. The bundle will apply 100644 and 100755 from each repository index after extraction.

  23. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Packaged recorder checksum decision, five rounds.

    Option A disables post-install stripping for the package so the recorder bytes hashed during package assembly are the bytes installed. Option B lets package tooling transform the binary and weakens or regenerates the checksum later.

    1. Runtime integrity: A wins because the checksum is immutable package payload, not first-run state.
    2. Package size and debug symbols: B wins because normal stripping produces smaller packages and separate debug information.
    3. Cross-channel determinism: A wins because Arch, RPM, and per-user installs share one exact-byte rule.
    4. Security review: A wins because no install script or first-run trust window writes the expected hash.
    5. Packaging convention: B wins because distribution defaults prefer stripping and debug extraction.

    Winner: preserve packaged recorder bytes, 3-2. Arch and Fedora will explicitly opt out of post-install stripping with a documented integrity reason; the runtime checksum remains strict.

  24. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Third-party notice collision decision, five rounds.

    Option A merges OpenFrag and recorder notices into one generated file. Option B installs the original notices under distinct stable filenames.

    1. License provenance: B wins because each exact upstream or project-authored notice remains independently auditable.
    2. User convenience: A wins because there is only one file to open.
    3. Reproducibility: B wins because packaging does not generate or concatenate legal text.
    4. Cross-channel consistency: B wins because Arch already uses distinct recorder notice and fork filenames.
    5. Collision resistance: B wins because future files with the same basename cannot overwrite one another.

    Winner: distinct installed notice files, 4-1. Every package verifier will byte-compare the OpenFrag notice, recorder fork description, and recorder third-party notice separately.

  25. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Complete software and package gate passed for the native v1 candidate.

    Evidence:

    • Complete suite: PASS in 1,014.73s under the 1,200s budget, four jobs, maximum two concurrent native package builds.
    • Clean Arch: build, tests, namcap, install, reinstall, smoke, removal, and preserved state passed.
    • Clean Fedora 43 and Fedora 44: build dependencies from the spec, hardened build, tests, rpmlint with zero errors, install, reinstall, smoke, removal, and preserved state passed.
    • Two source bundles were byte-identical and match SHA-256 c5e16898ae03a3dd4223d33f97b3a881ee1f6064963de70378754caf4a88d783.
    • The archive contains the pinned recorder fork at f9566cf1b0467bc43918ac5322d2c9fe0d6cdb1b, preserves Git file modes on NTFS/FUSE, and packages distinct verified legal notices.
    • Fresh and populated native AT-SPI journeys and the installed MVP journey passed.

    Result directory: /mnt/shared/openfrag/target/openfrag-suite/runs/complete-20260715T215036Z-158873.

    Ticket remains claimed because physical KDE/AMD PC1 and GNOME/NVIDIA PC2 installed journeys are still acceptance criteria.

  26. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    The supplied Doctor, Clips, Last Session, and Matches mocks are now the visual contract for this ticket, with the settled Last Session terminology replacing Tonight.

    The first real KDE launch exposed a scaffold-quality shell: oversized generic cards, sparse hierarchy, and malformed title controls. Commits a7fee34 and 4169322 tighten the native shell, add the mock's Session Matches, baseline, best Clips, and compact evidence hierarchy, fix native title controls, and align page names.

    The mocks also exposed a real data-contract omission. Storage retained Rating components, values, weights, and Receipt links, but the daemon discarded them before the Native Client. Commit f774bb7 carries that evidence through the versioned Unix-socket protocol and renders accessible component rows without fabricating unavailable player data. The red-to-green proof is a presenter contract plus the populated installed AT-SPI journey.

    Evidence after the changes:

    • populated installed MVP journey: PASS
    • fresh and populated native accessibility journeys: PASS
    • optimized fast suite: PASS in 72.17 seconds with four jobs
    • result directory: /mnt/shared/openfrag/target/openfrag-suite/runs/fast-20260715T222325Z-2210262

    The ticket remains open for final visual refinement and physical PC1 and PC2 qualification.

  27. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Final software candidate qualification passed.

    • Complete optimized suite: PASS
    • Wall time: 1,012.61s of 1,200s budget
    • Parallel jobs: 4; native package build cap: 2
    • All 13 required shards passed, including fresh and populated native AT-SPI journeys, staged installed-product behavior, deterministic release contracts, clean AUR lifecycle, and clean Fedora 43/44 lifecycles
    • Source archive SHA-256: 189b8ea23272a2a05aa7245eb9b141daae7611bbd04d3c6020c061aed7f3186e
    • Retained local evidence: target/openfrag-suite/runs/complete-20260715T223942Z-3121579
    • Native window controls use explicit high-contrast GTK controls and were verified only under the isolated test display; the live desktop was not opened or closed
    • Daemon SIGTERM now shuts down supervised capture cleanly; installed acceptance verifies no recorder process remains

    Publication remains blocked on the explicit PC1 KDE/AMD and PC2 GNOME/NVIDIA physical qualification gates. This Wayfinder ticket remains open.

  28. NtrpyDev commented on Jul 15, 2026

    @NtrpyDev
    OwnerAuthor

    Physical PC2 probing exposed and resolved a Doctor-state bug.

    The first implementation incorrectly treated a running desktop portal as an approved OpenFrag shortcut. The fast suite rejected that overclaim. The final model now distinguishes three states: unavailable, available but approval required, and approved. The regression proves that an available unapproved portal remains blocked with accurate remediation.

    Corrected candidate evidence:

    • Fast suite: PASS in 74.28s of 120s
    • Complete suite: PASS in 1,046.65s of 1,200s
    • All required shards passed
    • Source archive SHA-256: d00119eef5b4a7c2fc2fe54d5c03555e37c945e6fa9b5341348e544b00bae224
    • Retained result: target/openfrag-suite/runs/complete-20260715T230715Z-3789923

    PC2 partial physical evidence:

    • Exact tested client, daemon, and recorder installed without activation
    • CachyOS, kernel 7.1.3-2-cachyos, GNOME 50.3 Wayland, RTX 3070 Ti, NVIDIA 610.43.03
    • Doctor: capture ready; GSI blocked because CS2 is absent; Manual Flag blocked pending explicit portal approval
    • Daemon 1.0.0 start, private bootstrap, restart, stop all passed; no leaked daemon or recorder
    • No GUI was launched

    Full PC1/PC2 capture, portal approval, visual, playback, upgrade, and uninstall gates remain. Ticket stays open.

  29. NtrpyDev commented on Jul 16, 2026

    @NtrpyDev
    OwnerAuthor

    Final corrected candidate evidence:

    • Fast suite: PASS in 75.61s of 120s
    • Complete suite: PASS in 1,017.00s of 1,200s
    • All required shards passed; no failures or missing shards
    • AUR clean lifecycle: 308.59s using only a pacman download cache; source, build, test, install, and removal roots remained fresh
    • Fedora 43 clean lifecycle: 725.11s
    • Fedora 44 clean lifecycle: 683.28s
    • Source archive SHA-256: 1ecd655609a2bbbe3d199a86001cf1922cb6cd0fcaa883d8483bd9b2df9fdfc6
    • Retained result: target/openfrag-suite/runs/complete-20260716T002754Z-1541080

    Physical exact-artifact state:

    • PC1 and PC2 client: bdb9d886fd832bfbbe46949a8f3af214267bcb9c24ef4fb9534f54f6f6ba4d13
    • PC1 and PC2 daemon: 03e8adf2619c23dab0a35d1d55dda878ca0b501d52b0de891ae3f6d13f5eea7a
    • PC1 and PC2 recorder: 782c56f947697ce04afd5987dcd61a826cff5b921ce0128fc4b6a1f609297e44
    • PC1 Doctor now finds CS2 in the external /mnt/shared/SteamLibrary, capture dependencies are ready, daemon restart/bootstrap passed, service remains active and disabled
    • PC2 accurately reports no CS2, capture dependencies ready, daemon start/restart/stop passed, service remains inactive and disabled
    • Both accurately require explicit desktop shortcut approval
    • No live client window was launched or closed

    Remaining gates require human-visible consent or observation: GUI visual/accessibility on KDE and GNOME, shortcut approval, real AMD/NVIDIA capture, audio selection, FFprobe/playback observation, GSI consent/write and live CS2 freshness on PC1, plus physical upgrade/uninstall preservation. Publication remains blocked and this ticket stays open.

  30. NtrpyDev commented on Jul 16, 2026

    @NtrpyDev
    OwnerAuthor

    PC2 physical qualification progress found and fixed two release-blocking capture defects.

    Implemented:

    • 8a0c0e2 and cb35ca4 let replay capture and Manual Flag composition start before Steam identity or GSI credentials exist.
    • Nullable capture identity won the five-round comparison 4-1: truthful evidence, reconciliation safety, schema clarity, and future verified linking beat the lower migration cost of a fake sentinel identity.
    • 4f58fb1 corrects the bundled recorder contract to Matroska, H.264, default-output audio, and AAC; FFprobe now rejects saved media unless it has exactly one video and one audio stream.
    • The same commit assigns the user-visible Ctrl+Alt+F10 Manual Flag default and stores a private mode-0600 screen-capture portal restore token.

    Real GNOME/NVIDIA evidence on PC2:

    • The native AT-SPI qualifier passed all four pages, three window controls, Doctor fields, and exact native headings at 1280x800.
    • GNOME consent stored Ctrl+Alt+F10 for io.github.ntrpydev.openfrag.
    • A real Manual Flag produced an ingested Matroska artifact with H.264 video at 1920x1080 and AAC stereo at 48 kHz.
    • The artifact is 7.295 seconds and 161,599 bytes; OpenFrag moved it into the content-addressed artifact store and exposed it through the private Clip preview contract.
    • Capture portal restoration works across daemon restart without another screen-selection dialog.
    • Targeted capture, shortcut, daemon, no-identity, and strict owned-target Clippy checks pass.

    Remaining PC2 blocker:

    • On a subsequent daemon restart, GNOME 50.1 reports zero prior bindings, then gnome-control-center-global-shortcuts-provider crashes in gdk_surface_get_display while rebinding the already-approved shortcut with no parent window.
    • The daemon accurately reports Manual Flag unavailable after this provider crash. Capture itself remains ready.
    • This is reproducible through the canonical app-io.github.ntrpydev.openfrag service identity and is now part of the service-lifecycle release gate.

    Ticket remains claimed. No Wayfinder ticket is being closed.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    wayfinder:claimedA session is working this ticket nowwayfinder:taskTask ticket: manual work that unblocks the discussion

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions