Skip to content

feat: generate and expose session ID for history isolation#133

Merged
eitsupi merged 12 commits intomainfrom
feat/session-id
Mar 23, 2026
Merged

feat: generate and expose session ID for history isolation#133
eitsupi merged 12 commits intomainfrom
feat/session-id

Conversation

@eitsupi
Copy link
Copy Markdown
Owner

@eitsupi eitsupi commented Mar 23, 2026

Summary

  • Generate a per-process session ID (HistorySessionId) at startup using reedline's nanosecond-timestamp approach
  • Pass the session ID to SqliteBackedHistory and the line editor so history entries are tagged per session and search filters can isolate sessions
  • Expose history_session_id (i64) in IPC session info: SessionInfo (disk file), SessionResult (JSON-RPC), and HeadlessInfo (--json output)
  • In headless mode or when history is disabled/unavailable, the field is null
  • If history database initialization fails at runtime, the session ID is cleared from both in-memory cache and on-disk session file

Design notes

history_session_id as JSON number (i64)

The session ID is a nanosecond-precision timestamp (~1.7×10¹⁸), which exceeds JavaScript's Number.MAX_SAFE_INTEGER (~9.0×10¹⁵). This means JS/TS clients that parse the JSON with JSON.parse() will lose precision in the lower digits.

We chose to keep it as a JSON number (i64) because:

  • It matches reedline's internal representation (HistorySessionId(i64))
  • The ID is an opaque identifier — clients should not interpret or do arithmetic on it
  • JS/TS clients can handle this correctly using BigInt or libraries like json-bigint, or by using a reviver function in JSON.parse()
  • Introducing a string representation would add complexity without clear benefit for the current use case

If a future client ecosystem strongly prefers string-typed IDs, a parallel history_session_id_str field can be added in a backwards-compatible way.

Test plan

  • cargo check / cargo clippy / cargo fmt pass
  • Unit tests for create_session_id() covering disabled history, missing directory, and normal cases
  • Start arf, run some commands, verify session_id column in SQLite history DB is populated (not NULL)
  • Start a second arf instance, verify it gets a different session ID
  • arf ipc session | jq .history_session_id returns a non-null integer
  • arf headless --json | jq .history_session_id returns null

🤖 Generated with Claude Code

eitsupi and others added 2 commits March 23, 2026 13:05
Use Reedline::create_history_session_id() to generate a nanosecond-
precision timestamp as session ID. Pass it to SqliteBackedHistory and
the line editor so history entries are tagged per session and search
filters can isolate sessions.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Add history_session_id (i64) to SessionInfo (disk), SessionResult
(JSON-RPC), HeadlessInfo (--json output), and SessionMeta (cache).

In REPL mode the ID is generated once and shared across R/shell
history and IPC.  In headless mode the field is null since there
is no history backend.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@eitsupi eitsupi changed the title feat(history): generate and expose session ID for history isolation feat: generate and expose session ID for history isolation Mar 23, 2026
@eitsupi eitsupi requested a review from Copilot March 23, 2026 13:25
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a per-process history session identifier to isolate history entries by session, and exposes that identifier through IPC/session metadata so clients can filter history per run.

Changes:

  • Generate a HistorySessionId at interactive startup and thread it into both R and shell SqliteBackedHistory / Reedline instances.
  • Plumb history_session_id: Option<i64> through IPC session metadata (disk SessionInfo, JSON-RPC SessionResult, and arf headless --json output; null in headless).
  • Update IPC server startup APIs/callers to accept and cache the optional history session ID.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
crates/arf-console/src/repl/state.rs Stores the raw history_session_id in REPL state for IPC/meta-command access.
crates/arf-console/src/repl/mod.rs Adds session_id to Repl, configures Reedline + SQLite history with the session ID, and passes raw ID into meta commands.
crates/arf-console/src/repl/meta_command.rs Threads history_session_id into :ipc start so runtime-started IPC includes the same session ID.
crates/arf-console/src/main.rs Generates the session ID at startup, passes it to IPC startup, and includes it in headless --json output.
crates/arf-console/src/ipc/session.rs Adds history_session_id to on-disk session discovery metadata with backward-compatible deserialization.
crates/arf-console/src/ipc/server.rs Extends server startup to accept/capture history_session_id and includes it in SessionInfo.
crates/arf-console/src/ipc/protocol.rs Adds history_session_id to the JSON-RPC SessionResult schema.
crates/arf-console/src/ipc/mod.rs Plumbs history_session_id through IPC start, caches it in SessionMeta, and returns it in session responses.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Reduce visibility of history_session_id_raw() to fn (not pub)
- Update HeadlessInfo doc comment to mention history_session_id
- Add test for history_session_id propagation through SessionMeta

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

eitsupi and others added 2 commits March 23, 2026 13:44
When history is disabled (--no-history or config), generate None
instead of a session ID so IPC does not misleadingly advertise
history isolation.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Extract create_session_id() helper and add tests verifying that
session ID is generated when history is enabled and None when
history is disabled.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Update create_session_id() to also check that a history directory
is resolvable (matching Repl::r_history_path logic), so IPC does
not advertise history isolation when no backend exists.

Also update doc comments on SessionInfo and SessionResult to
reflect all cases where history_session_id can be null.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

eitsupi and others added 2 commits March 23, 2026 14:10
- setup_history() now returns a success flag and logs a warning on
  failure instead of silently falling back
- If neither R nor shell history DB opens, clear the session ID from
  IPC metadata via clear_history_session_id()
- ReplState only exposes session ID when at least one history DB
  was successfully initialized
- Update doc comments to reflect all cases where session ID is null

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Apply the same history-failure handling to run_standalone() that
was already in run_with_r_mainloop(): clear the IPC session ID
and gate the value passed to process_meta_command.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

clear_history_session_id() now updates both the in-memory
SessionMeta and the on-disk session file so clients discovering
sessions via the file system also see null for history_session_id
when history backends failed to open.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Update history_session_id docstring in SessionResult to mention the
  "no history directory available" case
- Add a NOTE comment explaining the brief window where IPC advertises
  a session ID before history DBs are confirmed open
- Guard clear_session_history_id against PID mismatch by forcing
  info.pid = pid before rewriting the session file

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@eitsupi eitsupi requested a review from Copilot March 23, 2026 14:31
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- clear_history_session_id: skip disk rewrite when value is already None
- clear_session_history_id: log non-NotFound read errors instead of
  silently swallowing them

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Simplify clear_history_session_id to only attempt disk cleanup when
IPC was started and the session ID was actually set.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@eitsupi eitsupi merged commit d1b61f0 into main Mar 23, 2026
14 checks passed
@eitsupi eitsupi deleted the feat/session-id branch March 23, 2026 15:12
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.

2 participants