Repository navigation
fix(plan): keep plan version history across midnight (#1679) - #1680
Open
backnotprop wants to merge 2 commits into
Open
backnotprop wants to merge 2 commits into
backnotprop wants to merge 2 commits into
Conversation
Plan history was keyed by generateSlug() = <heading>-<UTC date>, so a revision after UTC midnight landed in a new history dir as version 1 and lost its Versions tab and diff. Split the two jobs: generateSlug() still names the dated archive snapshots in plans/, while the new resolvePlanHistorySlug() picks the history chain: the open server's own slug (same heading), else today's dir if it has versions, else the most recently written <heading>-<date> dir of the project when its newest version is within 48h, else today's dir. Nothing on disk is renamed. Both plan servers (Bun and Pi) use it at startup and in updatePlan.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1679.
Problem
Plan version history lived in
history/{project}/{generateSlug(plan)}/, andgenerateSlugis<heading>-<UTC date of now>. A revision that arrived after UTC midnight landed in a new directory as001.md, sopreviousPlanwas null and the Versions tab and diff disappeared. The same slug also names the decision snapshots inplans/, where the date is wanted (parseArchiveFilename/listArchivedPlansread it back).Fix
The two jobs are now separate:
generateSlug(plan, now?)is unchanged and still names the archive files inplans/(decision-day UTC date).resolvePlanHistorySlug(project, plan, { now?, current? })inpackages/shared/storage.tspicks the history directory. The directory name keeps the{heading}-YYYY-MM-DDform, but the date now records when the chain started. The rule, in order:current: an open server keeps its own slug for revisions with the same heading (PiupdatePlan, the Claude Code mod's revisions).{heading}-{date}directory, if it already has versions. Same-day behavior is unchanged.{heading}-YYYY-MM-DDdirectory for this project, if its newest version file's mtime is within 48h.Both plan servers use it at startup and in
updatePlan(packages/server/index.ts,apps/pi-extension/server/serverPlan.ts, vendored throughvendor.sh). The history endpoints and the feedback archive'starget.slug/planVersionFileuse the history slug. The archive snapshot calls keep the datedslug. Nothing on disk is renamed or migrated: existing dated directories are simply continued.Why a 48h recency window
# Implementation Plan) into one chain forever. A window keeps unrelated same-heading plans days apart separate.Tests
packages/server/storage.test.ts:previousPlansetcurrentslug holdspackages/server/plan-history-midnight.test.tsand its Pi twin start a real plan server against a chain seeded under yesterday's date. They check/api/planpreviousPlan/versionInfo,/api/plan/versionsslug, PiupdatePlanstaying on the chain, and the approved snapshot named with today's date.generateSlug).All tests use a temp
PLANNOTATOR_DATA_DIRset inside the test, with the clock injected or mtimes set viautimes.Verified
bun run typecheck: clean.bun test: 5934 pass, 0 fail./tmp(not~/.local/bin), using a temp data dir withhistory/<project>/live-midnight-check-<yesterday>/001.mdstamped 3h ago. Fed an ExitPlanMode PermissionRequest:/api/planreturnedpreviousPlan= v1 andversion 2 / totalVersions 2./api/plan/versionsreturnedslug: live-midnight-check-2026-10-03.002.mdwas written into yesterday's directory.plans/live-midnight-check-2026-10-04-approved.md.Not verified live: the Pi extension inside a running Pi session (it is covered by the Pi server test above).