Skip to content

Team sharing on by default for paired computers, made safe - #2095

Open
AbirAbbas wants to merge 6 commits into
devfrom
feat/teams-share-on-by-default
Open

AbirAbbas wants to merge 6 commits into
devfrom
feat/teams-share-on-by-default

Conversation

@AbirAbbas

@AbirAbbas AbirAbbas commented Oct 31, 2026 •

Copy link
Copy Markdown
Collaborator

Team sharing between paired computers (#2080) shipped off by default. This turns it on by default, and fixes what a stability audit and an independent review found would hurt people who never touched the switch.

What changes for a person

  • Paired computers share teams automatically. Settings → General → share teams reads on unless this computer chose off. Turning it off on either computer stops teams moving between them; what was already exchanged stays.
  • Unpaired computers: nothing changes. Sharing only takes effect when the computer is paired. The hand test compared an unpaired home on this branch with one on dev: zero relay requests, and the same files.
  • A damaged setting fails safe. A missing key reads on; an unreadable config file or a wrong-typed value reads off, so a damaged file never switches on a computer that chose off.
  • The first merge loses nothing. Before a computer's first sharing round, its teams are copied to teams.before-sharing.json (with a fallback where hard links fail; incoming changes wait for the copy, and a failure is shown once). Duplicate team names both stay as they were. A cleared manager appointment is kept only in an empty former-manager slot, never overwriting one.
  • Pairing replace says what happens to teams. The confirmation names teams and appears even when teams are the only local state; the receipt names where they were set aside. Without a terminal it never waits for input; non-terminal --replace behaves as before.
  • A window on another computer's engine (chat --at, --host) follows that engine's sharing, not the viewing computer's.
  • A local team member opens like the same chat from Home. It no longer waits on, or is refused by, the relay before the first ownership reading.
  • The model stops seeing the other computer's history when sharing stops: cached digests are dropped.
  • Shared Traffic publishes at most every two minutes (was 30 s), so two busy computers stay inside the hosted relay's 5,000 frames per identity per day.
  • Pairing and preference reads stay off the TUI event loop.

Validation contract

  • C1/C2/F6: an unset preference reads on; an explicit off reads off; damage reads off.
  • C3: the preference stays local and remote preferences cannot change it.
  • F1: an unpaired computer with the preference unset behaves exactly like an explicit off on dev: the existing SharingOff tests run a second time unpaired and unset, with every assertion intact.
  • F2/R1/R2: two separately made team files merge byte-identically in both orders; the backup is made once and never rewritten; an occupied former-manager slot is never overwritten.
  • F3/R3: replace names teams, returns the set-aside path, and a silent open pipe never blocks.
  • F4: a local member opens with zero ownership requests; a positively remote one keeps continuation.
  • F5: Traffic windows publish at most every teams.TrafficSyncEvery (two minutes).
  • F7/R7: after sharing stops, the next outgoing provider request carries no mirrored line.
  • R4: a hosted window adopts the engine's effective sharing in both directions.

Proof

  • Codex gates (no -json): go build ./...; vet on 11 packages; whole internal/config (314), internal/teams (128), internal/pair (127), internal/syncsetup (217, 26 existing optional skips), internal/vaultsync, internal/filememo; manual Chat gates plus the packed-manual tests; 74 named regressions in cmd/codeaf, internal/tui3, internal/session, internal/remote.

  • Hand test, real binaries in tmux (local relay, scripted model, throwaway homes), round 1 on the pre-review build:

    • S1 default on, both new: a two-member team reached the other computer in 5.1 s without touching Settings. PASS
    • S2 rename converges; a team deleted while the other computer was offline stays deleted. PASS
    • S4 opening a member chat held by the other computer goes through Continue this chat here?; model requests 12 → 12 (nothing ran twice). PASS
    • S5 off on one side: new teams stop arriving; existing teams kept. PASS
    • S6 unpaired, this branch vs dev: zero relay requests; normalized file lists identical. PASS
    • S7 paired with a build from before teams: opt-in team sharing between paired computers #2080: both computers' teams intact after restarts; a synced preference still crosses; doctor clean. PASS
    • S8 paired with dev (setting untouched): teams stay separate; turning dev's switch on merges exactly the two teams. PASS
    • S9 upgrade day, dev → this branch on both computers: both teams merge, none lost or duplicated; model requests 68 → 68 (no member turn re-ran). PASS
    • S10 replace: warned, original team file preserved, joined identity's teams loaded. PASS
    • S3 (Traffic from a team move) FAILED, but the same failure is on dev and is not caused by this change; see Follow-ups.
  • Hand test round 2 on this head's code (fresh homes, prebuilt binary):

    • S1 default on: team on the other computer within 10.2 s. PASS
    • S4 continue a member on the other computer: opened in 1 s; model requests 32 → 32. PASS
    • S6 unpaired vs dev: zero relay requests; normalized file lists identical. PASS
    • S9 dev → this branch on both computers: both teams merged within 3.8 s; model requests 80 → 80 over 148 s. PASS
    • S10 interactive replace: warned; original team kept in the named backup. PASS
    • S11 an UNPAIRED window on a paired computer's engine (chat --at) showed the engine's imported Traffic read-only; turning share teams off on the engine computer hid it in 2.3 s. PASS
    • S12 teams-only pair … --replace with a silent, held-open stdin: exited 0 in 0.5 s and printed where the teams were set aside. PASS
    • Seen once, outside this change: /delete answered "that path is not a saved conversation" for a --once chat's transcript path (internal/session/conversation_delete.go is unchanged here; not investigated).

Follow-ups (not in this PR)

  • In the default engine-backed window, a team move writes no Traffic line: cmd/codeaf/chatv3_host_teams.go leaves the seam's Append door nil (the seam comment says no wire answers it yet). With --no-host the lines are written and shared correctly (verified). The manual section "Moving a conversation between teams is written to Traffic" is therefore untrue in the default window today.
  • A team's spending cap is enforced against each computer's own spending (the manual now says so). One shared budget needs a single budget owner or reservations.
  • Local delivery's ownership listing can wait behind a relay write that holds the member mutex (pre-existing; the manual now says a local message can wait while this computer finishes sending a change to the relay).
  • Turning sharing off on one computer stops it sending and receiving; the other computer still uploads its own teams to the encrypted vault (nobody applies them). True bilateral permission would need a negotiated flag.
  • An adaptive, fleet-wide throttle and quota reservation for optional history.
  • A restore action for teams set aside by pairing replace (the file and receipt exist today).

🤖 Generated with Claude Code

AbirAbbas and others added 6 commits October 31, 2026 11:34
A missing or empty teams.share now reads on. An explicit off stays off, and an
unreadable config file or a wrong-typed value reads off, so a damaged file never
switches on a computer that had chosen off. TeamsSharingAt combines the
preference with an injected pairing gate; filememo gains an opt-in strict read
for that one preference.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… went

Before the first sharing round, this computer's teams are copied to
teams.before-sharing.json (hard link, or an exclusive-create fallback) and
incoming changes wait for that copy. A merge records a cleared manager
appointment only in an empty former-manager slot and never renames teams.
Pairing replace returns where teams were set aside. Shared Traffic publishes
at most every two minutes, inside the relay's daily frame allowance. Sync
carriers use effective sharing (preference and pairing).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the engine

Every surface reads effective sharing: an unpaired computer keeps its old
refresh, completion, cursor and Traffic behavior. Pairing is read off the
event loop. A window on another computer's engine follows that engine's
sharing. A local team member opens like the same chat from Home. A cached team
digest is dropped when sharing stops. Pairing replace asks about teams only on
a terminal and never waits on a silent pipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The team pages, Settings and PERF.md say what the code now does: automatic
sharing between paired computers, unpaired computers unaffected, turning it off
on either computer, the first-sharing backup, duplicate names, former managers,
spending caps counted per computer, two-minute Traffic, and what pairing replace
does with teams.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The new team-sharing sections said 'file' and 'share' often enough to pull
'how do I share a file with it' away from attaching files, and the hint's
'paired computers' pulled a Settings search for 'pair' onto General. Reword
both without changing any fact, and give the change entry its PR number.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@AbirAbbas

Copy link
Copy Markdown
Collaborator Author

Status: PR gate and Full check green on 9acd06f (Full check run 41217842378; its one red, internal/remote TestTaskWorkspaceEarlierCallerDeadlineStopsResidentOperation, is the known intermittent dev failure in task workspaces, untouched here, and passed on re-run). Hand test rounds 1 and 2 passed (see body). Not merging yet: the macOS check on this exact head is still to run; the Mac is away. Merge follows a Mac PASS.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant