Skip to content

减少 typed store 样板代码并显式选择 replay 恢复 / Reduce typed store boilerplate with explicit replay recovery #8

Description

@tiye

中文

用户问题

组件调用端已经足够简洁:state 和 dispatch 通过 use_store(spec, initial = ...) 获得。但 spec 的定义成本仍然很高。一个小型本地编辑器目前需要定义 state 类型、action 类型、reducer、state codec、action codec,再组装 Store_spec。

用户可感知的目标并不是 replay 本身,而是在保留可序列化 typed actions 与 HMR 恢复能力的同时,去掉普通组件 store 定义中的持久化样板代码。

目标书写体验

  • 组件 view 继续使用现有的 state/dispatch pair,不需要了解日志、path 或 snapshot entry。
  • 恢复方式是 store 定义处的显式选择:适合 state codec 时使用 snapshot recovery;只需要纯可序列化 actions 时使用 replay recovery。
  • 基于 replay 的 Todo editor 不再定义或传递 state codec。
  • store identity、action schema/version、reducer 和 compaction 规则仍在定义处保持可见。

原型范围

  1. 引入命名清晰的 snapshot 与 replay store constructors,或等价的 recovery policies。
  2. 只迁移 Todo editor store 到 replay recovery。
  3. 将 versioned component-action log 与 domain action observation 分开持久化。
  4. 从当前 initial value 和解码后的纯 component actions 重建 state。
  5. 压缩高频 draft changes,并限制保留的 history。
  6. ordinary-child lifecycle cleanup 时清除 replay entries;整个 persistent feature 暂时缺席时则保留。

验收标准

  • Todo editor 删除手写 state encode/decode 与 State_codec 声明。
  • 组件仍然使用 (state, dispatch) = use_store(spec, initial = ...)。
  • draft state 能经过 snapshot round-trip,并在浏览器 HMR/localStorage 恢复后保留。
  • Finish/cancel 语义不会留下陈旧 editing session 供后续 replay。
  • input history 得到压缩,并有经过测试的上限。
  • malformed payload 以及不支持的 action schema/version 会安全回退到 initial。
  • domain actions 与 external effects 绝不自动 replay。
  • 文档展示 store 定义的 before/after,并解释何时选择 snapshot 或 replay。
  • 原型需要证明概念数量和定义体积有实质下降,否则不提升为默认方案。

非目标

  • 让 useState identity 变成隐式。
  • replay confirm、request、timer、browser 或 service effects。
  • 把 component logs 当作 domain persistence。
  • 向 agents 暴露 raw runtime state 或 log mutation。
  • 在评估 Todo 实验前迁移所有现有 stores。

English

User problem

The component call site is already concise: state and dispatch come from use_store(spec, initial = ...). Defining that spec is still expensive. A small local editor currently requires a state type, action type, reducer, state codec, action codec, and Store_spec assembly.

The user-visible goal is not replay by itself. The goal is to keep serializable typed actions and HMR recovery while removing persistence boilerplate from ordinary component-store definitions.

Target authoring experience

  • Component views keep the existing state/dispatch pair and do not learn about logs, paths, or snapshot entries.
  • Recovery is an explicit store-definition choice: snapshot recovery when a state codec is appropriate, replay recovery when pure serializable actions are enough.
  • A replay-backed Todo editor does not define or pass a state codec.
  • Store identity, action schema/version, reducer, and compaction remain visible at the definition site.

Prototype scope

  1. Introduce clearly named snapshot and replay store constructors or equivalent recovery policies.
  2. Migrate only the Todo editor store to replay recovery.
  3. Persist a versioned component-action log separately from domain action observation.
  4. Rebuild state from the current initial value and decoded pure component actions.
  5. Compact high-frequency draft changes and bound retained history.
  6. Clear replay entries with ordinary-child lifecycle cleanup, while retaining them when the whole persistent feature is temporarily absent.

