Skip to content

Two independent readers of Codex session_meta enforce the same privacy-relevant invariant; it has silently drifted twice already #465

Description

@philcunliffe

What

Two modules now read a Codex rollout's session_meta line and must apply the same three rules:

The shared rules, each load-bearing:

  1. Parse the raw JSONL line, never a deserialized struct - Codex's hand-written Deserialize (protocol.rs:3157-3184) back-fills session_id from id, so a struct read silently returns a thread id where a container was asked for.
  2. Require type === 'session_meta' - another envelope type can carry id/cwd/session_id and be mistaken for the header.
  3. Unconfirmable means unresolvable - absent or blank fields refuse rather than substitute.

Why this needs an issue rather than a shrug

The failure mode of getting any of these wrong is a silent wrong id in a privacy control, and it has already shipped twice:

Both were the same root confusion. During #462's review, rollout-cwd.js was found to have two of the three rules and to be missing guards that readRolloutMeta had - and its mutation testing surfaced two survivors on exactly these predicates. That is drift happening in real time, between two files that are supposed to agree.

Why it was deliberately not unified in PR #462

Three honest reasons, all still true:

So the deferral was right for that PR. It is not right permanently.

Suggested shape (do this after #458 lands)

Extract one reader - a shared readRolloutSessionMeta returning { threadId, sessionId, cwd } with all three rules in one place, refusing rather than guessing - and have both callers use it. It belongs wherever both plugins can reach it without one importing the other's internals; if no such home exists today, that placement is itself the design question worth answering here.

Whatever the shape, the invariant should be stated once and tested once, so a future change cannot satisfy one caller and break the other.

Ground-truth gate

The extracted reader needs the union of both callers' failure-path tests: legacy rollout with no session_id (refuse, do not back-fill), wrong envelope type (refuse), blank/non-string fields (refuse), and the mutation checks that each guard reddens its own named test. Then confirm both callers still pass their existing suites unchanged.

Provenance

Recommended by the review of PR #462 (#462), which found the drift and judged unification out of scope. Blocked on #458 landing. Related: #453, #459, LLP 0066, LLP 0067, LLP 0083.

Metadata

Metadata

Assignees

No one assigned

    Labels

    neutral:fixDelegate this issue to neutral for an autonomous fix attempt (reproduce -> fix -> PR)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions