Skip to content

Locked out of my own chat: pressing enter only shows "Continue this chat here?" #2072

Closed

Description

@santoshkumarradha

Summary

A person can be locked out of their own chat on their only computer. The chat opens and shows its history, but pressing enter brings back "Continue this chat here?", and pressing continue here does nothing visible. The only way back in is an undocumented combination of an environment variable and a flag.

The root cause is a version gap between the codeaf client and the hosted sync service. Around it are about a dozen bugs and UX problems that turn one server-side gap into a lockout with no way out. This issue lists all of them from the person's side. #2070 and #2071 hold the deeper detail for some of them.

Principle: the chat on this computer is the person's. Sync is a convenience on top. No state of the sync service, a lease, or another device should ever stop a person from writing to a chat on the computer in front of them.


What a person meets, in order

  1. They pair two computers, work in a chat on one, then go back to the other.
  2. Home shows the same chat two or three times: two identical <title> 28 turns · <machine> 16m rows and a third row with the same title and no count.
  3. Opening the chat shows "Continue this chat here?". Pressing continue here closes the card and nothing opens. No message.
  4. They unpair the other computer to simplify things. codeaf devices revoke <name> --all says no device called "<name>" is paired with this machine, while codeaf devices lists that exact name. Without --all it works.
  5. Home now offers "Continue 's latest chat here?" for the device they just removed.
  6. Opening a duplicate row offers "open separately / discard / leave them". Discarding both copies cleans Home, but the chat still shows the card, now saying "this chat was last held here", on the only computer they use.
  7. They open the chat directly with codeaf chat --session <path>. It opens with full history. Typing a message and pressing enter brings the card back. They can't send.
  8. The chat shows two lines they can't act on: "calls are not being sealed, so rewind cannot reach them: the sync service must be updated before chats can move; codeaf's operators update the hosted service, or run this build of codeaf relay for your own service".
  9. They turn sync off with CODEAF_SYNC_URL=off. Home now shows only chats from a week ago or more; every current chat is gone from the list.
  10. They open the chat with sync off. It fails: "the background engine for this folder started with a different environment than this terminal and is still in use…" along with an engine --stop command that would interrupt their other window.
  11. What finally works: CODEAF_SYNC_URL=off codeaf chat --no-host --session <path-to-transcript.jsonl>. Nobody would find that.
  12. Separately, trying to reach the computer without ssh (codeaf serve) fails with error code: 522 (Reaching a paired computer without ssh fails on the hosted relay #2071).

Bugs and causes

Code citations are origin/dev at 66fa77e.

A. Lockout: no writes when the service can't do a conditional take — the blocker

  • When a chat's lease has lapsed (wasFree), writing needs Acquire(RequireConditional: true) (internal/syncsetup/drive.go:271-286). continue here does too (internal/handoff/handoff.go:140).
  • The client only allows that when the service sends codeaf-conditional-takes (internal/directory/http.go:97-106). Otherwise it returns ErrConditionalTake.
  • The relay source in dev has sent that header since 2026-10-23 (relay/hosted/src/routes.js:111, Wormhole: your codeaf follows you between computers (on by default) #1888 and Relay: coordination as a Raft group, and joined computers can lead #1950). The deployed hosted service doesn't, so every lapsed chat on every client of this build can't be written.
  • The window falls back to "only shows its local copy", and each enter shows the takeover card again instead of saying why.

B. Client and hosted service can drift apart unnoticed

Nothing stops a client build from requiring service behaviour that isn't deployed: no version handshake, no deploy gate, no CI check that the live service answers what the shipped client requires.

C. continue here fails silently (#2070)

  • takeRemoteState returns early while homeTaking is set, and successful landings never clear it (internal/tui3/homepanel_continue.go:298).
  • In a fresh window, the ErrConditionalTake sentence is put on Home's say line, which the person doesn't see when the card closes.

D. "Continue this chat here?" on the only computer

The card says "this chat was last held here" and still asks. With no other live holder, there is nothing to continue from.

E. Duplicate rows and the meaning of a branch row (#2070)

  • Branch copies (N turns · <device>, internal/chatlist/copy.go:39,174) show as identical rows next to the main chat.
  • Local rows are keyed by transcript path, machine rows by cell id (homepanel_sessions.go:24-36, homepanel_machines.go:169-200).
  • Nothing on the row says it is a leftover copy, and nothing says whether "discard" loses anything.

F. A removed device is still offered

After codeaf devices revoke, Home still offers "Continue 's latest chat here?".

G. devices revoke --all misses computers that sync chats

stopAllByName sends --all to the first kind that can stop several, which is the serve device book, never the synced-chats kind (cmd/codeaf/devices.go:160-170). Without --all, kindOf finds it. The same name works or fails depending on a flag that only means "every device with this name".

H. Turning sync off hides current chats

With CODEAF_SYNC_URL=off, Home lists only legacy chats. Current chats live in the copy root (<project>/.moving/<id>, internal/cell/copy.go:27), which is only listed through sync. Sync off should mean "don't talk to the service", not "forget my chats".

I. Sync off can't be used while another window is open

The background engine refuses a terminal with a different environment and offers only engine --stop, which interrupts the other window. --no-host works but isn't mentioned.

J. Store-busy shows the wrong reason (#2070)

The engine's "store writer is still busy after waiting 30 seconds" falls through to "the chat could not be put in this folder" (homepanel_heldelsewhere.go:374). It never names the program holding the store.

K. --host takes onto the wrong computer (#2070)

Under codeaf chat --host B, sync and takeover run on the connecting computer while Home's rows come from B (chatv3_host.go:599 → chatv3_surface.go:86).

L. Messages written for operators, not people

M. The folder name .moving reads like a stuck transfer

Every current chat lives under .moving/. Anyone checking state by hand reads it as "half-moved" and may try to clean it up, which would delete their chats.


Acceptance (end to end, each one a two-device or one-device test on the hosted service)

Never locked out

  • With the hosted service missing any capability the client wants (e.g. conditional takes), a chat whose lease has lapsed and that no other device holds live can still be written on this computer. The person types, presses enter, and gets a reply. The turn is kept locally and published when the service allows. No card is shown.
  • When another device holds the chat live, pressing enter says so in one line naming the device, with continue here as the action. It is never just the card again with no reason.
  • There is no state of sync, lease, relay or device list in which a person can read a chat on this computer but has no visible way to write to it.

Service and client stay compatible

  • The release and deploy pipeline fails if the live hosted service doesn't answer a capability the client being shipped requires. A client never ships ahead of the service it depends on.
  • A client talking to an older service keeps every feature that doesn't need the new capability, and says in one plain sentence which feature waits for the update.

Continue here

  • Pressing continue here either opens the chat within a few seconds or shows one line saying why, with retry. Three continues in a row in one window all work.
  • On a computer that last held the chat, with no other live holder, no card is shown. The chat just opens.

Home

  • Each chat appears once. Leftover copies show as a small marker on that row ("2 copies from "), not as identical rows. Opening the marker says plainly what is in each copy and whether discarding loses anything.
  • A removed device never appears in any offer, row or card.

Devices

  • codeaf devices revoke <name> and codeaf devices revoke <name> --all both remove a computer listed by codeaf devices, whichever kind it is.

Sync off

  • With sync off, Home lists every chat on this computer, current and legacy, and each opens and can be written.
  • Turning sync off while another window is open either applies to the new window without touching the other one, or says exactly what to run. --no-host is offered when it is the answer.

Messages

  • Every message about sync tells the person what still works, what doesn't, and the one thing they can do. No operator instructions, no raw upstream bodies.
  • codeaf doctor reports a lapsed lease that can't be retaken, a client/service capability gap, leftover copies and removed devices still referenced. codeaf doctor --fix repairs what is safe to repair and says what it did.

Storage

  • The folder holding current chats has a name that doesn't suggest something in flight, or carries a README saying it is the live store and must not be removed.

Related: #2070 (continue here, duplicate rows, store-busy reason, --host), #2071 (reaching a computer without ssh on the hosted relay), #1982 and #1986 (closed, earlier sealing and two-computer issues).

Seen on the dev channel build of 2026-10-29 against the hosted sync service on 2026-10-30.

Activity

  1. added
    bugSomething the code does that it should not
    area:chatThe v3 surface a person sits in front of (internal/tui3)
    area:remote--host, relay, pairing, enginehost, attachments
    sev:seriousWrong or missing behaviour a person meets in ordinary use
    on Oct 30, 2026
  2. AbirAbbas commented on Oct 30, 2026

    @AbirAbbas
    Collaborator

    Status after #2075 and #2078 (both merged into dev):

  3. AbirAbbas commented on Oct 31, 2026

    @AbirAbbas
    Collaborator

    Everything here has landed on dev:

    Two doctor items were left out on purpose:

    • Naming a sync service capability gap. The capability header only comes back on a write (POST /v1/dir/acquire), and doctor must not create anything on the service. codeaf-release service keeps that probe.
    • Naming a removed device still referenced locally. Holds, offers and saved rows store a device's display label, which changes on a rename. Matching them against the paired list would clear the wrong things. Never lock a person out of their own chat on an older sync service #2075 already stops offering removed devices.
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

    area:chatThe v3 surface a person sits in front of (internal/tui3)area:remote--host, relay, pairing, enginehost, attachmentsbugSomething the code does that it should notsev:seriousWrong or missing behaviour a person meets in ordinary use

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions