move-codex-session ignores databases and tables it does not know and still reports sourceRemoved: true #143

Open
opened 2026-10-10 06:57:41 +00:00 by jercik · 0 comments
Owner

At 1a85c77, the script moves rows only out of the six database families it names. A move reports sourceRemoved: true without a word about any other database in the home.

main finds state, thread_history, logs, goals, memories and queue through latestDatabase, which matches ^<prefix>_(\d+)\.sqlite$. Nothing scans the home for other databases. Codex 0.160.1 has two more that hold per-session rows:

  • memories_v2_1.sqlite. Codex deletes a thread's rows from it next to memories_1 (delete_versioned_thread_memory in codex-rs/state/src/runtime/memory_versions.rs). The pattern never matches it, because v2_ follows the prefix.
  • agent_message_board_1.sqlite. Its boards are keyed by the session ID in a board column (codex-rs/ext/agent-message-board/src/local.rs).

Tables inside the known databases get only a heuristic check. requireNoUnknownThreadTables refuses a table whose name contains thread, that has a thread_id, parent_thread_id, child_thread_id or session_id column, or that is linked by foreign key to a known table. It missed memories_1.jobs, which keys its stage-1 rows by thread ID in job_key, so that table is now handled explicitly (lines 117-123). A table keyed any other way still passes.

The move exits 0, the rows for the moved session stay in the source database, and the destination doesn't get them. Nothing is deleted. The session's v2 memories or board posts just don't follow it, and the output gives no hint.

Reproduced on fixtures, each with exit 0, empty stderr and sourceRemoved: true, and the session's rows still in the source file:

  • memories_v2_1.sqlite in both homes, and in the source only (the destination then has no such file).
  • agent_message_board_1.sqlite in the source.
  • A table notes(id, owner) added to memories_1, holding the thread ID in owner. The same table with a thread_id column is refused.

A possible fix keeps the heuristic and adds one refusal: when the source home holds a <prefix>_<N>.sqlite whose prefix is not one of the six, fail and name the file. Other versions of a known prefix, such as an old state_4.sqlite, stay ignored as today. Moves then fail on memories_v2_1.sqlite until the script learns it. A strict allowlist of every table would catch more, but it would also refuse after any Codex upgrade that adds an unrelated table.

Evidence: reproduced at 1a85c77 with the fixtures above. The file names and their use come from reading Codex 0.160.1.

At `1a85c77`, the script moves rows only out of the six database families it names. A move reports `sourceRemoved: true` without a word about any other database in the home. [`main`](https://code.j4k.dev/j4k-oss/agent-skills/src/commit/1a85c77277b4f8924278686aa2c2969477c4eece/skills/move-codex-session/scripts/move-codex-session.ts#L2061-L2069) finds `state`, `thread_history`, `logs`, `goals`, `memories` and `queue` through [`latestDatabase`](https://code.j4k.dev/j4k-oss/agent-skills/src/commit/1a85c77277b4f8924278686aa2c2969477c4eece/skills/move-codex-session/scripts/move-codex-session.ts#L193-L201), which matches `^<prefix>_(\d+)\.sqlite$`. Nothing scans the home for other databases. Codex 0.160.1 has two more that hold per-session rows: - `memories_v2_1.sqlite`. Codex deletes a thread's rows from it next to `memories_1` (`delete_versioned_thread_memory` in `codex-rs/state/src/runtime/memory_versions.rs`). The pattern never matches it, because `v2_` follows the prefix. - `agent_message_board_1.sqlite`. Its boards are keyed by the session ID in a `board` column (`codex-rs/ext/agent-message-board/src/local.rs`). Tables inside the known databases get only a heuristic check. [`requireNoUnknownThreadTables`](https://code.j4k.dev/j4k-oss/agent-skills/src/commit/1a85c77277b4f8924278686aa2c2969477c4eece/skills/move-codex-session/scripts/move-codex-session.ts#L251-L299) refuses a table whose name contains `thread`, that has a `thread_id`, `parent_thread_id`, `child_thread_id` or `session_id` column, or that is linked by foreign key to a known table. It missed `memories_1.jobs`, which keys its stage-1 rows by thread ID in `job_key`, so that table is now handled explicitly (lines 117-123). A table keyed any other way still passes. The move exits 0, the rows for the moved session stay in the source database, and the destination doesn't get them. Nothing is deleted. The session's v2 memories or board posts just don't follow it, and the output gives no hint. Reproduced on fixtures, each with exit 0, empty stderr and `sourceRemoved: true`, and the session's rows still in the source file: - `memories_v2_1.sqlite` in both homes, and in the source only (the destination then has no such file). - `agent_message_board_1.sqlite` in the source. - A table `notes(id, owner)` added to `memories_1`, holding the thread ID in `owner`. The same table with a `thread_id` column is refused. A possible fix keeps the heuristic and adds one refusal: when the source home holds a `<prefix>_<N>.sqlite` whose prefix is not one of the six, fail and name the file. Other versions of a known prefix, such as an old `state_4.sqlite`, stay ignored as today. Moves then fail on `memories_v2_1.sqlite` until the script learns it. A strict allowlist of every table would catch more, but it would also refuse after any Codex upgrade that adds an unrelated table. Evidence: reproduced at `1a85c77` with the fixtures above. The file names and their use come from reading Codex 0.160.1.
Sign in to join this conversation.
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
j4k-oss/agent-skills#143
No description provided.