Skip to content

Native RPC: durable, idempotent session creation and initial-prompt acceptance for mobile reconnects #705

Open

Description

@PsychedelicShayna

Note

Claude Opus 5.5 on behalf of PsychedelicShayna. Drafted by the NeoCode upstream-sync session (GPT-6.1 Sol) from its integration evidence; filed by the first officer.

Problem

A mobile client must survive a disconnected connection or process restart between native session creation, initial prompt acceptance, and receiving the corresponding response. The native creation/command interface currently exposed to NeoCode does not provide a durable caller-chosen creation key or an acceptance lookup. Retrying an ambiguous creation can create a second native session; retrying an ambiguous initial prompt can execute it twice.

NeoCode will ship new-task creation as online-only, explicitly reporting that offline queueing is unsupported for new tasks. It will not manufacture a SQL conversation, invent a native session filename, or treat transport correlation IDs as durable receipts. This issue requests the authoritative NeoPi contract needed to restore a genuine persistent mobile creation queue.

Evidence from the downstream integration

Source paths below are in PsychedelicShayna/neocode, branch sync/2026-11-11, inspected before the online-only creation adaptation. These are observations about the exposed interface, not a claim that all internal NeoPi code has been audited.

  1. packages/contracts/src/neopiNativeSessions.ts, NeoPiNativeSessionsOpenInput, accepts exactly:

    {
      providerInstanceId: ProviderInstanceId;
      sessionFile?: string;
      cwd?: string;
    }

    The result contains { ref: { providerInstanceId, sessionFile }, sessionId, cwd, attachment, capabilities, state }. Neither the input nor result exposes a durable creation request key or receipt. A downstream workspace-preparation option does not solve that missing native guarantee.

  2. apps/server/src/provider/neopi/NeoPiNativeSessions.ts, open, calls create(profile, input) whenever sessionFile is omitted. Existing sessions are gated/reused by the canonical file only after the client knows that file. The new-session connection starts the configured native executable using the requested canonical working directory. The GUI does not choose native identity.

  3. The same module's request removes id and requestId from ordinary incoming commands before issuing the native request. Its comment explains that window-local IDs must not collide. Native Models login separately preserves a server-generated command ID. These are correlation/flow identities, not a durable deduplication guarantee for session creation or prompts.

  4. apps/mobile/src/state/use-native-composer-state.ts sends { type: "prompt", message, ... }, then consumes the accepted draft snapshot only after the awaited response. That preserves local draft content on an error but cannot prove that a lost response means the prompt was never accepted.

  5. The existing mobile SQL/V2 outbox has stable command/message/thread IDs and a bootstrap.createThread path (apps/mobile/src/lib/projectThreadStartTurn.ts). Reusing it for native creation would create a competing SQL conversation authority rather than solve native acceptance.

Ambiguous-response sequence

  1. Mobile persists draft D and intends to create native session S with initial prompt P.
  2. The server/native runtime creates S, or accepts P.
  3. The connection drops before mobile receives the authoritative session identity or prompt receipt.
  4. Mobile restarts and still has D but cannot distinguish “not accepted” from “accepted; reply lost.”
  5. Blindly opening again without a file may create S2. Blindly sending P again may duplicate an agent turn or external work.

No paid model call or destructive duplicate-session experiment was run to demonstrate this risk; it follows from the exposed creation branch and the absence of a durable reconciliation contract.

Required contract

Please define the native-owned interface; the following are required semantics, not prescribed command names:

  • Creation identity: a caller-generated durable request key, scoped to the correct native profile/storage authority. Retrying the same key returns the same canonical native session identity, including after reconnect and native/server restart.
  • Request consistency: reusing a key with different creation parameters must return an explicit conflict, not silently open another session or change the original request.
  • Durable initial-input identity: a distinct input/message key, or an atomic create-with-initial-input operation, ensuring replay cannot append/execute the initial prompt twice.
  • Acceptance reconciliation: query by those keys and distinguish unknown/not accepted, durably accepted with canonical identity/input identity, and any terminal rejection or cancellation. A transport timeout alone must not imply rejection.
  • Persistence ordering: acceptance must be durable before success is returned and recoverable after the connection or owner process is lost. Document retention/expiry so a queue cannot unknowingly retry after deduplication data expires.
  • Cancellation races: define what happens if cancellation races acceptance, and let the client recover the authoritative outcome without guessing or resubmitting.
  • Attachments: acceptance identifies the exact prompt plus attachment references that became native-owned, so mobile can release only that accepted snapshot and retain newer edits.
  • Capability negotiation: advertise the guarantee, allowing older native runtimes to remain explicitly online-only instead of silently degrading queue safety.

Acceptance scenarios

  • Lose the creation reply, reconnect, and retry the same key: one native session and the same canonical identity.
  • Restart the native owner/server after creation was committed but before replying: reconciliation still returns that identity.
  • Lose the initial-prompt reply and retry/reconcile: one accepted input and at most one execution.
  • Reuse a key with different cwd/profile/prompt/attachments: explicit conflict.
  • Cancel immediately before and after acceptance: one authoritative, recoverable result.
  • Send a newer local draft while reconciling the old one: only the accepted snapshot is consumed.

Scope

NeoPi remains authoritative for session IDs/files, history, prompt acceptance, and leases. NeoCode can own its persistent mobile draft/queue and project/worktree preparation, but must not implement a second native receipt store or infer acceptance by scanning loosely matching sessions.

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

    downstreamNeeded by a project that consumes NeoPineeds-triageNot yet triaged

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions