Context
PR #101 introduced versioned Codex app-server generations. Its review identified
that stopped generation directories accumulated until the 256-directory scan cap
blocked both startup and forced cleanup. PR #103 fixed that failure by excluding
inactive directories that retain neither state.json nor a generation socket from
the live and cleanup candidate limits.
The automated review on PR #103 identified the other side of this tradeoff:
inactive 24-hex generation directories now bypass both
MAX_SERVER_DIRECTORY_ENTRIES and MAX_SERVER_GENERATION_DIRECTORIES.
all_server_paths() still validates and probes every such directory, so a corrupted
or deliberately populated user-owned CODEX_HOME can force unbounded filesystem
work on every startup and codex-server stop --force.
Impact
This is a local resource-exhaustion or denial-of-service risk. It requires many
entries in the user-owned Codex runtime directory; it does not provide privilege
escalation, corrupt workflow data, or disconnect sessions by itself. Ordinary
history is unlikely to cause noticeable delay, but the implementation no longer
upholds its bounded-scan invariant.
Required Properties
- Bound CPU, memory, and filesystem operations for hostile or corrupted stores.
- Do not let ordinary inactive history permanently block startup or forced cleanup.
- Retain the 64-live-generation limit.
- Preserve fail-closed handling for live, unsafe, symlinked, foreign-owned, or
unverifiable generation entries.
- Do not delete or rename a generation without safely proving that operation is
valid.
- Keep lifecycle commands recoverable after interruption.
Simply counting inactive directories toward the old cap is not a fix because it
restores the PR #101 failure. Possible designs include a separate bounded history
namespace, a durable generation index, or incremental cleanup with durable
progress. The design should stay smaller than the abandoned generalized retention
subsystem explored during the PR #103 follow-up.
Acceptance Tests
- More than 256 legitimate inactive histories do not block normal startup or forced
cleanup.
- Very large sets of valid inactive names cannot cause unbounded traversal.
- Mixed inactive and live generations preserve every live generation and enforce
the live cap.
- Unsafe names, symlinks, ownership violations, and replacement races remain
fail-closed.
- Interrupted maintenance can resume without leaving permanent capacity blockers.
Related: #101, #103.
Context
PR #101 introduced versioned Codex app-server generations. Its review identified
that stopped generation directories accumulated until the 256-directory scan cap
blocked both startup and forced cleanup. PR #103 fixed that failure by excluding
inactive directories that retain neither
state.jsonnor a generation socket fromthe live and cleanup candidate limits.
The automated review on PR #103 identified the other side of this tradeoff:
inactive 24-hex generation directories now bypass both
MAX_SERVER_DIRECTORY_ENTRIESandMAX_SERVER_GENERATION_DIRECTORIES.all_server_paths()still validates and probes every such directory, so a corruptedor deliberately populated user-owned
CODEX_HOMEcan force unbounded filesystemwork on every startup and
codex-server stop --force.Impact
This is a local resource-exhaustion or denial-of-service risk. It requires many
entries in the user-owned Codex runtime directory; it does not provide privilege
escalation, corrupt workflow data, or disconnect sessions by itself. Ordinary
history is unlikely to cause noticeable delay, but the implementation no longer
upholds its bounded-scan invariant.
Required Properties
unverifiable generation entries.
valid.
Simply counting inactive directories toward the old cap is not a fix because it
restores the PR #101 failure. Possible designs include a separate bounded history
namespace, a durable generation index, or incremental cleanup with durable
progress. The design should stay smaller than the abandoned generalized retention
subsystem explored during the PR #103 follow-up.
Acceptance Tests
cleanup.
the live cap.
fail-closed.
Related: #101, #103.