Skip to content

code-mode: use client cell ids and linear observations#29398

Closed
cconger wants to merge 1 commit into
cconger/code-mode-runtime-compact-03i-terminal-cleanupfrom
cconger/code-mode-runtime-compact-03j-client-cell-identity
Closed

code-mode: use client cell ids and linear observations#29398
cconger wants to merge 1 commit into
cconger/code-mode-runtime-compact-03i-terminal-cleanupfrom
cconger/code-mode-runtime-compact-03j-client-cell-identity

Conversation

@cconger

@cconger cconger commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Why

Core already owns stable thread and tool-call identity. A separate idempotency key plus a host-generated cell ID adds protocol state, while retaining every arbitrary observation key grows replay storage for the session lifetime.

What

  • Generate compact 16-character CellId values in Core from thread ID and tool-call ID.
  • Replace the create idempotency key with caller-provided cell_id: CellId in the wire CreateCellRequest.
  • Make repeated creation of the same ID idempotent and reject conflicting request contents.
  • Replace the observe idempotency key with generation: ObservationGeneration in the wire ObserveRequest.
  • Keep the ObserveOutcome variants from code-mode: expose create and observe operations #29291 unchanged and retain only the latest value per cell for replay.
  • Implicitly acknowledge a non-terminal observation when Core starts the next generation.
  • Add resume-stability, create-conflict, replay, and eviction coverage.

Host/Core wire sequence

sequenceDiagram
    participant Core
    participant Host
    Core->>Core: derive CellId(thread_id, tool_call_id)
    Core->>Host: CreateCellRequest { cell_id, ... }
    Host-->>Core: same CellId
    Core->>Host: ObserveRequest { cell_id, generation: 0, ... }
    Host-->>Core: ObserveOutcome for generation 0
    opt outcome is ObserveOutcome::Yielded
        Core->>Host: ObserveRequest { cell_id, generation: 1, ... }
        Host->>Host: evict generation 0 outcome
        Host-->>Core: ObserveOutcome for generation 1
    end
Loading

Stack boundary

At this commit an ObserveOutcome::Completed or ObserveOutcome::Terminated value has no successor generation, so its replay payload remains retained until session shutdown. #29401 adds explicit terminal acknowledgement and release.

Validation

  • just test -p codex-code-mode
  • just test -p codex-code-mode-protocol
  • Focused Core tests cover deterministic cell IDs and linear observation generations.

Stack parent: #29310.

@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03i-terminal-cleanup branch from b9578cb to cb43921 Compare June 22, 2026 06:48
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03j-client-cell-identity branch 2 times, most recently from ba7fa7b to 846a04a Compare June 22, 2026 06:53
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03i-terminal-cleanup branch from cb43921 to 9139181 Compare June 22, 2026 06:53
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03j-client-cell-identity branch from 846a04a to 8ec0e02 Compare June 22, 2026 07:02
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03i-terminal-cleanup branch from 9139181 to 86200fe Compare June 22, 2026 07:02
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03j-client-cell-identity branch from 8ec0e02 to 12fe361 Compare June 22, 2026 07:09
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03i-terminal-cleanup branch 2 times, most recently from 28b4f57 to 2cb2170 Compare June 22, 2026 07:22
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03j-client-cell-identity branch 2 times, most recently from 74b9705 to aaa1d51 Compare June 22, 2026 07:49
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03i-terminal-cleanup branch from 2cb2170 to 474422b Compare June 22, 2026 07:49
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03j-client-cell-identity branch from aaa1d51 to ffe72de Compare June 22, 2026 08:37
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03i-terminal-cleanup branch from 474422b to abbe7df Compare June 22, 2026 08:37
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03j-client-cell-identity branch from ffe72de to e7f4fc2 Compare June 22, 2026 08:56
@cconger cconger force-pushed the cconger/code-mode-runtime-compact-03i-terminal-cleanup branch from abbe7df to 28536e0 Compare June 22, 2026 08:56
source: args.code.clone(),
})
.await
.map_err(|error| {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

(found by Codex)
This also runs for ConflictingCreate. In that case this attempt was not admitted, but finish_with_error closes and terminates the original cell that owns this ID. Can we make cleanup ownership-aware so a conflicting retry cannot tear down the existing cell?

.observation_generations
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
generations.insert(cell_id, next_generation);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Missing also reaches this insert..

struct IdempotentCell {
id: CellId,
kind: CellKind,
request: CreateCellRequest,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: created_cells outlives the actor entry, so retaining the full request here pins every script plus a duplicate enabled-tool catalog for the whole session

@cconger cconger closed this Jun 23, 2026
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