Skip to content

20.6: History rewind as a registry command #78

Open

Description

@aliasfoxkde

Objective. Expose history rewind as a first-class registry command and surface the document's edit history as an inspectable overlay that a user can step back through.

Why. FireCraft's undo stack is not inspectable. A user who has made five edits cannot see what the fifth one was, cannot go back to the state after the second, and cannot tell whether a document is already where they think it is. Every other shell action in FireCraft is a registry command reachable from the menu and the palette; rewind being a special case breaks that shape and leaves the one operation a user reaches for under stress without a UI.

Current state. Implemented on branch feat/history-rewind-palette and in flight as PR #122 (head dec2e77, merged with main and conflict-free), which adds the registry command, the shell menu row, the Action variant and the command-palette entry.

Authority. The engine's existing history model — the one to reuse, not to replace; docs/planning/generated/dom-parity.md for the command-bound count; the CS6 History panel as the behavioural authority for what the overlay lists.

Work.

  1. Expose history rewind as a registry command in the same shape as every other shell command — engine catalog command id, shell menu row, Action variant, command-palette entry.
  2. A history panel/overlay listing the document's edit-history entries; selecting one returns the document to that state.
  3. Reuse the engine's existing history model if one exists. Do not build a second, parallel history.
  4. Be explicit — in the implementation and in the docs — about what is and is not rewound. If only the undo stack is covered, say so plainly rather than implying a full time-travel surface.

Acceptance.

  • The registry command exists and is dispatchable by command id.
  • The history list reflects the document's edits; choosing an earlier entry restores the earlier state.
  • Rewinding to the current entry is a no-op, and rewinding an empty history is safe.
  • The command appears in the command palette.
  • No inert menu rows are added (the inert_count_never_rises test caps them at 8).

Verification. cargo run -p xtask -- ci green on the exact PR head; unit tests cover the no-op, the empty-history, and the restore-to-earlier-state cases.

Boundaries. "Rewind" must not be presented as covering anything the engine's history does not actually record. If the raster cache, the undo stack and the document model are separate histories, the overlay lists the one it can truly restore — and the docs say which.

Tracking. Task #201; PR #122.

Next action (owner: shell). Land PR #122 on the receipt of both CI gates, then write down in docs/ exactly which history is rewound, so the feature is not over-claimed.

Activity

  1. aliasfoxkde commented on Nov 10, 2026

    @aliasfoxkde
    OwnerAuthor

    Implemented in PR #84 (branch feat/history-rewind-session).

    The design point: rewind is not a registry command. Its state is the session's undo history, not the document, and every id in catalog::ids() must undo and redo exactly against the document alone — the fuzz property that guards the catalog. A registry handler only receives &mut Document, so it could not express a rewind's effect at all.

    It is therefore a session-scoped command id, history.rewind:

    • engine::session::REWIND_ID, listed by catalog::session_ids() and catalog::all_ids(); catalog::ids() is unchanged, so the catalog fuzz properties are untouched.
    • Payload {"depth": n} with deny_unknown_fields. Depth 0 is the document as opened.
    • Session::rewind_to(depth) undoes and drops every step above depth; a depth past the recorded steps is refused (InvalidState), not clamped.
    • Session::history_entries() returns the panel's rows (document-as-opened at depth 0, then one row per edit).
    • The rewind is journaled, so a restarted session lands on the rewound document; the journal replay path handles the entry.

    Shell behaviour: the History panel lists those rows newest-first and clicking one rewinds (CS6's clickable History panel). A rewind clears the redo stack; a rewind to the current depth changes nothing and leaves redo alone.

    Decision record: docs/decisions/0082-session-scoped-history-rewind.md.

    Tests: crates/engine/tests/history_rewind.rs (depth semantics, redo rules, refusal, panel rows, session-scope split, payload contract, journal round-trip) and crates/app/tests/history_rewind.rs (the same through the editor's command door).

    Status: IMPLEMENTED — CI validation pending on PR #84.

  2. aliasfoxkde commented on Nov 10, 2026

    @aliasfoxkde
    OwnerAuthor

    Status: IN PROGRESS

    Landed (unmerged): PR #84 (feat/history-rewind-session, head b81e2e22, mergeable) adds crates/engine/src/{history.rs,journal.rs,session.rs}, the catalog command, the app shell panel, tests in crates/app and crates/engine, and the decision record docs/decisions/0082-session-scoped-history-rewind.md — 10 files, 566 insertions.
    Still outstanding: the PR is open and its GitHub checks currently show two failures, and nothing is on main.
    Next: fix the failing checks on the exact head, then land the lineage (see #86). Owner: app/shell owner, with the engine owner.

  3. aliasfoxkde commented on Nov 11, 2026

    @aliasfoxkde
    OwnerAuthor

    Campaign fields (appended 2026-11-11)

    Outcome — A user can step back to an earlier state of a document from a list of the session's edit-history entries, and the rewind is a documented, journaled command.

    Objective — Expose history rewind as a session-scoped command id (the engine's catalog ids must keep undoing and redoing against the document alone), add a history panel listing the document's edit-history entries newest-first, and state in the implementation and the docs exactly what is and is not rewound.

    Stopping condition — The rewind command is dispatchable by command id, the history list reflects the document's edits and choosing an earlier entry restores the earlier state, rewinding to the current entry is a no-op, rewinding an empty history is safe, and the command appears in the command palette.

    Verification — crates/engine/tests/history_rewind.rs (depth semantics, redo rules, refusal, panel rows, session-scope split, payload contract, journal round-trip) and crates/app/tests/history_rewind.rs (the same through the editor's command door) pass on the PR head, and the decision record docs/decisions/0082-session-scoped-history-rewind.md states the scope.

    Status — IN PROGRESS

    Tracking: task #201; implemented on PR #84 (feat/history-rewind-session), which is open and unmerged; the lineage is tracked in #86.

    Defects: none recorded.

  4. aliasfoxkde commented on Nov 11, 2026

    @aliasfoxkde
    OwnerAuthor

    Progress from train #107 (2026-11-11): the rewind capability landed — #84 adds history.rewind as a session-scoped engine command (catalog::session_ids()/all_ids(), deliberately not in the document-only registry catalog per the fuzz property), Session::rewind_to(depth), Session::history_entries(), and the clickable History panel (panels.rs "Rewind to step N"), with crates/app/tests/history_rewind.rs covering it.

    Still missing vs this issue's registry-command shape: a shell menu row, an Action variant, and a command-palette entry for rewind (the dispatch is panel-internal today). Leaving open for that residual.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions