Tasks follow the architecture spec phases: - Phase 0: key field on UElement (2 tasks + review) - Phase 1: reactive-host bridge / fiber tree (4 tasks + review) - Phase 2: key-based children reconciliation (3 tasks + review) - Phase 3: unmount & dispose support (4 tasks) - Phase 4: TypeBox value optimizations (4 tasks) Validated with taskgraph CLI: no cycles, 15 parallel generations, 3 high-risk tasks identified (signal-driven-updates, commit-mutations, fiber-disposal).
54 lines
2.3 KiB
Markdown
54 lines
2.3 KiB
Markdown
---
|
|
id: value-hash-detection
|
|
name: Value.Hash O(1) change detection
|
|
status: pending
|
|
depends_on: [value-clone-prevprops]
|
|
created: 2026-05-18T16:22:57.369878873Z
|
|
modified: 2026-05-18T16:22:57.369879316Z
|
|
scope: narrow
|
|
risk: medium
|
|
impact: component
|
|
level: implementation
|
|
---
|
|
|
|
# Description
|
|
|
|
Add `Value.Hash` as an O(1) change detection layer before `Value.Equal`. Hash comparison is faster than deep-equal for large subtrees because it's a single integer comparison.
|
|
|
|
**Critical constraint:** `Value.Hash` uses a global mutable accumulator (FNV-1a state). It is NOT re-entrant. You cannot call `Value.Hash` from within a `computed` or `effect` that is itself triggered by a hash comparison. Hashes must be computed outside reactive computations, during the commit phase.
|
|
|
|
The optimization strategy from the architecture doc says to add `Value.Hash` after confirming the global accumulator constraint is manageable. This task must verify that the reconciler never calls `Value.Hash` from within a `computed` or `effect`.
|
|
|
|
Approach:
|
|
1. Cache hash on fiber after each commit
|
|
2. On next reconciliation, compute hash of new node
|
|
3. If hashes differ, proceed to `Value.Equal` check
|
|
4. If hashes match, skip subtree (hash match is sufficient for "unchanged")
|
|
|
|
## Acceptance Criteria
|
|
|
|
- [ ] `Value.Hash` imported from `@alkdev/typebox/value`
|
|
- [ ] Fiber caches hash value after each commit (new `hash` field)
|
|
- [ ] On reconciliation: hash comparison before `Value.Equal` comparison
|
|
- [ ] Hash computed OUTSIDE reactive computations (commit phase only)
|
|
- [ ] Verified: no `Value.Hash` call happens inside `computed` or `effect` callbacks
|
|
- [ ] When hashes differ, falls through to `Value.Equal` (then to full reconciliation)
|
|
- [ ] When hashes match, skip subtree (fast path)
|
|
- [ ] Existing tests pass
|
|
- [ ] New test: unchanged subtree detected by hash match
|
|
- [ ] New test: hash mismatch falls through to Value.Equal / reconciliation
|
|
- [ ] New test: hash never called from within a computed/effect
|
|
|
|
## References
|
|
|
|
- docs/architecture/reconciler.md — TypeBox Optimization Layer, Value.Hash row, Value.Hash Constraint
|
|
- docs/architecture/reconciler.md — Optimization Strategy (step 2)
|
|
- docs/architecture/reconciler.md — Open Question 3 (should Value.Hash be used given the constraint)
|
|
|
|
## Notes
|
|
|
|
> To be filled by implementation agent
|
|
|
|
## Summary
|
|
|
|
> To be filled on completion |