System skills marker can falsely validate an incomplete `.system` cache
Summary
A matching .codex-system-skills.marker can make Codex accept an incomplete cache without repairing it. Unlike #19265 (disabled-process deletion, fixed by #36989) or #30014 (non-atomic refresh), no refresh occurs: the marker matches, so missing content is trusted.
Environment
- Codex Desktop
26.810.41047(build6570), macOS arm64 - App-bundled CLI:
/Applications/ChatGPT.app/Contents/Resources/codex(0.148.0-alpha.9) - Binary SHA-256:
7a26b07855ef91194c8d1bf58d15970878ee11458253df328d38fec0c87ec192 - Tested:
2026-08-16
Reproduction
This uses an isolated CODEX_HOME; it does not touch the normal cache:
probe_home="$(mktemp -d /private/tmp/codex-system-skills-marker.XXXXXX)"
bundle="/Applications/ChatGPT.app/Contents/Resources/codex"
system_root="$probe_home/skills/.system"
marker="$system_root/.codex-system-skills.marker"
missing_file="$system_root/skill-creator/SKILL.md"
CODEX_HOME="$probe_home" "$bundle" debug prompt-input -- 'probe' >/dev/null
find "$system_root" -type f | wc -l
test -f "$marker"
test -f "$missing_file"
marker_hash_before="$(shasum -a 256 "$marker" | awk '{print $1}')"
rm -f -- "$missing_file"
find "$system_root" -type f | wc -l
CODEX_HOME="$probe_home" "$bundle" debug prompt-input -- 'probe again' >/dev/null
find "$system_root" -type f | wc -l
test -f "$missing_file" && echo restored || echo missing
marker_hash_after="$(shasum -a 256 "$marker" | awk '{print $1}')"
test "$marker_hash_before" = "$marker_hash_after" && echo marker-unchanged
Observed result:
initial: 59 files
after deletion: 58 files
after rerun: 58 files; missing file not restored
marker changed: no
Cause and expected behavior
The install_system_skills fast path returns when .system exists and its marker matches the fingerprint derived from the embedded payload. It does not verify the on-disk files.
Missing or modified expected content should invalidate and repair the cache. Otherwise, a partial cache can persist until the marker changes or the directory is manually removed, leaving built-in skills or supporting files unavailable.
This reproduces a current integrity gap; it does not attribute any historical partial-cache report to this cause.
Acceptance criteria
- Matching-marker caches with a missing or modified expected file are detected and repaired.
- Validation covers every expected embedded file; complete caches retain a fast path.
- Regression tests cover both missing and modified files.
- Repair preserves the publication guarantees tracked in #30014.