Skip to content

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

Description

@seonghobae

Current authoritative state

The bounded imperative history-control feature is implemented on the existing canonical single-writer Draft PR #149 / branch feat/imperative-history-control. Protected shipped truth remains exact main@3b38ead2d00f44eb578d0689087b9293b3dabe1e; current exact Draft head is 8e0ab3832460d83b7ae0e664bf697bc2d53f19b4.

The active PR adds canUndo(), undo(), canRedo(), and redo() to CwlEditorHandle without creating a second history engine. Standalone CwlEditor delegates to its existing TipTap/StarterKit history; CollaborativeCwlEditor delegates to the existing Yjs-aware history. All four operations return false while read-only without consuming history, and retained handles fail closed once the underlying editor is destroyed. Existing explicit host-control mutators keep their prior programmatic authority.

The same canonical handle lane now also enforces the public runtime string contract for active-editor setValue() / insertValue(). JavaScript/untyped callers supplying a non-string value receive the stable payload-redacted TypeError('editor value must be a string.') before Inkspan parses, coerces, reflects over, or inserts caller-controlled data. The retained-handle lifecycle guard remains first: before an editor exists or after destruction, these mutators remain inert rather than turning a stale handle into an input-validation oracle.

This remains local editor command/document mutation authority only. A successful history or explicit host-control command does not establish durable save, actor identity, authorization, persistence, audit, collaboration-provider acknowledgement, transport, tenancy, credential, model or server-side revision evidence.

Test-first lineage

  • Initial API RED 1d08f70210e5abdd68e2d83f4096117eab389973 proved the stable handle lacked the four history operations.
  • Lifecycle REDs 2fc4d9f83c1405697b23402689546d4a48e880c2 / CI 31414556067 and 554140d40035d5af4f006ad123d3bcdb5b55d261 / CI 31415215254 proved retained destroyed-editor authority remained on adjacent handle surfaces.
  • Packaging RED 836a72220ca66f390f660fb3eb71eebfaa84b621 / CI 31418632930 proved packed strict-TypeScript consumers did not exercise the public operations.
  • Read-only RED d7ead2540d91cfbb0b64319946e554eab1119b44 / CI 31422150835 proved user-facing history remained actionable after editable={false}.
  • Root-cause repair e752891647cfd2341f362a70dcfbc029f8294e4f gates only the history surface through active-and-editable editor authority.
  • Predecessor product head e6278289c47a54f97d450e7dad857f1397ebbe7b proves the read-only guard does not consume history and the same undo becomes available after editability returns.
  • 829c4097c8b86df01f32f04d10149ccf82acceb9 non-destructively synchronized the branch with protected main; predecessor evidence does not transfer.
  • Runtime-string RED 9388ac4faa0c96df8c0a4ccd81905becbef591d8, CI 32242747975, build job 96036683192: normal install/typecheck completed, then exact 100%-coverage tests failed 1 / 845 because a hostile Proxy reached Marked and threw private imperative-value sentinel instead of the stable Inkspan boundary error.
  • Runtime-string GREEN source repair df91ce76ee1adef586040b7cf2bf2f8deb8f5f3a validates active-editor imperative text before parser/editor access while preserving destroyed/no-editor no-op semantics.
  • Current exact head 8e0ab3832460d83b7ae0e664bf697bc2d53f19b4 adds the matching active-PR contract documentation; predecessor workflow evidence does not transfer to this head.

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;
  • qualifying approving reviews: 0;
  • unresolved inline review threads: 0;
  • GitHub reports the Draft mechanically mergeable.

Repository exact-head technical success is not qualifying independent approval and does not establish separately applicable central OpenCode/Noema/Strix/coverage/review evidence. Pending/queued/skipped/cancelled/absent/stale/predecessor/status-only/model-only evidence remains non-passing.

Integration boundary

The feature and runtime-input repair are active-PR truth only and are not protected-main shipped behavior. Keep this issue open until #149 integrates under then-live governance. Keep #149 Draft/unmerged while #118 owns the protected v0.6.0 release/publication boundary and qualifying independent approval/live governance remain incomplete. Before any lifecycle transition refetch exact head/base, live rules/permissions, reviews/threads and every applicable repository/central workflow. Do not create a competing history writer, self-approve, transfer predecessor evidence, weaken gates, move protected main or fabricate release identity.

Activity

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

    area: apiAPI, protocol, event, or external contractarea: authAuthentication, authorization, identity, or tenant isolationarea: ci-cdCI, GitHub Actions, checks, release, or supply chainarea: securitySecurity boundary, hardening, or vulnerability preventionbugSomething isn't workingenhancementNew feature or requestpriority: mediumNormal-priority or P2 workstatus: triagedOpen issue has an organization taxonomy assignmenttype: bugDefect or incorrect behaviortype: featureNew or expanded product capability

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions