[codex] simplify savepoint UX while preserving resume safety#24
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a unified savepoint CLI tool (savepoint.py) that handles creating, validating, inspecting, and exporting text-mode savepoints, replacing legacy standalone scripts. It refines the project validation posture with explicit statuses (such as failed-expected and not-run-justified) and updates the documentation, schemas, and test suites accordingly. The review feedback suggests two key improvements: using is_file() instead of exists() in the CLI to robustly handle directory paths, and fixing a potential false-positive bug in the legacy project validation parser when handling mixed passing and failing commands.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| "next_validation": next_validation, | ||
| "source": "legacy", | ||
| } | ||
| if project_validation_passed(legacy): |
There was a problem hiding this comment.
Calling project_validation_passed(legacy) on line 173 can lead to false positives. project_validation_passed returns True as soon as it encounters any passing command in the list, even if subsequent commands in the list failed. This means a legacy validation list containing both passing and failing commands will be incorrectly marked as passed overall. We should perform a safer check that ensures all commands passed and none failed.
has_passed = False
all_passed = True
for item in (legacy if isinstance(legacy, list) else []):
if not isinstance(item, dict):
continue
res = clean_text(item.get("result"), fallback="").lower()
sum_text = clean_text(item.get("summary"), fallback="").lower()
comb = f"{res} {sum_text}"
if re.search(r"\\b(pass|passed|ok|success|succeeded)\\b", comb) and not re.search(
r"\\b(fail|failed|error|not-run|not run|skipped)\\b",
comb,
):
has_passed = True
else:
all_passed = False
break
if has_passed and all_passed:| if not args.savepoint.exists(): | ||
| print(f"error: file does not exist: {args.savepoint}", file=sys.stderr) | ||
| return 1 |
There was a problem hiding this comment.
Using args.savepoint.exists() is not fully robust because it will evaluate to True if the path exists but is a directory (e.g., if a user accidentally passes a directory path). Attempting to call read_text() on a directory will raise an IsADirectoryError. Using args.savepoint.is_file() is safer and more defensive.
| if not args.savepoint.exists(): | |
| print(f"error: file does not exist: {args.savepoint}", file=sys.stderr) | |
| return 1 | |
| if not args.savepoint.is_file(): | |
| print(f"error: file does not exist or is not a file: {args.savepoint}", file=sys.stderr) | |
| return 1 |
Summary
/savepoint,/savepoint load, and/savepoint textwhile keepingSAVEPOINT_V1marker compatibility.scripts/savepoint.py, for save, validate, inspect, and text modes; legacy root renderer/validator wrappers were removed.passed,failed-expected,failed-blocking,not-run-justified, andnot-run-unknown.failed-expectedso resume-ready requires failed command/result/summary evidence, an explicit reason recorded in the artifact, and a next validation command.Breaking Changes
scripts/render_savepoint.pyandscripts/validate_savepoint.py.scripts/savepoint.py save ...andscripts/savepoint.py validate ...instead.skills/savepoint/scripts/savepoint.py.Safety Notes
RESUME_READY: yesdoes not mean project tests passed; it means a fresh agent can safely verify and continue.RESUME_READY: yestext.0 errorsandno failuresno longer make passed validation look failed.failed-expectedcannot be satisfied by a passing command such aspassed: <command> - 0 errors, or by historical failure wording in the summary when the result itself is passed.noneas missing before validator fallback.Validation
python3 scripts/check-frontmatter.pypython3 scripts/check-marker-block.pypython3 scripts/check-marker-semantics.pypython3 scripts/validate-examples.pypython3 scripts/validate-repo.pypython3 scripts/check-savepoint-renderer.pypython3 scripts/check-install-helper.py(Windows symlink privilege case skipped as expected)python3 scripts/savepoint.py validate --allow-example-paths examples/SAVEPOINT.filled.example.md examples/file-bugfix/SAVEPOINT.md examples/file-architecture/SAVEPOINT.md examples/unsafe-savepoint/SAVEPOINT.mdpython3 -m compileall -q skills/savepoint/scripts scriptsgit diff --checkSubagent Review