Skip to content

feat(editor): expose imperative undo/redo history control - #149

Draft
seonghobae wants to merge 31 commits into
mainfrom
feat/imperative-history-control
Draft

feat(editor): expose imperative undo/redo history control#149
seonghobae wants to merge 31 commits into
mainfrom
feat/imperative-history-control

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Closes #148.

Purpose

Implement #148 as a bounded host-control surface for the same undo/redo commands already owned by Inkspan's toolbar/editor history extensions, while making retained host handles consistently fail closed once the underlying TipTap editor has been destroyed, keeping user-facing history commands inert while the editor is read-only, and enforcing the public runtime string contract on active-editor imperative text mutation.

Implemented boundary

  • canUndo, undo, canRedo, and redo delegate to the currently registered history implementation;
  • all four return false while the editor is read-only and do not consume history;
  • collaboration mode continues to use Yjs-aware history rather than a duplicate local StarterKit history engine;
  • retained handles fail closed after editor destruction across history and the established read/restore/evidence surface;
  • setValue() and insertValue() reject non-string JavaScript/untyped values on an active editor with stable payload-redacted TypeError('editor value must be a string.') before parser/editor access;
  • the active-editor lifecycle check remains first, so pre-init/destroyed retained handles stay inert rather than becoming an input-validation oracle; and
  • packed public declarations and real standalone/collaborative consumers exercise the history methods.

No release workflow, release identity, persistence, transport, credential, model, provider, room, database, tenancy or durable-audit authority is added.

Test-first lineage

  • Initial API RED 1d08f70210e5abdd68e2d83f4096117eab389973 proved the stable handle lacked canUndo / undo / canRedo / redo while the editor already owned history commands.
  • Lifecycle RED Inkspan: fix build defect, bundle offline multilingual fonts, product branding #1 2fc4d9f83c1405697b23402689546d4a48e880c2, CI 31414556067, proved a retained destroyed-editor handle still returned stale document state.
  • Lifecycle RED Inkspan: AI-authored Word/Excel/PowerPoint #2 554140d40035d5af4f006ad123d3bcdb5b55d261, CI 31415215254, proved revision/evidence/restore paths still retained stale editor authority after destruction.
  • Packaging RED 836a72220ca66f390f660fb3eb71eebfaa84b621, CI 31418632930, proved packed strict-TypeScript consumers did not exercise the new public history operations.
  • Read-only RED d7ead2540d91cfbb0b64319946e554eab1119b44, CI 31422150835, proved history remained actionable after editable={false}.
  • Root-cause repair e752891647cfd2341f362a70dcfbc029f8294e4f gates only the four user-facing history operations through an active-and-editable editor; explicit host-control mutators retain their existing programmatic authority.
  • Predecessor product head e6278289c47a54f97d450e7dad857f1397ebbe7b additionally proves read-only mode does not consume history and the same undo becomes available after editability returns.
  • 829c4097c8b86df01f32f04d10149ccf82acceb9 non-destructively synchronized the branch with exact protected main; predecessor workflow/review evidence does not transfer.
  • Runtime-string RED 9388ac4faa0c96df8c0a4ccd81905becbef591d8, CI 32242747975, build job 96036683192: immutable install and typecheck succeeded, then the exact 100%-coverage suite failed exactly the new hostile-Proxy regression (1 failed / 844 passed) because the caller-controlled sentinel reached Marked instead of a stable Inkspan boundary failure.
  • Runtime-string GREEN source repair df91ce76ee1adef586040b7cf2bf2f8deb8f5f3a validates active-editor imperative text before parser/editor access while preserving no-editor/destroyed-handle no-op semantics.
  • Current exact head 8e0ab3832460d83b7ae0e664bf697bc2d53f19b4 adds the matching active-PR contract documentation. Predecessor workflow/review evidence does not transfer to it.

Current protected-main synchronization

Protected shipped truth is independently resolved as exact main@3b38ead2d00f44eb578d0689087b9293b3dabe1e. Current exact Draft head is 8e0ab3832460d83b7ae0e664bf697bc2d53f19b4.

The branch remains Draft and GitHub reports it mechanically mergeable. The intended source/document delta remains confined to the canonical imperative-history handle lane; the runtime-input repair changes only that handle boundary and its regression/contract evidence.

Exact-current-head evidence

