ekp/postmortem/20260728-dp-cache-signature.md
Kinneyzhang fd1210e557 fix: close repository audit findings
Complete task002 through task016 across cache correctness, editor lifecycle, C boundaries, build and release governance, dictionary provenance, performance, interactive workflows, tests, documentation, and final cleanup.
2026-07-28 22:43:10 +08:00

67 lines
2.5 KiB
Markdown

# Complete DP Cache Signatures Instead of Invalidation Watchers
## Context
`ekp-para` caches width-dependent DP and rendered results. The old key was
only the line width, with a special `(width . looseness)` cons when looseness
was non-zero. Two failures followed:
- changing a cost parameter reused a result computed under the old value;
- the cons key never hit an `eql` hash table when reconstructed.
The DP reads six cost parameters at runtime, so paragraph identity alone
cannot make those cached results valid.
## Decision
Use one flat signature containing line width, looseness, and all six runtime
cost parameters. Compare keys with structural `equal`.
Paragraph-construction inputs remain in `ekp--para-key`; DP-only inputs
remain in `ekp--dp-key`. No cache-clearing side effect crosses that boundary.
## Alternatives Rejected
### Variable watchers that clear caches
Watchers would spread ownership across seven variables and discard
width-independent paragraph work. Forgetting the next parameter would
silently recreate the bug.
### An integer hash of all parameters
A hash collision would become a correctness failure. Structural keys make
collisions harmless because equality is still checked.
### A memoized global signature object
It saves small list allocations but adds mutable global state and comparison
logic. A 100,000-hit microbenchmark measured approximately 0.37 seconds for
the complete key versus 0.17 seconds for the old scalar key: about two
microseconds per lookup, below the cost threshold that would justify another
state owner.
## Consequences
- Algorithm changes take effect on the next call without manual flushing.
- Returning to a previous parameter set can reuse its prior cached result.
- Non-zero looseness now receives real cache hits.
- Cache lookup performs structural hashing over eight small scalar values.
- Each distinct parameter set can retain its own result in the paragraph
cache; normal interactive configuration has low cardinality, but a caller
that sweeps parameters should clear caches between experiments.
- No public API, C ABI, saved-file format, or paragraph representation
changed.
## Verification
- The old model failed both the parameter-isolation and identical-signature
tests.
- The new model passes all six parameter cases and the cache-identity check.
- Full ERT, C/Elisp fuzz, warning-clean byte compilation, and checkdoc pass.
## Rollback
Revert the key/table change and these regression tests. No migration or data
cleanup is necessary because caches are process-local.