feat(parser): persist generation-bound lexer restart checkpoints (#6982) - #7324
feat(parser): persist generation-bound lexer restart checkpoints (#6982)#7324EffortlessSteven wants to merge 50 commits into
Conversation
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
EffortlessSteven
left a comment
There was a problem hiding this comment.
Review verdict: not ready. Persisting complete lexer state is the correct next architecture, but the current identity and lifetime implementation can make ordinary lexing quadratic and can diverge from fresh lexing after an idle editor interval. Those defects sit in the restart authority itself, so token-parity tests run immediately after state construction do not falsify them.
| Self { | ||
| summary, | ||
| live, | ||
| source_fingerprint: fingerprint(source.as_bytes()), |
There was a problem hiding this comment.
[P1] This hashes the complete source—and then the growing prefix—once per retained checkpoint. With up to 4,096 checkpoints, initial lexing and generation carry-forward become O(checkpoints × source_len) and can approach quadratic work on large files before the incremental path starts. Compute the generation digest once and derive prefix identity incrementally or from a precomputed prefix-hash structure.
| return false; | ||
| }; | ||
| self.source_fingerprint == fingerprint(source.as_bytes()) | ||
| && self.prefix_fingerprint == fingerprint(prefix.as_bytes()) |
There was a problem hiding this comment.
[P1] A 64-bit FNV equality is not sufficient to authorize restoration of behavior-bearing lexer state. A collision makes belongs_to_source accept state from different bytes, which can produce incorrect tokens rather than merely a cache miss. Bind checkpoints to the canonical collision-resistant source/generation identity and use direct unchanged-prefix evidence; do not make a small fingerprint the correctness gate.
| if !self.belongs_to_source(old_source) | ||
| || self.summary.byte > edit.start_byte | ||
| || self.live.is_timeout_sensitive() | ||
| { |
There was a problem hiding this comment.
[P1] Rejecting only checkpoints that are currently timeout-sensitive does not make a persisted start_time safe. A checkpoint captured before a later heredoc has an empty queue, can sit in an editor for minutes, then restores the old Instant; when lexing reaches that heredoc, the wall-clock budget can expire immediately and diverge from a fresh lex. Make timeout/cancellation budget operation-local or deterministically charged, and add a delayed-restart control before persisting this state across generations.
…s' into agent/6982-stored-lexer-checkpoints # Conflicts: # crates/perl-parser/src/incremental/lex.rs # crates/perl-parser/tests/incremental_lexer_restart.rs
ecfe931 to
dd1afd0
Compare
5e2f54e to
5d2a13c
Compare
|
Read-only stale-PR preparation (live base fdfe5f1): disposition REPAIRABLE. The incremental checkpoint seam remains current, but unresolved authority risks include source/generation identity binding, delayed-restart timeout behavior, collision-safe identity, and large-source cost. Same-writer current-main repair plus focused falsifiers is required; no mutation was made. |
|
Disposition (campaign #11869 stale-queue sweep, 2026-08-21):
Idle >3h → reclaimable per umbrella #11869 queue policy. |
|
Disposition: REPAIR (campaign #11869 stale-PR sweep, 2026-08-21). Feature-complete lexer-checkpoint slice (+1758/-405) but CONFLICTING with moved incremental-parser code on main; 3 unresolved threads. Repair: rebase against current incremental code, CI replay, human review. Downstream #7332 is sequenced behind this. |
|
Disposition (campaign #11869 stale-queue sweep, 2026-08-22): |
Claim
The canonical incremental lexer path can now restore a complete behavior-bearing checkpoint without replaying the unchanged old-source prefix.
This PR is stacked on #6759 and targets
agent/6704-live-lexer-checkpoints. It preserves #6759’s conservative correctness rule: retain only the proven unchanged token prefix, re-lex the edited generation to EOF, and reuse zero old suffix tokens.What changed
StoredLexCheckpointrecords containing:perl_lexer::LexerCheckpointstate;#[cfg(test)];StoredCheckpointToEofand explicit receipt fields for:old_prefix_bytes_replayed;Correctness boundary
This PR does not reuse an old token suffix.
reused_suffix_tokensremains exactly zero. Exact suffix synchronization requires #6986’s complete-state equality, source mapping, and token-window proof.The current source/prefix fingerprint is an internal stable adapter. #4851 remains the canonical source/content identity owner; migration to its types must not weaken the generation check.
Validation
Hosted CI is authoritative for this connector-built stacked candidate. Focused commands:
Refs #6698
Refs #6704
Refs #6982
Refs #2021
Refs #2327