refactor(lsp): version-tagged _DocState replaces timestamp freshness tracking

The staleness fix (f9b1fd799) bolted two wall-clock dicts (_changed_at,
_pulled_at) onto a client that already scattered per-document state
across six parallel dicts (_files, _push_diagnostics, _pull_diagnostics,
_published, _published_version, _first_push_seen) — eight maps kept in
sync by hand.

Collapse all of it into one _DocState per path, and use the LSP document
version as the freshness token instead of clocks:

- didChange bumps doc.version; stored push/pull results carry the
  version they describe (push_version from the server's echoed version,
  or the current version at receipt for servers that don't echo one;
  pull_version captured at request send so an in-flight pull that a
  didChange races past is stale on arrival).
- fresh == tag >= version. Invalidation is implicit in the bump — no
  store-clearing, no clock comparisons, no race windows.
- _has_fresh_push/_has_fresh_pull helpers dissolve into two one-line
  _DocState methods; diagnostics_for(fresh_only=True) becomes a
  three-liner.

Semantics are unchanged from f9b1fd799 (same tests pass, one test
updated off private internals); net -15 lines.
This commit is contained in:
ethernet 2026-07-17 15:01:43 -04:00
parent a632e68a01
commit eb09df6ec8
2 changed files with 114 additions and 129 deletions

View file

@ -146,8 +146,8 @@ async def test_wait_timeout_param_overrides_mode_budget(tmp_path: Path):
@pytest.mark.asyncio
async def test_stale_pull_result_dropped_when_change_races(tmp_path: Path):
"""A pull answered for pre-edit content must not be stored after a
didChange raced past it (send-time anchoring)."""
"""A pull answered for pre-edit content must not read as fresh after
a didChange raced past it (version-tag anchoring)."""
f = tmp_path / "x.py"
f.write_text("bad code\n")
@ -156,13 +156,15 @@ async def test_stale_pull_result_dropped_when_change_races(tmp_path: Path):
try:
v0 = await client.open_file(str(f), language_id="python")
await client.wait_for_diagnostics(str(f), v0, mode="document", timeout=2.0)
assert client._has_fresh_pull(os.path.abspath(str(f)))
doc = client._docs[os.path.abspath(str(f))]
assert doc.fresh_pull()
# Simulate an edit racing in: the change invalidates the pull.
# Simulate an edit racing in: the version bump invalidates the
# stored pull without any explicit clearing.
f.write_text("good code\n")
await client.open_file(str(f), language_id="python")
assert not client._has_fresh_pull(os.path.abspath(str(f)))
assert os.path.abspath(str(f)) not in client._pull_diagnostics
assert not doc.fresh_pull()
assert client.diagnostics_for(str(f), fresh_only=True) == []
finally:
await client.shutdown()