Acceptance criteria

  • Todo editor removes its manual state encode/decode and State_codec declaration.
  • The component remains (state, dispatch) = use_store(spec, initial = ...).
  • Draft state survives snapshot round-trip and browser HMR/localStorage restoration.
  • Finish/cancel semantics do not leave stale editing sessions to replay.
  • Input history is compacted and has a tested upper bound.
  • Malformed payload and unsupported action schema/version fall back safely to initial.
  • Domain actions and external effects are never automatically replayed.
  • Documentation shows before/after store definitions and explains when to choose snapshot versus replay.
  • The prototype demonstrates a meaningful reduction in concepts and definition size; otherwise it is not promoted as the default.

Non-goals

  • Making useState identity implicit.
  • Replaying confirm, request, timer, browser, or service effects.
  • Treating component logs as domain persistence.
  • Exposing raw runtime state or log mutation to agents.
  • Migrating every existing store before the Todo experiment is evaluated.

Activity

  1. tiye commented on Aug 30, 2026

    @tiye
    MemberAuthor

    Lifecycle prerequisite update: PR #11 defines the persistent feature root versus ordinary keyed child boundary and adds snapshot-persisted child ownership markers.

    For the replay prototype, logs should now follow the same ordinary-child lifecycle: remove a scoped log when that child is swept, but retain logs while its whole feature is temporarily absent. Replay metadata should stay distinct from respo/component-scope lifecycle metadata and from domain action observation. The implementation order remains snapshot lifecycle first, replay recovery second.

  2. changed the title [-]Prototype action-replay component stores for HMR recovery[/-] [+]Reduce typed store boilerplate with explicit replay recovery[/+] on Aug 30, 2026
  3. tiye commented on Aug 30, 2026

    @tiye
    MemberAuthor

    Implemented as the user-facing experiment in PR #14.

    The component API remains use_store(spec, initial = ...). Store authors now choose snapshot_store or replay_store. Todo editor removed its state codec and declares a session policy instead: Begin is Replay_start, draft input is Replay_replace on one stable slot, and Finish/Cancel are Replay_reset.

    During implementation, an initial generic max-history design was rejected: dropping the oldest arbitrary action can change reducer results. The public prototype therefore has no append/truncate replay mode. Replay is intentionally limited to naturally bounded start/replace/reset sessions; cumulative or order-sensitive reducers continue to use snapshot_store.

    Verification covers compressed draft history, reset to the latest domain initial value, malformed/version/legacy fallback, empty action payload framing, ordinary-child cleanup, route retention, Koka/Vite HMR, full reload, and browser console health. The complete author guidance is in docs/store-recovery.md.

  4. changed the title [-]Reduce typed store boilerplate with explicit replay recovery[/-] [+]减少 typed store 样板代码并显式选择 replay 恢复 / Reduce typed store boilerplate with explicit replay recovery[/+] on Aug 30, 2026
  5. tiye commented on Aug 30, 2026

    @tiye
    MemberAuthor

    中文

    当前进度

    实现已在 PR #14 完成:Todo editor 已迁移到 replay_store,组件调用仍保持 use_store 返回的 state/dispatch pair;snapshot_store 继续服务于无法安全压缩 action history 的 stores。replay session 的 start、replace-slot、reset 语义,以及 ordinary child cleanup、persistent feature retention、HMR/localStorage 恢复均已有测试或浏览器验证。

    PR #14 当前 CI 通过且可合并。合并后本 issue 由 Closes #8 自动关闭;后续用户体验工作分别由 #12 和 #13 跟踪。

    English

    Current progress

    The implementation is complete in PR #14. The Todo editor now uses replay_store while the component call remains the state/dispatch pair returned by use_store. snapshot_store remains available for stores whose action history cannot be compacted safely. Replay session start, replace-slot, and reset semantics, together with ordinary-child cleanup, persistent-feature retention, and HMR/localStorage recovery, are covered by tests or browser verification.

    PR #14 currently has passing CI and is mergeable. Merging it will close this issue through Closes #8; follow-up user-experience work is tracked separately in #12 and #13.

  6. added
    enhancementNew feature or request
    area: authoring组件作者 API / Component authoring API
    experience: ergonomics日常组件书写体验 / Everyday component ergonomics
    on Aug 31, 2026
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: authoring组件作者 API / Component authoring APIenhancementNew feature or requestexperience: ergonomics日常组件书写体验 / Everyday component ergonomicsstatus: shipped已经合并 / Already merged

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions