Skip to content

feat([issue-730]): per-session cross-machine resume toggle + reconcile in Story Builder - #869

Merged
atomantic merged 4 commits into
mainfrom
claim/issue-730
Jun 4, 2026
Merged

feat([issue-730]): per-session cross-machine resume toggle + reconcile in Story Builder#869
atomantic merged 4 commits into
mainfrom
claim/issue-730

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Summary

Ships the final slice of #730: the in-page UI for cross-machine resumable Story Builder sessions. The backend (POST /:id/sync, POST /:id/reconcile) shipped in #861 and the sync wire integration in #866 — this PR wires the Story Builder page to those existing endpoints.

  • Adds a per-session Cross-machine resume toggle to the Story Builder detail header (POST /:id/sync). Local-only is the default.
  • For a synced session, surfaces a Reconcile action (POST /:id/reconcile) that re-baselines the session's staleness against this machine's live universe/series records. Reconcile is hidden for local-only sessions (the route rejects them) and enabled only when drift exists.
  • Adds a syncDrift signal to the session view so the reconcile button only enables when this machine's records have actually diverged from the session's carried syncedHashes baseline — computed from the live hashes already gathered in getStorySessionView, so no extra reads. Always false for local-only sessions.
  • New apiStoryBuilder wrappers setStorySessionSync / reconcileStorySession (auto-exported via the services barrel; README row updated). Both mutate local state reactively after the call (no full refetch) and pass { silent: true } since they own their own toast.

Closes #730

Test plan

  • cd server && npx vitest run lib/storyBuilderIntegrity routes/storyBuilder services/storyBuilder — 111 pass, including new computeSyncDrift unit tests, the view's syncDrift flag, the /:id/sync + /:id/reconcile route dispatch (and local-only reconcile → 400 mapping).
  • cd client && npx vitest run src/pages/StoryBuilder.test.jsx — 19 pass, including two new UI tests: toggling sync on reveals the reconcile control reactively, and reconcile enables only on drift and clears it.

atomantic added 4 commits June 3, 2026 22:03
…e in Story Builder

Wire the Story Builder page to the existing POST /:id/sync and
POST /:id/reconcile routes (#861). Each session header gains a
cross-machine-resume toggle; for synced sessions a Reconcile button
re-baselines staleness against this machine's live records.

Add a syncDrift signal to the session view so the reconcile action only
enables when this machine's records have actually drifted from the
session's carried baseline — computed from the live hashes already
gathered in getStorySessionView, so no extra reads.
…Steps update reactively

Both reviewers flagged that POST /:id/sync and /:id/reconcile returned
the bare session record, so toggling sync or reconciling — which shift
the staleness baseline and can change which locked steps read as stale —
left the step rail's stale badges showing pre-mutation state until a
reload. The routes now return the same flattened view as GET /:id
({ ...session, staleSteps, syncDrift }) and the client merges all three
fields, no full refetch. Also align the computeSyncDrift JSDoc with its
missing-baseline-counts-as-drift behavior and list it in the lib README.
@atomantic
atomantic merged commit a30160d into main Jun 4, 2026
2 checks passed
@atomantic
atomantic deleted the claim/issue-730 branch June 4, 2026 05:15
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.

Optional cross-machine resumable story-builder sessions

1 participant