Guardian threads retain their parent in rollouts but are absent from thread_spawn_edges
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 45/100
Research direction
Start with codex-rs/core/src/guardian/review_session.rs, codex_delegate.rs, and agent/control/spawn.rs to trace Guardian creation and edge persistence. Read codex-rs/core/src/agent/control.rs and codex-rs/state/src/runtime/threads.rs, then reproduce the SQLite query against a Guardian rollout. Done means the persisted parent relationship is available in thread_spawn_edges or another canonical state relation, with existing Guardian records backfillable from session_meta.parent_thread_id.
Written by the indexing model from the issue text.
Description
Verified against: upstream/main commit
71448a29e7343b9613eaea620fcdbd196aed2af0 from 2026-07-16.
Related but not duplicate:
- #25341 covers ordinary
subagent visibility and staleopenedges; it assumes child edges exist. - #32035 shows Guardian
parent_thread_idmetadata while reporting resume and UI failures; it does
not report the missingthread_spawn_edgesrow.
The examples below are from a local profile, with thread IDs replaced by
consistent synthetic UUIDs so the SQLite and rollout records can still be
correlated safely.
What issue are you seeing?
Persisted Guardian review threads have an exact parent_thread_id in their
rollout session_meta, but no corresponding row is written to
thread_spawn_edges in ~/.codex/state_5.sqlite.
This makes the canonical SQLite thread graph incomplete. Consumers using
thread_spawn_edges cannot associate Guardian cost, activity, or lifecycle
with the parent thread even though Codex had and persisted the exact parent ID.
Local read-only counts:
Guardian rows in threads: 466
All thread_spawn_edges rows: 1137
Guardian child edge rows: 0
Two example threads records:
id source thread_source cli_version
11111111-1111-4111-8111-111111111111 {"subagent":{"other":"guardian"}} subagent 0.144.5
22222222-2222-4222-8222-222222222222 {"subagent":{"other":"guardian"}} subagent 0.144.5
For both children, this query returns zero rows:
SELECT parent_thread_id, child_thread_id, status
FROM thread_spawn_edges
WHERE child_thread_id IN (
'11111111-1111-4111-8111-111111111111',
'22222222-2222-4222-8222-222222222222'
);
Their rollout files contain the missing relationship in the first record:
{"type":"session_meta","payload":{"id":"11111111-1111-4111-8111-111111111111","parent_thread_id":"aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa","source":{"subagent":{"other":"guardian"}},"thread_source":"subagent"}}
{"type":"session_meta","payload":{"id":"22222222-2222-4222-8222-222222222222","parent_thread_id":"bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb","source":{"subagent":{"other":"guardian"}},"thread_source":"subagent"}}
Each prompt independently records the same parent:
Reviewed Codex session id: aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa
Reviewed Codex session id: bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb
Both referenced parent IDs exist in threads.
What steps can reproduce the bug?
- Run Codex with Guardian review enabled and trigger an action that creates a
persisted Guardian review thread. - Read the Guardian rollout's first
session_metarecord and note
payload.idandpayload.parent_thread_id. - Query
thread_spawn_edgesforchild_thread_id = payload.id. - Observe that the rollout has an exact parent while the edge query returns no
row.
Aggregate verification query:
SELECT count(*) AS guardian_edges
FROM thread_spawn_edges AS edge
JOIN threads AS child ON child.id = edge.child_thread_id
WHERE child.source = '{"subagent":{"other":"guardian"}}';
Observed result: 0.
What is the expected behavior?
A persisted Guardian thread with session_meta.parent_thread_id should have a
canonical parent relation in SQLite. Preferably, thread_spawn_edges should
contain the same parent/child pair so existing relation filters and graph
consumers work consistently for all persisted subagent threads.
If Guardians are intentionally excluded from thread_spawn_edges, the state
database should expose another canonical, queryable parent relation rather than
requiring consumers to reopen rollout JSONL files.
Existing Guardian rollouts should be backfillable from
session_meta.parent_thread_id.
Additional information
The current source still has the complete failure path:
- Guardian spawning receives the reviewed parent and uses
SubAgentSource::Other("guardian"):
review_session.rs#L656-L681. - The delegate supplies
parent_thread_id: Some(parent_session.thread_id)to
the spawned session:
codex_delegate.rs#L102-L114. SubAgentSource::parent_thread_id()returns a parent only for
ThreadSpawn;Other(_)returnsNone:
protocol.rs#L2973-L2982.- The edge writer is called from the regular agent spawn and resume paths, but
the Guardian spawn path above does not call it:
spawn.rs#L516-L526 and
spawn.rs#L898-L916. - Even if source-based edge persistence is reached, the edge writer exits when
SessionSource::parent_thread_id()returnsNone:
control.rs#L672-L680. - The state backfill also derives the parent only from serialized
source, so
it cannot recover Guardian edges fromsession_meta.parent_thread_id:
threads.rs#L318-L326 and
threads.rs#L1252-L1255.
The prompt builder also deliberately emits the reviewed session ID:
prompt.rs#L184-L191.
No write or manual repair was performed while collecting this evidence.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.5k
- Avg merge
- 1m
- Merged PRs (30d)
- 1k
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from openai/codex
-
enhancement remote
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
bug CLI windows-os
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
-
macOS sandbox blocks hw.optional.arm64 sysctl, causing Flutter to misdetect Apple Silicon as x64 Openbug CLI sandbox
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
bug CLI TUI
Difficulty 2/5 1-3 hours Newbie friendliness 90/100
-
CLI config enhancement skills
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
kwakseongjae/auto-hwp#319 ·
-
area:cli bug filter-quality good first issue priority:medium
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
Difficulty 1/5 Under an hour Newbie friendliness 72/100
bevyengine/bevy#25861 ·
-
comp-datalake
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
ClickHouse/ClickHouse#121222 ·
-
A-linter
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
oxc-project/oxc#26863 ·