Skip to content

fix(sleep): normalize transcript_source once so checkpoints match the harvested source - #363

Merged
Yifan Yang (Yif-Yang) merged 1 commit into
mainfrom
maintenance/normalize-transcript-source
Nov 4, 2026
Merged

Yifan Yang (Yif-Yang) merged 1 commit into
mainfrom
maintenance/normalize-transcript-source

Conversation

@Yif-Yang

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #354. That PR normalized transcript_source (case, surrounding whitespace) only inside harvest_for_config(). The per-(project, source) harvest checkpoint from #322/#312 and the tasks document still used the raw config value. As a result:

This adds normalize_transcript_source() in skillopt_sleep/harvest_sources.py and uses that one canonical value everywhere:

  • the harvest itself;
  • the cursor read and writes in run_sleep_cycle and in the handoff pin path;
  • the tasks document written by the handoff pin path and by cmd_harvest.

run_sleep_cycle now validates the source before it creates the night's staging directory, so an invalid value no longer leaves an orphan staging dir. Canonical names keep byte-identical cursor keys, and the legacy bare-<project> cursor is still read as the fallback for claude. get_backend() and state.py are unchanged.

CHANGELOG.md [Unreleased] → Changed now also tells users that a misspelled backend or transcript_source stops the run instead of silently using the mock backend or Claude transcripts (#350, #354, thanks Hrushikesh Ramilla (@Hrushikesh-ramilla)).

Verification

  • 13 new tests in tests/test_harvest_checkpoint_source.py. 12 fail on current main for the intended reasons: the stale ::Codex cursor is read, the tasks document records " Codex ", a list value raises AttributeError, and an orphan staging dir is left behind. All 13 pass here. Canonical keys and the legacy bare-project cursor are pinned unchanged.
  • Full isolated suite: 2027 passed, 13 skipped, 4 xfailed, 8 warnings, 381 subtests passed in 47.78s. mkdocs build --strict passes. New code is ruff-clean; the one remaining finding is an existing I001 in cycle.py's import block, also on main.

Compatibility notes:

  • Users with a non-canonical spelling switch to the canonical cursor, falling back to the legacy cursor or the lookback_hours window. The stale ::Codex entry is left in state.json but is no longer used.
  • Runs with seed_tasks or pinned digests now also reject an invalid transcript_source.

… harvested source

#354 normalized transcript_source only inside harvest_for_config, while the
per-(project, source) harvest checkpoint and the tasks document still used
the raw config value. "Codex" therefore harvested Codex but read and
advanced a "<project>::Codex" cursor, which may hold a time written while
that spelling silently harvested Claude, so older Codex sessions could be
skipped (#312). A non-string value raised AttributeError.

Add normalize_transcript_source() and use it for the harvest, for the
cursor in run_sleep_cycle and the handoff pin, and for the tasks document.
The cycle now validates the source before it creates the night's staging
dir. Canonical names keep byte-identical cursor keys, and the legacy
bare-project cursor is still read as the fallback.

Also note the #350/#354 fail-loudly change in CHANGELOG.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Yif-Yang

Copy link
Copy Markdown
Contributor Author

Merging this maintainer follow-up to #354. Background: an independent re-check of #354 (Claude Code, cross-checked here) found that transcript_source was normalized only inside harvest_for_config(), while the per-source harvest checkpoint from #322/#312 still used the raw spelling. So "Codex" harvested Codex but read a ::Codex cursor that could hold a stale time. The change was drafted with Claude Code and reviewed and re-run here before merging:

  • 12 of the 13 new tests fail on main and all pass here;
  • canonical cursor keys and the legacy bare-project cursor are unchanged;
  • full isolated suite: 2027 passed, 13 skipped, 4 xfailed, 8 warnings, 381 subtests passed in 47.78s;
  • official CI is green on this head.

The CHANGELOG entry credits Hrushikesh Ramilla (@Hrushikesh-ramilla) for #350/#354.

@Yif-Yang
Yifan Yang (Yif-Yang) merged commit 52ad5a2 into main Nov 4, 2026
13 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