Skip to content

feat(trios-macos): Internet calls through the TRI-NET call stack - #2054

Draft
dmitrii-f-t27 wants to merge 3 commits into
mainfrom
feat/trios-internet-calls
Draft

dmitrii-f-t27 wants to merge 3 commits into
mainfrom
feat/trios-internet-calls

Conversation

@dmitrii-f-t27

@dmitrii-f-t27 dmitrii-f-t27 commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Status after the owner's correction (2026-10-21): calls must work locally inside TriOS with no external servers. This PR's server-address flow over TRI-NET's call API and LiveKit is therefore not the main product path and is kept as a draft. Parts that carry over to the local path: the attempt and server isolation, exactly-once media teardown, the app-level incoming panel, the account binding rules and the clade-build seam. The local, server-free path will follow in its own spec and PR.

Closes #2053

Spec first: apps/trios-macos/.trinity/specs/internet-calls.md. Owner decision 2026-10-21: Internet calls between TriOS users on Mac and phone; this PR is the Mac side. It reuses TRI-NET's identity, directory, signalling and LiveKit media instead of a second call stack.

What it adds

  • Calls segment in the Mesh tab (incumbent matte-black style, grok* tokens, labelled controls): call server field, account binding (claim a nickname, or join the phone's account with a link code), exact-nickname lookup over the Internet route only, a call button on a resolved contact only, incoming banner plus an app-level floating panel with Answer/Decline, Calling/Ringing/Connecting/Connected/Reconnecting/Ended/Failed, mute, hang up. A mesh node ID never gets a call button and never implies an account.
  • App-lifetime model (InternetCallsModel.shared, started in applicationDidFinishLaunching): receiving continues whatever tab is selected; an invitation is consumed only when shown (otherwise the shared poll offers it again); transient poll errors keep the banner, only authoritative absence closes it; a failed decline keeps the banner; every end signal (terminal status, remote departure, room closed, TriOS's own status poll for answered calls) releases room and microphone once, without waiting for server DeleteRoom.
  • Call server configuration: validated (https, or http only for local addresses; no credentials, query or fragment), confirmation before switching to a different server, refused during a call, previous server's nickname/link forgotten, only the address saved. The label states configuration only: HTTPS address, not verified.
  • Build seam in clade-build (the build that links SQLCipher and QueenUILib; xtask build does not link SQLCipher and is unchanged): TRINET_PIN pins the TRI-NET commit whose phone/shared/{CallIdentity,InternetCall,NicknameDirectory}.swift are compiled in; packages/TriOSLiveKit builds LiveKit 2.15.2 with the TRI-NET Xcode projects' pins; -D TRIOS_CALLS; the bundle is made runnable: executable in Contents/MacOS/trios, QueenUILib, LiveKit dylib and frameworks embedded, ad hoc signed and verified. Sources/CSQLCipher is now found in the monorepo layout too.
  • Info.plist: TRINET_IDENTITY_KEYCHAIN_SERVICE (TriOS is its own TRI-NET device; needs phone(shared): per-origin service tokens, per-app identity Keychain service, stale account results dropped tri-net#416) and NSMicrophoneUsageDescription.

Dependencies

Evidence in this PR

  • TriOSCallPolicyTests (XCTest, Trios Swift CI).
  • TriOS calls seam workflow (macos-15): full clade-build with pinned TRI-NET, Queen (gHashTag/trinity 8e535bc9) and LiveKit; bundle executable, @rpath dependency closure and signature checks; seam integration test (real model + TRI-NET controller vs a stub call server); trios.app kept as an artifact for app and device QA.
  • Nothing was built or run locally (memory pressure on this machine); CI is the first build.

Not verified

No live call yet. Acceptance still needs Mac -> phone and phone -> Mac on two networks with audible two-way audio, accept/decline/cancel/end convergence, reconnect and TURN with UDP blocked, against a call API, LiveKit and TURN reachable from both networks; none has been verified from the configuration available here.

Dmitrii Fedorov (@dmitrii-f-t27)

Spec first: apps/trios-macos/.trinity/specs/internet-calls.md (#2053).

- Calls segment in the Mesh tab: call server field (validated, confirmed,
  never changed during a call), account binding by claimed nickname or link
  code, exact-nickname lookup over the Internet route only, call button on a
  resolved contact, incoming banner and app-level floating panel, states,
  mute, hang up. Mesh node IDs never get a call button.
- InternetCallsModel lives for the app session (started at launch); incoming
  invitations are consumed only when shown, transient poll errors keep the
  banner, a failed decline keeps it, and every end signal (terminal status,
  remote departure, room closed, own status poll for answered calls) releases
  room and microphone once.
- Build seam in clade-build: pinned TRI-NET shared Swift (TRINET_PIN), a
  SwiftPM-built LiveKit 2.15.2 (packages/TriOSLiveKit), -D TRIOS_CALLS, and a
  runnable signed bundle (executable in Contents/MacOS, QueenUILib, LiveKit
  dylib and frameworks); Sources/CSQLCipher found in the monorepo layout.
- Info.plist: own TRI-NET identity Keychain service, microphone usage text.
- Pure policy TriOSCallPolicy with XCTests; a seam integration test drives
  the real model and TRI-NET controller against a stub server in CI.

Closes #2053

Agent: LEAD
@tri-claw

tri-claw Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Summary by t27-bees

Worth a look

  • apps/trios-macos/TRINET_PIN:1 — The pinned commit f70939ab90e638ee62b33ff4b8de314189957769 differs from the one cited in the spec (f6fe7d45 from phone(shared): per-origin service tokens, per-app identity Keychain service, stale account results dropped tri-net#416). If the wrong commit is used, the compiled TRI-NET shared code may lack the per-app Keychain service, Internet-only exact lookup, or origin-scoped tokens required by the spec.

  • apps/trios-macos/BR-OUTPUT/InternetCallsModel.swift:312 — adopt() subscribes to account.$nickname and calls self.adopt(reloaded) inside the sink. A nickname change (e.g., after linking) triggers a second adopt(), which creates fresh subscriptions to controller.$state, controller.$participantName, etc. without cancelling the previous ones, potentially duplicating UI updates and leaking cancellables.

  • apps/trios-macos/BR-OUTPUT/InternetCallsModel.swift:387 — watchIncoming() polls every 3 s but has no back-off, max-retries, or cancellation when the model shuts down (only Task.isCancelled stops it). A permanently failing authenticatedIncoming call will spin forever, wasting CPU and network.

  • apps/trios-macos/BR-OUTPUT/InternetCallsModel.swift:224 — applyServerAddress() calls controller?.stopIncomingPolling() then adopt(current), which calls startReceiving() and thus controller?.startIncomingPolling() on the same controller instance. If stopIncomingPolling()/startIncomingPolling() aren’t idempotent or leave intermediate state, the poll could miss an incoming call during the switch.

  • apps/trios-macos/BR-OUTPUT/InternetCallsView.swift:345 — IncomingCallPanel.show() calls created.center() before created.contentView = NSHostingView(rootView: content). The panel’s frame is centered for the default empty size (380×84), not the SwiftUI content’s actual size, so the panel may appear off-center or clipped until the next layout pass.


Read: 14 files, +2231 -6, the whole diff up to 60000 characters (the rest was not read). Head 190f16f. Model: openai-compatible/nvidia/nemotron-3-ultra-550b-a55b. Commands: @t27-bees review | summary | help | pause | resume. Free for every repository.

- A server change bumps a generation: a late claim, search or account result
  of the previous server is dropped before it reaches the Keychain, the
  binding or the contacts; pending operations are cancelled. The
  configuration is reloaded through the shared loader, which now sends a
  service token only to its own origin (Trinity-S-AI-DNA/tri-net#415), also after a
  restart. TRINET_PIN moves to f70939ab.
- Every call, answer and hang-up bumps an attempt: a completion or error of a
  superseded attempt never tears down the current call or shows an error on
  it. teardownCount records each release.
- Seam test (CI): delayed stub responses for create, claim, search and link;
  captured Authorization per host; active teardown exactly once with a server
  cancel; delayed A never ends B; incoming panel visible outside the Calls tab.
- TriOSServerAddressProblem conforms to Error (Result needs it).

Refs #2053

Agent: LEAD
@dmitrii-f-t27
dmitrii-f-t27 marked this pull request as draft October 21, 2026 16:53

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TriOS macOS: Internet calls between TriOS users through the TRI-NET call stack

1 participant