diff --git a/openspec/changes/phase-3d-macos-native-mvp/.openspec.yaml b/openspec/changes/phase-3d-macos-native-mvp/.openspec.yaml new file mode 100644 index 0000000..d7bc011 --- /dev/null +++ b/openspec/changes/phase-3d-macos-native-mvp/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-08-10 diff --git a/openspec/changes/phase-3d-macos-native-mvp/design.md b/openspec/changes/phase-3d-macos-native-mvp/design.md new file mode 100644 index 0000000..175cf25 --- /dev/null +++ b/openspec/changes/phase-3d-macos-native-mvp/design.md @@ -0,0 +1,176 @@ +## Context + +Phase 3C freezes a gateway-only control/media baseline, but the Data Plane macOS target is +still a template and the shared Protocol has no requested display mode, absolute pointer, or +high-resolution scroll contract. The closed Server already owns broker persistence, +allocation policy, manifest disclosure, and provider-work. The GPLv3 Data Plane owns the +pure-Go gateway/Apollo translation plus the future Rust core and native client. The Protocol +repository remains the only wire authority. + +The implementation must preserve strict legacy JSON decoding, exact immutable Protocol pins, +no direct client-to-provider path, encoded-media relay without gateway decode/transcode, and +bounded release-all behavior. UI references are retained in the Planning repository as +review evidence only. + +## Goals / Non-Goals + +**Goals:** + +- Deliver one native Apple-Silicon SwiftUI/AppKit client for macOS 26 with macOS 15/14 + compatibility, built against a deterministic fake core before real streaming integration. +- Carry a client-requested display mode through Server allocation to provider work, while the + Server remains the only policy/clamp authority and both requested/effective values remain + visible to the client. +- Add provider-neutral absolute pointer and high-resolution scroll events without changing + the gateway-only route or coupling the public contract to Apollo packet shapes. +- Keep lifecycle, input release, local preview storage, secrets, media, and diagnostics + bounded and testable at their trust boundaries. +- Preserve a small, sized/versioned Rust C ABI and a single Swift unsafe bridge. + +**Non-Goals:** + +- Remote apps, manual PC/direct provider connections, live display renegotiation, + multi-monitor remote topology, HDR, microphone, file/folder redirection, image clipboard, + macros/timed sequences, Intel, provider-specific UI, or a plugin framework. +- Gateway decode, encode, transcode, render, cgo, native sidecar, insecure retry, or silent + capability fallback. +- Public release, signing credentials, deployment, promotion, or agent access to the owner's + Apollo host. Live Apollo/SudoMaker evidence remains owner E2E. + +## Decisions + +### 1. Repository and compatibility ownership + +- Protocol adds a reusable `DisplayMode` object and optional request/response fields while + retaining control wire version 1. Generated Go represents optional referenced objects as + pointers so `nil` is omitted; Rust/Swift use optionals. A legacy request receives the + legacy response shape, while a display-aware request requires `display.request.v1` and a + display-aware manifest contains the accepted value. +- Protocol registers `display.request.v1`, `input.absolute.v1`, and `input.scroll.v1` and + extends VGI1 only behind those negotiated features. Old gateways continue to reject + unknown kinds; clients therefore never send an unadvertised kind. +- Protobuf remains unchanged unless an observed consumer or verification gate proves that + the JSON control route actually depends on it. This avoids an unrelated second contract. +- A verified-unused immutable Phase 3D Protocol RC is frozen before Server/Data pins advance + together. No sibling `replace` or local wire fork is committed. + +### 2. Server-owned display decision + +- Broker sessions gain nullable requested/effective width, height, and FPS columns plus the + immutable policy-version identity needed to replay allocation/reconnect. Dedicated columns + keep the decision queryable and avoid overloading the existing bandwidth policy JSON. +- Request validation accepts width 320..16384, height 200..8640, and FPS 1..240. Requested + mode participates in every idempotency identity, including waiting sessions. +- Allocation selects the machine, resolves the immutable machine/pool/global policy, computes + the accepted mode, and atomically persists the allocation and accepted values. Reconnect + reuses the persisted result; it does not re-clamp against later policy. +- Clamp is proportional and deterministic: + `scale = min(policyWidth/requestWidth, policyHeight/requestHeight, 1)`; + `effectiveWidth = floorToEven(requestWidth * scale)`; + `effectiveHeight = floorToEven(requestHeight * scale)`; + `effectiveFPS = min(requestedFPS, policyFPS)`. +- Provider work uses the persisted effective dimensions/FPS and the selected immutable + policy's codec/bitrate/audio. Legacy sessions retain today's exact policy dimensions. + +### 3. Provider-neutral input + +- VGI1 kind `0x06` has exactly eight body bytes: big-endian unsigned `x`, `y`, viewport + width, and viewport height. Width/height must be nonzero; x < width and y < height. +- VGI1 kind `0x07` has exactly four body bytes: big-endian signed 16-bit vertical and + horizontal high-resolution scroll deltas. +- Protocol docs, fixtures, Go/Rust/Swift classifiers, Data encode/decode, fuzzing, transport, + and Apollo translation share the same vectors. Apollo packet details remain private to the + adapter and must be justified by pinned reference source before implementation. +- Absolute/scroll events do not enter the pressed-state ledger. Keys, buttons, and controllers + continue to release through the existing ledger on every authority/lifecycle exit. + +### 4. Native workspace, display discovery, and input ownership + +- The client uses `NavigationSplitView`, native controls/materials, and standard macOS 26 + Liquid Glass APIs conditionally. macOS 15/14 retain identical hierarchy with native + materials; no custom glass framework is introduced. +- Desktop cards remain `328 x 205 pt`; an adaptive grid only changes column count. Card + actions remain accessible without hover, and no direct-connect button or endpoint entry is + added. +- Automatic mode reads physical pixels for the screen where the session window opens and + uses its maximum FPS. A defensible notch-safe built-in mode is preferred; otherwise Full + Native is disclosed. A display move offers a new-session reconnect and never mutates the + active stream. +- The renderer aspect-fits. Absolute coordinates originate only inside the rendered viewport; + letterbox bars produce no pointer event. +- Native `NSWindow` fullscreen preserves top-edge system UI in absolute mode. Relative mode + hides/captures the cursor. Reserved mode-toggle and emergency-release chords are handled + before mapping and never cross the core boundary. Mode switches release pressed input and + clamp cursor restoration to the rendered viewport. + +### 5. State, Rust core, and platform boundaries + +- Swift actors own authentication, resources, brokerage, streaming, and settings; immutable + projections reach `MainActor` views. One bridge owns every C pointer/callback/lifetime. +- The Rust core owns tunnel negotiation, authenticated framing, packet reconstruction, + encoded media delivery, input encoding, statistics, cancellation, and structured errors. + Apple frameworks own decode/render/audio/device/input capture and product state. +- The C ABI uses fixed-width values, explicit lengths, opaque handles, sized/versioned tables, + a declared callback queue, caught panics, cancellation, and late-callback/destroy rules. +- Fakes cover every external boundary before real core/media integration. No speculative + adapter/factory/plugin layer is added beyond interfaces already needed for deterministic + tests. + +### 6. Preview and diagnostic privacy + +- Stable desktop previews are downscaled to `656 x 410`, stored in the sandbox cache as mode + `0600`, and written only after an active session ends cleanly. Failed launch retains the + prior preview. Pool cards use generic art. +- Logout or entitlement loss clears affected previews. Hide/Clear settings are explicit. + Backup, telemetry, OSLog, crashes, support bundles, and default diagnostics exclude preview + and raw media bytes. +- Diagnostics are allowlisted structured state/correlation/performance summaries; tokens, + grants, provider endpoints, media, input, clipboard, and Windows secrets never enter them. + +### 7. Delivery and evidence + +- Land capability-sized commits in order: Planning/OpenSpec, Protocol, Server, gateway input, + fake-core native shell, Rust/core integration, platform media, then full qualification. +- Every nontrivial boundary starts with a focused failing test/vector and ends with the + narrow affected gate; one complete clean-source gate runs only after freeze. +- macOS 26/15/14 native behavior, accessibility, lifecycle, privacy, and platform media require + real target evidence. The owner later runs the only live Apollo/SudoMaker acceptance. + +## Risks / Trade-offs + +- [Strict legacy decoders reject additive response fields] -> Emit display fields only for a + negotiated display-aware request; retain legacy shapes and cross-version fixtures. +- [Requested dimensions exceed policy or change aspect] -> Apply one Server-owned + proportional/even clamp, persist it atomically, and disclose both values. +- [Absolute coordinates mismatch presentation] -> Normalize against the rendered viewport, + reject letterbox coordinates, and test edge/scale/display cases. +- [Relative capture strands local input] -> Keep an unremappable emergency release, release + before every mode/authority transition, and test focus/sleep/cancel/revocation paths. +- [Preview bytes leak user media] -> Minimize one local file, mode `0600`, clean-session-only + writes, lifecycle clearing, and explicit exclusion/secret-canary tests. +- [Apollo input semantics are guessed] -> Stop until the pinned provider source establishes + the exact packet; do not encode provider assumptions into VGI. +- [macOS API rendering differs by release/accessibility setting] -> Test deterministic + geometry and state automatically; use bounded manual material review without snapshots of + OS-owned pixels as the sole gate. +- [The full client scope is large] -> Keep serial capability commits and stop at the first + failed contract/environment gate rather than introducing fallbacks or partial claims. + +## Migration Plan + +1. Freeze Planning/OpenSpec and visual references. +2. Implement/freeze an immutable Protocol RC with legacy and new feature fixtures. +3. Apply the forward-only Server migration and update Server/Data Protocol pins together. +4. Deploy no schema or runtime automatically; validate clean install/upgrade/legacy rows and + gateway fixtures locally/private CI first. +5. Build the native shell against fakes, then integrate the frozen core/gateway surfaces. +6. Roll back application binaries only while schema compatibility permits; nullable additive + fields preserve legacy row behavior. Never down-migrate or rewrite applied migrations. +7. Keep signing, publication, deployment, promotion, and live owner E2E under separate + authorization. + +## Open Questions + +None at proposal time. Exact Apollo absolute-pointer/scroll packet vectors must be established +from the approved pinned source before the adapter step; absence of that evidence is an +implementation hard stop, not a design choice to guess. diff --git a/openspec/changes/phase-3d-macos-native-mvp/proposal.md b/openspec/changes/phase-3d-macos-native-mvp/proposal.md new file mode 100644 index 0000000..dd43320 --- /dev/null +++ b/openspec/changes/phase-3d-macos-native-mvp/proposal.md @@ -0,0 +1,65 @@ +## Why + +Phase 3C has frozen the gateway and Connection Server image-engineering baseline, so the first +native VerseVDI endpoint can now be built against an immutable gateway-only authority model. +Phase 3D must add the user-facing macOS workspace, exact display negotiation, safe native +input, and streaming core without exposing Apollo/provider details or weakening the existing +control and transport boundaries. + +## What Changes + +- Build the Apple-Silicon SwiftUI/AppKit client and platform-neutral Rust Streaming Core + behind one sized/versioned C ABI (`P3D-001`–`P3D-031`). +- Implement the reviewed native workspace, fixed preview cards, Favorites, search/sort, + settings, accessibility, and privacy-bounded desktop previews (`P3D-032`, `P3D-037`). +- Add feature-gated requested/effective display modes, Server-owned policy clamping, + client display detection/disclosure, and explicit reconnect-on-display-change behavior + (`P3D-033`–`P3D-034`). +- Add provider-neutral absolute pointer and high-resolution scroll input while preserving + relative input, release-all, reserved local escape chords, letterbox exclusion, and scoped + keyboard mapping (`P3D-035`–`P3D-036`). +- Keep authentication, manifests, media, input, and clipboard on the authenticated + gateway-only route. The client receives no provider endpoint, provider credential, or + Windows credential outside normal encrypted input. +- Defer remote apps, manual PC/direct-provider connections, live display renegotiation, + multi-monitor remote topology, HDR, microphone, file/folder redirection, image clipboard, + macros, Intel, public release, and provider-specific client UI. + +## Capabilities + +### New Capabilities + +- `macos-native-foundation`: Platform baseline, Swift/Rust/C ABI ownership, authentication, + resource/broker authority, gateway-only manifest validation, and fake-core-first delivery. +- `macos-media-presentation`: Registered media dispatch, hardware video presentation, audio, + bounded queues, and observable quality without media persistence. +- `macos-input-control`: Provider-neutral keyboard, pointer, scroll, controller, text + clipboard, mappings, reserved local chords, and release-all behavior. +- `macos-lifecycle-quality`: Interruption, reconnect, accessibility, privacy, diagnostics, + packaging, rollback, uninstall, and candidate qualification behavior. +- `macos-workspace`: Screenshot-backed workspace/card/settings interactions, Favorites, + search/sort, and privacy-bounded previews. +- `session-display-mode`: Feature-gated requested/effective display mode, Server policy + clamping, client detection/disclosure, and owner Apollo IDD acceptance. + +### Modified Capabilities + +None. Existing Phase 3C gateway capabilities remain unchanged; this change consumes and +extends their separately owned Protocol surfaces without redefining their requirements. + +## Impact + +- **Protocol repository:** additive strict JSON display objects, feature identifiers, VGI1 + absolute/scroll grammar, cross-language bindings, fixtures, and compatibility tests. +- **Connection Server:** additive broker-session migration/query fields, request identity, + allocation transaction/clamp, manifest disclosure, and provider-work projection. +- **Data Plane:** Protocol pin update, Go gateway input validation/Apollo translation, Rust + core/C ABI/XCFramework, SwiftUI/AppKit client, tests, documentation, and private build + configuration. +- **Provenance and license boundary:** Apollo, Moonlight, Microsoft Windows App, and Omnissa + material remains reference evidence only. No proprietary Server or Planning content is + copied into the GPLv3 Data Plane. +- **Hard stops:** unknown provider packet semantics, incompatible legacy response behavior, + direct-provider routing, secret/media/input persistence, unsupported platform safety, or + a failed deterministic gate blocks the affected capability. Live Apollo/macOS/firewall + interoperability remains `deferred-owner-e2e` until the owner runs the frozen candidate. diff --git a/openspec/changes/phase-3d-macos-native-mvp/specs/macos-input-control/spec.md b/openspec/changes/phase-3d-macos-native-mvp/specs/macos-input-control/spec.md new file mode 100644 index 0000000..09362c3 --- /dev/null +++ b/openspec/changes/phase-3d-macos-native-mvp/specs/macos-input-control/spec.md @@ -0,0 +1,55 @@ +## ADDED Requirements + +### Requirement: P3D-016 complete MVP input +Input SHALL support keyboard, absolute and relative mouse, high-resolution scroll, and one standard controller with a pressed-state ledger and release-all on every authority/interruption boundary. + +#### Scenario: Authority loss with pressed input +- **WHEN** focus, network, session authority, sleep, cancellation, or termination changes while input is pressed +- **THEN** release-all is sent/recorded once and no pressed state remains + +### Requirement: P3D-017 Windows password is ordinary input +Windows lock-screen credentials SHALL travel only as normal encrypted input events and SHALL never be collected, stored, autofilled, or separately injected. + +#### Scenario: Lock-screen typing +- **WHEN** the user types into a remote Windows credential field +- **THEN** the client handles the keys like any remote input and retains no credential value + +### Requirement: P3D-028 controller layouts +Controller input SHALL support user-selectable Xbox, PlayStation, and Nintendo/Switch-style normalized layouts with explicit unsupported-capability behavior. + +#### Scenario: Layout selection +- **WHEN** the user changes controller layout +- **THEN** subsequent normalized events use the selected mapping and unsupported controls are surfaced explicitly + +### Requirement: P3D-029 bounded text clipboard +The client SHALL expose clipboard enablement/direction and visible failure behavior, permit only bounded text, and reject files, file URLs, folders, binary data, and oversized content. + +#### Scenario: File clipboard attempt +- **WHEN** a local or remote clipboard advertises a file or file URL +- **THEN** transfer is rejected without reading or persisting file content + +### Requirement: P3D-035 native pointer modes and escape safety +The client SHALL aspect-fit video, emit absolute pointer events only inside the rendered viewport, default to macOS-owned absolute cursor behavior, and provide session-only relative capture with reserved local control chords. + +#### Scenario: Letterbox pointer +- **WHEN** the absolute pointer is in a letterbox bar +- **THEN** no remote absolute-pointer event is emitted + +#### Scenario: Toggle relative mode +- **WHEN** `Control-Option-Shift-M` is pressed during a session +- **THEN** pressed input is released, the chord is not forwarded, capture switches, and the saved/restored cursor point is clamped inside the rendered viewport + +#### Scenario: Emergency release +- **WHEN** `Control-Option-Shift-Escape` is pressed in any input mode +- **THEN** pressed input is released, absolute/local cursor ownership and controls return, and the chord is not forwarded + +### Requirement: P3D-036 scoped keyboard mappings +Keyboard mapping SHALL support physical/logical keys and simultaneous chords with Mac-to-Windows and language defaults, deterministic global/resource precedence and modifier order, conflicts, enablement, add/remove, and Restore Defaults; macros and reserved-chord remapping are prohibited. + +#### Scenario: Conflicting resource mapping +- **WHEN** an enabled resource mapping conflicts with a global mapping +- **THEN** deterministic resource precedence applies and the conflict is visible/editable + +#### Scenario: Reserved mapping attempt +- **WHEN** a mapping targets either local reserved escape chord +- **THEN** the mapping is rejected and the local chord remains intercepted diff --git a/openspec/changes/phase-3d-macos-native-mvp/specs/macos-lifecycle-quality/spec.md b/openspec/changes/phase-3d-macos-native-mvp/specs/macos-lifecycle-quality/spec.md new file mode 100644 index 0000000..c2cdf55 --- /dev/null +++ b/openspec/changes/phase-3d-macos-native-mvp/specs/macos-lifecycle-quality/spec.md @@ -0,0 +1,43 @@ +## ADDED Requirements + +### Requirement: P3D-018 explicit recovery states +The client SHALL distinguish network interruption, reconnectable session, draining, provider cleanup failure, assignment unavailable, capacity queue, entitlement loss, and terminal end with safe actions. + +#### Scenario: Reconnectable interruption +- **WHEN** the control authority reports a reconnectable session after network loss +- **THEN** the UI offers only a fresh authorized reconnect path and does not replay the old grant + +### Requirement: P3D-019 deterministic lifecycle changes +Sleep/wake, foreground/background, display/audio/controller/network changes, server/gateway restart, and core cancellation SHALL have deterministic tested behavior. + +#### Scenario: Sleep during active stream +- **WHEN** the Mac sleeps during an active stream +- **THEN** input is released, owned tasks/resources stop, and wake reconciles authority before reconnect + +### Requirement: P3D-021 accessible critical paths +Authentication, resources, brokerage, session, errors, and settings SHALL support VoiceOver, keyboard navigation, visible focus, contrast, reduced motion, dynamic type where applicable, and non-color status cues. + +#### Scenario: Keyboard-only connection +- **WHEN** a user navigates the workspace without a pointer +- **THEN** every critical action is reachable with visible focus and meaningful accessibility labels + +### Requirement: P3D-022 redacted diagnostics +Errors, telemetry, logs, crashes, and support artifacts SHALL exclude credentials, grants, provider endpoints, raw media/input, clipboard content, and Windows secrets while retaining bounded correlation identifiers. + +#### Scenario: Synthetic secret canary +- **WHEN** all diagnostics and support outputs are generated after injecting secret canaries +- **THEN** the scanner finds no secret, media, input, clipboard, or provider-endpoint value + +### Requirement: P3D-023 release platform safety +Any distributed release SHALL be signed, notarized, hardened-runtime compatible, signature-verified for update, and rollback-tested. + +#### Scenario: Tampered update +- **WHEN** update metadata or the application artifact is modified after signing +- **THEN** update verification fails before installation or execution + +### Requirement: P3D-024 explicit uninstall policy +Uninstall SHALL remove documented local application state according to explicit Keychain/cache policy and SHALL NOT silently delete server-side device authority. + +#### Scenario: Offline uninstall +- **WHEN** the app is removed while the Server is unreachable +- **THEN** local state follows policy and server-side revocation is not falsely claimed diff --git a/openspec/changes/phase-3d-macos-native-mvp/specs/macos-media-presentation/spec.md b/openspec/changes/phase-3d-macos-native-mvp/specs/macos-media-presentation/spec.md new file mode 100644 index 0000000..f23781f --- /dev/null +++ b/openspec/changes/phase-3d-macos-native-mvp/specs/macos-media-presentation/spec.md @@ -0,0 +1,15 @@ +## ADDED Requirements + +### Requirement: P3D-014 hardware video presentation +Video SHALL use negotiated registered media identifiers, VideoToolbox hardware decode, and Metal presentation without unnecessary copies or persistence. + +#### Scenario: Unsupported hardware decode +- **WHEN** the negotiated profile cannot be decoded by supported VideoToolbox hardware +- **THEN** the session fails explicitly without software fallback, remote transcode, or pixel logging + +### Requirement: P3D-015 bounded audio playback +Audio SHALL use a proven CoreAudio abstraction with bounded buffering, negotiated channel layout, drift handling, and measurable A/V synchronization. + +#### Scenario: Audio device replacement +- **WHEN** the default audio device changes or disappears during an active session +- **THEN** bounded playback state is recreated or fails visibly without persisting streamed audio diff --git a/openspec/changes/phase-3d-macos-native-mvp/specs/macos-native-foundation/spec.md b/openspec/changes/phase-3d-macos-native-mvp/specs/macos-native-foundation/spec.md new file mode 100644 index 0000000..00d3f16 --- /dev/null +++ b/openspec/changes/phase-3d-macos-native-mvp/specs/macos-native-foundation/spec.md @@ -0,0 +1,134 @@ +## ADDED Requirements + +### Requirement: P3D-001 Apple Silicon platform baseline +The client SHALL target Apple Silicon with macOS 26 primary, macOS 15/14 supported, and a non-release macOS 27 compatibility lane when its SDK/runtime exists. + +#### Scenario: Supported platform matrix +- **WHEN** the frozen candidate is qualified +- **THEN** exact native evidence exists for macOS 26, 15, and 14, while Intel is not claimed + +### Requirement: P3D-002 isolated SwiftUI state +The shell SHALL use SwiftUI with structured concurrency and isolated authentication, resource, broker, stream, and settings state. + +#### Scenario: Concurrent state update +- **WHEN** control and stream events arrive concurrently +- **THEN** owning actors serialize mutation and views receive immutable main-actor projections + +### Requirement: P3D-003 no former C++ core +The implementation SHALL NOT restore the superseded C++ core packaging design. + +#### Scenario: Core dependency audit +- **WHEN** the native client dependency graph is inspected +- **THEN** no VerseVDI C++ streaming core or wrapper is linked + +### Requirement: P3D-004 stable C ABI +The C ABI SHALL use sized versioned tables and define pointer ownership, lifetime, callback thread, cancellation, error, reentrancy, and destroy behavior. + +#### Scenario: Older caller table +- **WHEN** a caller supplies a supported older structure size +- **THEN** the core reads only available fields and returns a deterministic compatibility result + +### Requirement: P3D-005 Rust core +The platform-neutral streaming core SHALL be Rust, not the superseded C++ implementation. + +#### Scenario: Core artifact inspection +- **WHEN** the XCFramework artifact is inventoried +- **THEN** its exported VerseVDI surface is the reviewed C ABI backed by the pinned Rust core + +### Requirement: P3D-006 Swift platform ownership +Swift SHALL own HTTPS/WebSocket control, Keychain, navigation, accessibility, Apple decode/render/audio/input objects, signing, and update integration. + +#### Scenario: Platform operation routing +- **WHEN** a platform credential, window, decoder, audio device, or input operation occurs +- **THEN** it is owned by Swift/AppKit/Apple frameworks and not by the Rust core + +### Requirement: P3D-007 narrow credential storage +Refresh credentials and device private keys SHALL use the narrowest practical Keychain accessibility; access tokens and gateway grants SHALL remain memory-only. + +#### Scenario: Relaunch storage audit +- **WHEN** the app terminates and relaunches +- **THEN** no access token or gateway grant is recoverable from persistent client storage + +### Requirement: P3D-008 authenticated device enrollment +First use SHALL authenticate before device-key generation/registration and SHALL complete server challenge proof before launch authority. + +#### Scenario: Unauthenticated enrollment attempt +- **WHEN** device enrollment is requested without a current authenticated user session +- **THEN** no key is registered and no launch authority is issued + +### Requirement: P3D-009 no active LDAP mode +The Phase 3D client SHALL NOT expose an active LDAP login mode before Phase 6. + +#### Scenario: Login surface inspection +- **WHEN** the Phase 3D login UI and control requests are exercised +- **THEN** only local login is offered and no LDAP request is made + +### Requirement: P3D-010 authorized resources only +The UI SHALL show only assigned desktops and entitled pools, including unavailable assignment, `awaiting_desktop`, and capacity queue state. + +#### Scenario: Cross-subject cached resource +- **WHEN** stale local data references another subject's resource +- **THEN** reconciliation removes or withholds it and no action is available + +### Requirement: P3D-011 idempotent broker reconciliation +The client SHALL request/cancel idempotently, apply events by sequence, resync gaps through REST, and reconcile current authority after relaunch. + +#### Scenario: Event sequence gap +- **WHEN** the next event sequence is not contiguous +- **THEN** incremental application stops and REST reconciliation completes before further action + +### Requirement: P3D-012 gateway-only manifest +The client SHALL accept only a gateway-only manifest matching authenticated server, device, session, audience, expiry, and supported tunnel range. + +#### Scenario: Wrong manifest context +- **WHEN** any manifest binding or required tunnel capability is wrong +- **THEN** the core rejects it before opening a media/input session + +### Requirement: P3D-013 forbidden provider details +The client SHALL reject and safely report any manifest containing a provider/VM endpoint or credential-like field. + +#### Scenario: Provider field injection +- **WHEN** a manifest contains a provider address or credential-shaped field +- **THEN** launch fails closed and diagnostics contain no injected value + +### Requirement: P3D-020 callback isolation +Core callbacks SHALL transfer bounded immutable values to their owning actor and SHALL NOT mutate SwiftUI state directly. + +#### Scenario: Callback storm +- **WHEN** callbacks arrive rapidly from a non-main core thread +- **THEN** bounded bridge delivery preserves order/ownership without direct view-state mutation + +### Requirement: P3D-025 fake-core-first candidate +The client SHALL pass fake-core UI behavior before real-core fixture integration and SHALL freeze a platform-qualified candidate before owner live Apollo acceptance. + +#### Scenario: Live provider unavailable +- **WHEN** deterministic implementation gates pass without owner Apollo access +- **THEN** the candidate can reach engineering review with live interoperability recorded `deferred-owner-e2e` + +### Requirement: P3D-026 XCFramework packaging +The Rust core SHALL be packaged as a static library within an XCFramework behind one stable C ABI and thin Swift wrapper. + +#### Scenario: Unsafe-call audit +- **WHEN** Swift source is inspected +- **THEN** only the designated bridge owns direct C ABI pointer and callback translation + +### Requirement: P3D-027 core responsibility boundary +The Rust core SHALL own tunnel negotiation, cryptography, reconstruction, encoded delivery, input encoding, policy updates, statistics, and core errors without owning product authorization or Apple UI/media devices. + +#### Scenario: Responsibility audit +- **WHEN** the core dependency/module graph is inspected +- **THEN** no SwiftUI, Apple decoder/renderer/audio device, or product-auth implementation is linked into it + +### Requirement: P3D-030 registered media dispatch +Core and client SHALL dispatch framing, reconstruction, decode, and render from registered negotiated identifiers and SHALL fail stably on unsupported/stale combinations. + +#### Scenario: Unsupported profile combination +- **WHEN** framing and media identifiers have no supported explicit intersection +- **THEN** the session fails before decoder allocation without guessing, fallback, or transcode + +### Requirement: P3D-031 local authentication lifecycle +The MVP SHALL support local login, rotating refresh, logout, device-revocation response, and generic anti-enumeration errors. + +#### Scenario: Refresh-family revocation +- **WHEN** the Server reports refresh reuse or device revocation +- **THEN** local authority and active input/stream state are cleared and generic reauthentication is shown diff --git a/openspec/changes/phase-3d-macos-native-mvp/specs/macos-workspace/spec.md b/openspec/changes/phase-3d-macos-native-mvp/specs/macos-workspace/spec.md new file mode 100644 index 0000000..3037c91 --- /dev/null +++ b/openspec/changes/phase-3d-macos-native-mvp/specs/macos-workspace/spec.md @@ -0,0 +1,23 @@ +## ADDED Requirements + +### Requirement: P3D-032 native desktop workspace +The app SHALL expose Favorites, Desktops, Pools, and Settings in a native split workspace without Apps, Add PC, manual endpoint, or direct-provider surfaces. Desktop cards SHALL remain `328 x 205 pt`, use full-bleed previews and subtle readable metadata treatment, and adapt only the grid column count. + +#### Scenario: Narrow and wide resize +- **WHEN** the workspace moves between narrow, medium, and wide widths +- **THEN** card geometry remains fixed, the column count changes, and text/actions do not overflow + +#### Scenario: Accessible card actions +- **WHEN** a card receives hover or keyboard focus +- **THEN** Favorite and settings controls become available without adding a connect button; double-click or Return connects + +### Requirement: P3D-037 private favorites and previews +Favorites, search, sort, filters, diagnostics, and previews SHALL reveal only current authorized resources. A stable desktop MAY retain one `656 x 410` mode-`0600` preview only after an active session ends cleanly; pool art is generic and preview bytes are excluded from backup/telemetry/log/crash/support data. + +#### Scenario: Failed launch and clean end +- **WHEN** a launch fails and a later active session ends cleanly +- **THEN** the failed launch preserves the old preview and only the clean end atomically replaces it + +#### Scenario: Entitlement loss +- **WHEN** logout or reconciliation removes a desktop entitlement +- **THEN** its preview is cleared and cannot appear through Favorites, search, cache, or diagnostics diff --git a/openspec/changes/phase-3d-macos-native-mvp/specs/session-display-mode/spec.md b/openspec/changes/phase-3d-macos-native-mvp/specs/session-display-mode/spec.md new file mode 100644 index 0000000..2d10e58 --- /dev/null +++ b/openspec/changes/phase-3d-macos-native-mvp/specs/session-display-mode/spec.md @@ -0,0 +1,27 @@ +## ADDED Requirements + +### Requirement: P3D-033 requested and effective display mode +The client SHALL offer global and desktop/pool overrides for Automatic, detected/common preset, Custom, and Full Native width/height/FPS. A display-aware request SHALL be feature-gated; the Server SHALL validate, include it in idempotency identity, resolve immutable policy, proportionally clamp to even dimensions and maximum FPS, persist requested/effective values atomically, and disclose both without provider details. + +#### Scenario: Oversized custom request +- **WHEN** a requested mode exceeds either policy dimension or FPS +- **THEN** the Server applies one proportional scale, floors both dimensions to even pixels, caps FPS, persists the result, and returns the requested and accepted modes + +#### Scenario: Legacy request +- **WHEN** a client omits the feature and requested display object +- **THEN** the Server preserves the legacy response shape and provider work uses the existing exact policy mode + +#### Scenario: Same idempotency key with different mode +- **WHEN** two requests reuse an idempotency key but contain different requested display modes +- **THEN** the Server rejects the mismatch rather than returning or mutating the earlier session + +### Requirement: P3D-034 native detection and reconnect semantics +Automatic mode SHALL derive physical pixels and maximum FPS from the screen where the session window opens, prefer a defensible notch-safe built-in mode, otherwise disclose Full Native, and SHALL NOT mutate an active mode after a display move. Reconnect to match the new display SHALL end the prior session and use a new request/idempotency key. Owner E2E SHALL prove accepted values on Apollo/SudoMaker IDD through the gateway-only route. + +#### Scenario: Move active session to another display +- **WHEN** an Automatic session window moves to a display with different native capability +- **THEN** the active mode remains unchanged and the user may explicitly reconnect with a newly detected request + +#### Scenario: Exact owner virtual-display acceptance +- **WHEN** the owner runs the frozen client, Server, gateway, and Apollo candidate +- **THEN** retained evidence binds requested and accepted width/height/FPS to the actual SudoMaker virtual display without a direct client-provider route diff --git a/openspec/changes/phase-3d-macos-native-mvp/tasks.md b/openspec/changes/phase-3d-macos-native-mvp/tasks.md new file mode 100644 index 0000000..ac56cee --- /dev/null +++ b/openspec/changes/phase-3d-macos-native-mvp/tasks.md @@ -0,0 +1,69 @@ +## 1. Contract Freeze + +- [ ] 1.1 Add Protocol `DisplayMode`, negotiated display fields/features, VGI1 absolute/scroll grammar, strict valid/invalid cross-language fixtures, and optional-field omission regressions +- [ ] 1.2 Regenerate Go/Rust/Swift outputs twice, pass Protocol `make verify`, freeze a verified-unused immutable Phase 3D RC, and record its fixture/generated hashes +- [ ] 1.3 Update Server and Data Plane to the exact Protocol RC without a filesystem replacement and prove clean-cache module resolution before consumer implementation + +## 2. Server Display Authority + +- [ ] 2.1 Add the forward-only nullable requested/effective display and policy-version migration plus clean-install/upgrade/schema/grant tests +- [ ] 2.2 Add strict request validation and requested-mode idempotency identity, including waiting-session mismatch regressions +- [ ] 2.3 Implement one proportional even-pixel/FPS clamp at allocation and atomically persist the immutable requested/effective decision +- [ ] 2.4 Disclose display-aware broker/manifest values only to negotiated clients, preserve legacy response shapes, and reuse the persisted mode on reconnect +- [ ] 2.5 Project persisted effective width/height/FPS through existing provider work with selected immutable codec/bitrate/audio and pass focused repository/E2E tests + +## 3. Gateway Input Translation + +- [ ] 3.1 Add red VGI absolute/scroll encode/decode/bounds/fuzz/transport tests and prove unadvertised kinds fail before provider translation +- [ ] 3.2 Establish exact Apollo absolute-pointer and scroll vectors from the approved pinned source; hard-stop without that evidence +- [ ] 3.3 Implement the smallest provider-neutral VGI validation and Apollo adapter translation without adding pressed-state or direct-provider surfaces +- [ ] 3.4 Pass focused input vectors/fuzz/transport/fake-provider tests, then one affected Data Plane `make verify` + +## 4. Rust Core and Stable ABI + +- [ ] 4.1 Pin Rust toolchain/dependencies and add minimal core modules with bounded fake transport, Protocol fixtures, cancellation, errors, queues, and redaction +- [ ] 4.2 Specify and test the sized/versioned C ABI ownership, callback thread, panic, reentrancy, cancellation, late-callback, and destroy contracts before implementation +- [ ] 4.3 Implement gateway-only manifest/QUIC/framing/media/input behavior against fixtures with no provider endpoint, decoder, renderer, transcode, or product-auth path +- [ ] 4.4 Package deterministic Apple-Silicon static XCFramework output and one Swift bridge; pass Cargo format/Clippy/tests plus applicable fuzz/Miri/sanitizer and ABI stress gates + +## 5. Native Foundation Against Fakes + +- [ ] 5.1 Reconcile the Xcode project to macOS 14 deployment, Xcode 26.6/Swift 6.3 Swift-6 mode, Apple Silicon, and conditional macOS 26 APIs +- [ ] 5.2 Implement isolated auth/resource/broker/stream/settings owners and deterministic control/event/core/credential/platform fakes with unit tests before views +- [ ] 5.3 Implement local login, device proof, serialized rotating refresh, Keychain/memory-only policy, logout/revocation, and anti-enumeration tests +- [ ] 5.4 Implement resource/broker/event-gap/relaunch/idempotency reconciliation and cross-subject fixture negatives + +## 6. Workspace and Display UX + +- [ ] 6.1 Build the screenshot-backed Favorites/Desktops/Pools/Settings shell with fixed `328 x 205 pt` cards, adaptive columns, safe truncation, native focus/VoiceOver, and no Apps/Add-PC/direct endpoint surfaces +- [ ] 6.2 Add global and resource Automatic/preset/Custom/Full Native settings, physical-pixel/FPS detection, notch-safe disclosure, and requested/accepted projections with deterministic display fakes +- [ ] 6.3 Add aspect-fit viewport math, letterbox pointer exclusion, display-move reconnect offer, and new-session/idempotency behavior tests +- [ ] 6.4 Pass geometry/hierarchy/visibility/responsive/accessibility automation and bounded macOS 26/15/14 native-material review + +## 7. Native Input and Preview Privacy + +- [ ] 7.1 Implement absolute and relative pointer capture with native fullscreen, top-edge local controls, pressed-state release, bounded cursor restore, HUD, and unremappable local toggle/emergency chords +- [ ] 7.2 Implement physical/logical and language-aware global/resource keyboard mappings, deterministic conflicts/precedence/modifier order, add/remove/enable/restore, and no-macro/reserved-chord negatives +- [ ] 7.3 Implement normalized controller layouts and bounded text-only clipboard with file/binary/oversize/loop/permission negatives +- [ ] 7.4 Implement atomic clean-session-only mode-`0600` desktop previews, generic pool art, hide/clear/logout/entitlement behavior, and backup/log/crash/support exclusion tests + +## 8. Platform Media and Lifecycle + +- [ ] 8.1 Implement registered VideoToolbox decode and Metal aspect-fit presentation with bounded latency-first queues, configuration/IDR/discontinuity/device-loss tests, and no pixel persistence +- [ ] 8.2 Implement bounded CoreAudio playback/synchronization with device/format/sleep/cancel tests and retained timing summaries without audio persistence +- [ ] 8.3 Implement deterministic sleep/wake, foreground/background, display/audio/controller/network change, server/gateway restart, cancellation, reconnect, and release-all behavior +- [ ] 8.4 Complete accessible errors/actions, allowlisted diagnostics, privacy manifest, secret-canary support-bundle tests, and 100-cycle ownership/leak stress + +## 9. Real-Core Integration + +- [ ] 9.1 Replace fake-core session transport only at the existing client seam and pass the same state/UI/lifecycle suites unchanged +- [ ] 9.2 Run shared Protocol manifest/framing/media/input fixtures through Go, Rust, Swift, gateway transport, and fake Apollo without payload or provider-detail leakage +- [ ] 9.3 Pass fixture-backed gateway-only video/audio/input/reconnect/cancel/revocation integration and reject every direct-route/provider-field/downgrade case + +## 10. Freeze and Qualification + +- [ ] 10.1 Freeze exact source, Protocol/core artifacts, locks, settings, Xcode/toolchain, fake/provider fixtures, and environment; any change invalidates only its affected evidence plus the final gate +- [ ] 10.2 Run the single final clean-source Protocol `make verify`, Server generated-SQL/OpenSpec/full serial Go suite, Data `make verify`/race/resource gates, Cargo gates, and Swift/XCTest/XCUITest/accessibility suites +- [ ] 10.3 Qualify macOS 26/15/14 Apple Silicon platform behavior, lifecycle, performance/energy, privacy, uninstall/rollback preparation, and clean checkout; keep signing/publication/deployment/promotion separately authorized +- [ ] 10.4 Retain versions, hashes, logs, inventories, redacted metrics, failures, and exact requirement mapping; archive this change only when canonical specs match +- [ ] 10.5 Package but do not execute the owner E2E that binds Automatic/Custom requested and accepted width/height/FPS to the Apollo/SudoMaker virtual display through the gateway-only route; retain it as `deferred-owner-e2e`