| Exact versions (`dv`) | …views never went backwards, i.e. no time travel: process batches strictly in order, or always include earlier batches' writes. | Loses the core feature: a later batch can't render while an earlier one is pending without showing the earlier one's state. |
| Recording versions at end of run (relies on flags for writes during a run) | Could go back to recording at read time, in `get()`. | That would _remove_ the dependency on `schedule`'s `active_reaction` rule, but it costs on every read. Recording at the end is cheaper. |
| `#unprocessed` / status scoping | …statuses were stored per batch (e.g. a `Map<Effect, status>` per batch), or every batch ran a full `#revalidate` on every process. | Per-batch statuses cost on the hot path. A full revalidation walks the graph for every process. |
| Alone → `MAYBE_DIRTY` in `schedule` | …async effects tolerated spurious restarts. | `async-stale-derived-2` fails; more restarted async work. |
| Block records when alone | …we knew before traversal that the batch will commit synchronously (no pending async work in it), or branch selection survived without records. | Today this is a small allocation per block re-run on the hot path. `async-state-new-branch-unrelated-update` shows why we can't just skip it. |
| `record_late_read` | …reads after `await` stopped being dependencies (dev already warns with `await_reactivity_loss`). | Breaking change for code that relies on it. |
| Latest rule ([§7.2](#72-latest-values)) | …deriveds' global state were updated eagerly, or every derived evaluation in a view were batch-local. | Eager updates cost on the hot path. Always-local means recomputing in the real world after each commit, and effects that saw the batch's versions re-run. |
| Derived records | …deriveds were simply re-evaluated in every view (cache per `activate` only). | Apps with pending async batches recompute deriveds on every process. With `adopt` gone too, forks redo work on commit. |
| `adopt` / fork commit keeping versions | …committing a fork were allowed to re-run its block/async effects. | Restarts async work that was preloaded in the fork, which defeats the point of forks. |
| Superset edges / `keep` | …we never pruned while any batch exists (simpler code). | More spurious `MAYBE_DIRTY` checks. Fewer branches in `update_record`, but it's off the hot path either way. |
| `own_result` capture when equal | — | Needed for the batch to own its async results. Otherwise other batches' undo, intersection, merge and commit logic would ignore them. |
| Derived records dropped on commit | Not a simplification but a possible optimisation: promote derived records that are still `is_current` in the real world on commit. | Would avoid re-evaluating those deriveds (and re-running effects that saw their versions) after a commit. |
| Part | Could be removed or simplified if… | Cost / behaviour change |
| Exact versions (`dv`) | …views never went backwards, i.e. no time travel: process batches strictly in order, or always include earlier batches' writes. | Loses the core feature: a later batch can't render while an earlier one is pending without showing the earlier one's state. |
| Versions themselves (compare values instead) | …no signal used `safe_equals`, which treats an object as changed even when the same one is written again. Once non-runes mode is dropped (Svelte 6), stores are the only users. A store could instead drive a plain `===` value source plus a counter source that is incremented when it emits the same object again, and `$store` would read both. | Removes the version reuse rules ([§3.2](#32-the-same-value-has-the-same-version)) and the `-1` in `seen_version`, and gets 1 → 2 → 1 right (clean, where versions say dirty). But `dv` and records would keep the values they saw alive until the reaction re-runs (disconnected deriveds, paused branches and pending batches might not re-run for a long time). Errors would need an explicit "is an error" bit. Speed impact unknown (V8 stores small-integer arrays more compactly, and storing object references adds GC work). |
| Recording versions at end of run (relies on flags for writes during a run) | Could go back to recording at read time, in `get()`. | That would _remove_ the dependency on `schedule`'s `active_reaction` rule, but it costs on every read. Recording at the end is cheaper. |
| `#unprocessed` / status scoping | …statuses were stored per batch (e.g. a `Map<Effect, status>` per batch), or every batch ran a full `#revalidate` on every process. | Per-batch statuses cost on the hot path. A full revalidation walks the graph for every process. |
| Alone → `MAYBE_DIRTY` in `schedule` | …async effects tolerated spurious restarts. | `async-stale-derived-2` fails; more restarted async work. |
| Block records when alone | …we knew before traversal that the batch will commit synchronously (no pending async work in it), or branch selection survived without records. | Today this is a small allocation per block re-run on the hot path. `async-state-new-branch-unrelated-update` shows why we can't just skip it. |
| `record_late_read` | …reads after `await` stopped being dependencies (dev already warns with `await_reactivity_loss`). | Breaking change for code that relies on it. |
| Latest rule ([§7.2](#72-latest-values)) | …deriveds' global state were updated eagerly, or every derived evaluation in a view were batch-local. | Eager updates cost on the hot path. Always-local means recomputing in the real world after each commit, and effects that saw the batch's versions re-run. |
| Derived records | …deriveds were simply re-evaluated in every view (cache per `activate` only). | Apps with pending async batches recompute deriveds on every process. With `adopt` gone too, forks redo work on commit. |
| `adopt` / fork commit keeping versions | …committing a fork were allowed to re-run its block/async effects. | Restarts async work that was preloaded in the fork, which defeats the point of forks. |
| Superset edges / `keep` | …we never pruned while any batch exists (simpler code). | More spurious `MAYBE_DIRTY` checks. Fewer branches in `update_record`, but it's off the hot path either way. |
| `own_result` capture when equal | — | Needed for the batch to own its async results. Otherwise other batches' undo, intersection, merge and commit logic would ignore them. |
| Derived records dropped on commit | Not a simplification but a possible optimisation: promote derived records that are still `is_current` in the real world on commit. | Would avoid re-evaluating those deriveds (and re-running effects that saw their versions) after a commit. |