Skip to content

0.2.0 known sharp edges: messagesSince("0") reads full history; permission-prompt inert under bypassPermissions #3

Description

@isingh

Two known sharp edges shipped (documented, not fixed) in 0.2.0. Filing so they're tracked rather than living only in local notes. Both are conscious ship-with decisions, not regressions.

1. messagesSince("0") slices the entire transcript (read-side cursor footgun)

  • send() was hardened to never return "0" (it returns the DELIVERY_UNCONFIRMED / DELIVERED_QUEUED sentinels), but the read side still honors a numeric/positional cursor: messagesSince("0")all.slice(0) = every message ever (src/session/handle.ts, the messagesSince resolver, ~L242).
  • No current code path feeds it "0", so it's defanged in practice — but it's a live trap: a consumer who stores or derives a numeric cursor gets the whole conversation back, which looks like a flood of duplicates or causes re-acting on old turns.
  • Its only writeup currently lives in local design notes (the F40 entry, now outside the repo), so it's effectively invisible to consumers.

Fix options (the "option 3" discussed):

  • Reject bare-numeric cursors on the read side — accept only real message ids + the two sentinels — so "0" stops silently meaning "everything".
  • Promote a first-class "read all / list turns" affordance (e.g. turns() / a no-cursor messages) so there's a sanctioned way to read history / recover cursors.

2. Permission-prompt is inert under bypassPermissions / acceptEdits

  • The S5 approve/deny path (wait() → awaiting{permission-prompt}, state() → permission-prompt, respond()) only fires when claude runs in a prompting mode (default / plan / ask). Under bypassPermissions (or acceptEdits for edits) claude runs tools un-gated — no prompt — and claudemux correctly reports completed.
  • This bites the likely primary user: an unattended daemon usually runs bypassPermissions so it doesn't block on prompts — and therefore never sees the gate it might be relying on for programmatic approve/deny.
  • Documented in the README permission-mode caveat; not solved at the API level.

Open design question:

  • Promote permissionMode to a first-class CreateOptions / ResumeOptions field instead of threading it through extraArgs, so the gate's prerequisite is discoverable.

Neither blocks 0.2.0. Tracking only.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions