0.0.10 review: the cache fixes a pre-release deep review found - #40
Merged
Merged
Conversation
Four would-take-live-data defects and their kin, all found by the pre-release review of PR #39, all fixed with tests: - the lease tick renamed a 0.0.9 guest's instance directory aside with no grace at all (only sweep_instances had the grace check), so a 0.0.10 owner took a live 0.0.9 guest's cache within a tick; rename_dead_instances now gives an undescribed directory the same grace the sweep does (P0-1) - reset_cache deleted the resetting instance's own instance.json -- the heartbeat that says it is alive -- leaving a rebuilding guest reapable for up to a renewal interval; the file survives a reset like owner.lease (P0-2) - mcppls.sweepCache and a stale cxxModules/cache walked the whole cache tree on the session's event loop: minutes of filesystem work held every request and the lease's own renewal behind it (a blocked owner loses its lease); the sweep is prepared on the loop, run on a thread, answered by an event (the exportBundle pattern), and a stale report answers from the last snapshot while a refresh runs off the loop (S3-5.7-8, S3-5.8-10) - owner_gone read an unreadable process identity (another user's process on Windows, a failed ps on macOS) as a dead owner and let a live lease be taken over; only a definite answer -- another incarnation, or a pid the platform says is gone -- releases a lease early (P0-4) - every cache pass, background or interactive, is single-flight with coalescing (a crash-looping engine used to start one full pass per restart) - generationStartedAt_ resets when clangd exits, so staleCommands sweeps are possible again after a crash instead of never - a heartbeat ahead of this clock (NTP step, waking from sleep) is alive within the window; parse_bytes consumes its input whole ('1.5G' silently meant 1G) and a budget that does not parse is logged, not silent - what a sweep counts freed is what left the disk (staleCommands counted attempted bytes into files; the CLI --prune did the same) - a dry run changes nothing the server remembers (it used to write lastSweep, so a preview read as a sweep that happened) - a multi-root sweep answers with the sum over its roots (the last root's answer used to overwrite the others') - the card's Open logs link opens the logs directory (it opened the cache root); the sweep receipt reads sizes the way a person does; ps(1) runs under LC_ALL=C on macOS so a lease reads the same spelling it was written with; KINDS carries a static_assert and a bounds guard Tests: the renamed-aside test now covers fresh-undescribed (kept), stale- described and past-grace (renamed); a heartbeat in the future is alive within the window; parse_bytes rejects partial input; lease_owner_gone is exported and covered; the card test pins the logs argument; the receipt test pins the human-readable size. Server suites dev and release, validate (296 rules), 114 extension units, E2E 40/0/1 in source and VSIX mode, and the windows/macos cross builds all pass.
sweepPendingReportOnly_ never reset, so a coalesced report-only refresh always retriggered as a removal pass -- safe (every pass refreshes the report too) but not what the latch said. It starts neutral now and resets when the batch is consumed.
The real-use check of the verify window: the table's bars were a touch short, so the bar column read as a strip tucked at the table's end instead of carrying its share of the width band the footer sets. 14 cells now (was 12) -- the class rows and the total row read as one even block, the right edge falling where the footer's does.
The person's pick from the verify window: 13 cells for the en table, and the two languages adapted separately. The cells now come from the columns the card itself shows -- the labels and the total row's 'bytes / limit' -- so the en table lands on 13 and the zh one, its words narrower around the same Latin sizes, runs its bars a cell or two longer: both tables close on the same right edge as the footer, one scale a card (the rows, the total row and the preparation line share it, nothing jitters as numbers change width). Clamped to 12..20 so no card ever renders an absurd strip. A test holds the property: en 13, zh longer, both tables within one column of the same band.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #39 (already squash-merged as eaf9ea4, not yet released). A pre-release deep review of the 0.0.10 cache work found four P0 defects that could take a live instance's data or block the session loop, plus their kin. All verified against the code before fixing, all covered by tests, all local gates green.
P0 — fixed
P0-1 A 0.0.10 owner renamed a live 0.0.9 guest's cache aside.
rename_dead_instanceshad no grace branch for a directory withoutinstance.json(onlysweep_instancesdid), so the tick renamed a fresh 0.0.9 leftover on its next 10s pass and the background pass then removed it — the old test asserted exactly this. Rename now gives an undescribed directory the same grace (newest_modified) the sweep does.P0-2
resetCachedeleted the resetting instance's owninstance.json— the heartbeat that says the directory is alive; the comment claimed the opposite of what the code did. It survives a reset now, likeowner.lease.P0-3
mcppls.sweepCacheand a stalecxxModules/cacheran whole-tree walks on the session's event loop. Minutes of filesystem work (the 64 GiB case) held every request and the lease renewal behind it — a blocked owner loses its lease to a new instance. The sweep is now prepared on the loop (prepare_sweep), run on a thread as plain data (run_prepared_sweep), and answered through adeferred_answerevent (the exportBundle F18 pattern); a stale report answers the last snapshot while a report-only pass refreshes it off the loop (S3-5.7-8, S3-5.8-10).P0-4 An unreadable process identity read as a dead lease owner.
owner_gonetreatedprocess_identity == nullopt(OpenProcess access-denied on Windows, a failedpson macOS) as gone, so a live owner's lease could be taken over. Only a definite answer releases a lease early: a different incarnation, or a pidprocess_alivesays is gone;lease_owner_goneis exported and unit-tested.P1 — fixed
generationStartedAt_resets when clangd exits (staleCommandswas unreachable after any crash)parse_bytesconsumes its input whole (1.5Gsilently meant1G,12abcGmeant12G); a budget that does not parse is loggedcache.maxBytes's summary now says what it does (reporting; eviction answers tocache.totalBytes)--prunecount what left the disk (tree_remove), not what they attemptedlastSweep, so a preview read as a sweep)P2 — fixed
report refresh renders prompts once from one facts object; enforce_budget walks each workspace once (was two full walks); the card's Open logs opens the logs directory (was the cache root); the receipt reads human sizes (
sizeText);psruns underLC_ALL=Con macOS; KINDS has a static_assert and a bounds guard.Verification
validate.py: 296 rules, 0 failures (new rules S3-5.7-8, S3-5.8-9..12 with evidence)cxxModules/cache) — fixed before push