Skip to content

[codex] simplify savepoint UX while preserving resume safety#24

Merged
dd3ok merged 7 commits into
mainfrom
codex/savepoint-v1.1-lite
Jun 12, 2026
Merged

[codex] simplify savepoint UX while preserving resume safety#24
dd3ok merged 7 commits into
mainfrom
codex/savepoint-v1.1-lite

Conversation

@dd3ok

@dd3ok dd3ok commented Jun 12, 2026

Copy link
Copy Markdown
Owner

Summary

  • Simplifies the Savepoint skill UX around /savepoint, /savepoint load, and /savepoint text while keeping SAVEPOINT_V1 marker compatibility.
  • Exposes one public CLI, scripts/savepoint.py, for save, validate, inspect, and text modes; legacy root renderer/validator wrappers were removed.
  • Separates project validation posture from resume safety using passed, failed-expected, failed-blocking, not-run-justified, and not-run-unknown.
  • Tightens failed-expected so resume-ready requires failed command/result/summary evidence, an explicit reason recorded in the artifact, and a next validation command.
  • Adds runtime references, README guarantee boundaries, output-contract fixtures, and CI compile validation.

Breaking Changes

  • Removed root scripts/render_savepoint.py and scripts/validate_savepoint.py.
  • Use scripts/savepoint.py save ... and scripts/savepoint.py validate ... instead.
  • Portable runtime entrypoint remains skills/savepoint/scripts/savepoint.py.

Safety Notes

  • RESUME_READY: yes does not mean project tests passed; it means a fresh agent can safely verify and continue.
  • Savepoint artifact validation, redaction, marker integrity, active-command accounting, and blocking drift remain hard blockers.
  • Renderer final success reads the final marker instead of body prose, preventing false success from incidental RESUME_READY: yes text.
  • Negated success summaries such as 0 errors and no failures no longer make passed validation look failed.
  • failed-expected cannot be satisfied by a passing command such as passed: <command> - 0 errors, or by historical failure wording in the summary when the result itself is passed.
  • Renderer blocker reporting treats placeholder reason/next validation values such as none as missing before validator fallback.

Validation

  • python3 scripts/check-frontmatter.py
  • python3 scripts/check-marker-block.py
  • python3 scripts/check-marker-semantics.py
  • python3 scripts/validate-examples.py
  • python3 scripts/validate-repo.py
  • python3 scripts/check-savepoint-renderer.py
  • python3 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.md
  • python3 -m compileall -q skills/savepoint/scripts scripts
  • git diff --check

Subagent Review

  • Re-reviewed after fixes: no blockers found for failed-expected semantics, negated success summaries, docs/evals, install-helper coverage, or compile validation.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

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:

Comment thread skills/savepoint/scripts/savepoint.py Outdated
Comment on lines +80 to +82
if not args.savepoint.exists():
print(f"error: file does not exist: {args.savepoint}", file=sys.stderr)
return 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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

@dd3ok dd3ok marked this pull request as ready for review June 12, 2026 07:18
@dd3ok dd3ok merged commit b0e4c56 into main Jun 12, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant