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:
- 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.
- Require
type === 'session_meta' - another envelope type can carry id/cwd/session_id and be mistaken for the header.
- 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.
What
Two modules now read a Codex rollout's
session_metaline and must apply the same three rules:hypaware-core/plugins-workspace/codex/src/rollout-cwd.js-readRolloutCwd, for the.hypignorecwd (LLP 0083).hypaware-core/plugins-workspace/ai-gateway/src/session_command.js-readRolloutMeta, forhyp sessionid resolution (LLP 0066/0067). Lands with PR hyp session ignore names the session container Codex drops on, not a thread id (#453) #458.The shared rules, each load-bearing:
Deserialize(protocol.rs:3157-3184) back-fillssession_idfromid, so a struct read silently returns a thread id where a container was asked for.type === 'session_meta'- another envelope type can carryid/cwd/session_idand be mistaken for the header.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:
hyp session ignorestated a thread id the drop never matched, reporting success while recording continued..hypignorewas evaluated against the wrong directory.Both were the same root confusion. During #462's review,
rollout-cwd.jswas found to have two of the three rules and to be missing guards thatreadRolloutMetahad - 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:
readRolloteMetais unexported and private to a different plugin.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
readRolloutSessionMetareturning{ 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.