For unchanged exact head 8e0ab3832460d83b7ae0e664bf697bc2d53f19b4 at the latest fresh refetch:

  • CI 32243336207: completed / success, including exact Typecheck, Test with 100% coverage, library build, packed package consumers, demo build, Office Python 3.11–3.14, and Playwright 1.62.0 cross-engine clipboard evidence;
  • Security Scan 32243336423: completed / success;
  • SAST Semgrep 32243336185: completed / success;
  • formal submitted reviews: 0;
  • unresolved inline review threads: 0;
  • qualifying independent approving reviews: 0;
  • GitHub reports the Draft mechanically mergeable; mergeability is not authorization.

Pending/in-progress/queued/skipped/cancelled/absent/stale/predecessor/status-only/model-only evidence is non-passing. Repository technical results do not independently establish separately applicable central OpenCode/Noema/Strix/coverage/review generations, and automated/model/status evidence is not qualifying independent approval.

Integration dependency

Keep this PR Draft and unmerged while #118 owns the protected v0.6.0 release/publication boundary and while qualifying independent approval/live governance remain incomplete. Before any future lifecycle transition, refetch the unchanged exact head, live protected base, ancestry/mergeability, live rules/permissions, formal reviews/threads, and every applicable repository/central workflow. Require qualifying independent latest-push approval under live governance. No self-approval, force push, destructive rebase, gate weakening, predecessor-evidence transfer or fabricated release identity.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
📝 Walkthrough

Walkthrough

CwlEditorHandlecanUndo, undo, canRedo, redo 메서드를 추가했습니다. 구현은 파괴된 편집기를 제외합니다. 편집기가 없으면 관련 메서드는 false를 반환합니다. 단일 편집기와 협업 편집기에서 동작을 검증했습니다.

Changes

Undo/Redo Handle API

Layer / File(s) Summary
Handle 계약 및 구현
src/types.ts, src/components/useEditorHandle.ts
CwlEditorHandle에 undo/redo 상태 조회 및 실행 메서드를 추가했습니다. getEditor는 파괴된 편집기를 반환하지 않습니다. 실행 메서드는 편집기에 포커스를 설정합니다.
핸들 동작 검증
src/components/CwlEditorHistoryHandle.test.tsx
실제 CwlEditor에서 콘텐츠 변경 후 undo와 redo를 검증했습니다. 활성 편집기가 없거나 destroy된 공유 핸들의 메서드가 false를 반환하는지 검증했습니다.
협업 이력 검증
src/collaboration/CollaborativeCwlEditor.test.tsx
두 에디터에서 canUndo, undo, canRedo, redo API를 사용합니다. undo/redo 결과와 추가 undo 가능 상태가 원격 에디터에 전파되는지 검증합니다.

Estimated code review effort: 3 (보통) | ~20분

Possibly related issues

  • ContextualWisdomLab/inkspan 이슈 148 — imperative CwlEditorHandle undo/redo API와 편집기 수명 주기 및 협업 동작 테스트를 다룹니다.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 imperative undo/redo history control을 공개하는 PR의 주요 변경 사항을 정확하고 간결하게 설명합니다.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/imperative-history-control

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@seonghobae
seonghobae marked this pull request as ready for review August 10, 2026 15:13
@seonghobae
seonghobae marked this pull request as draft August 10, 2026 18:01

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@opencode-agent opencode-agent Bot added priority: medium Normal-priority or P2 work status: draft Draft pull request type: feature New or expanded product capability labels Aug 22, 2026
@seonghobae

Copy link
Copy Markdown
Contributor Author

Restacked onto protected main at a40b9489665bed7d95af619a6079b9c51cab299a; exact head is 5e365be46afbf09bc962538c4502111552412ba9.

Fresh verification:

  • imperative history/collaboration tests: 3 files / 13 tests passed
  • TypeScript typecheck: passed
  • full Vitest suite: 158 files / 887 tests passed
  • coverage: 100% statements, branches, functions, and lines
  • production build and all packed-package consumers: passed
  • Python support contract: 4 passed
  • unresolved review threads: 0

This remains draft and dependency-gated by #118.

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

Remove the duplicated Python support contract changes from this imperative-history branch. PR #405 remains the single writer while this branch keeps its editor history API and package delta.

Signed-off-by: Seongho Bae <seonghobae@users.noreply.github.com>

Commit-Message-Assisted-by: Claude (via Claude Code)
@seonghobae

Copy link
Copy Markdown
Contributor Author

Office Python 지원 계약의 single-writer를 #405로 복원했습니다. imperative undo/redo API와 package 델타는 유지하고 공유 계약 파일만 additive revert로 제거했습니다. 현재 head: 1b0d3d4. 검증: 관련 13/13, 전체 build, packed package verification 통과.

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

Labels

priority: medium Normal-priority or P2 work status: draft Draft pull request type: feature New or expanded product capability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(editor): expose bounded imperative undo/redo history control

1 participant