fix(project): reader keeps one commit per visit after an absent file (G-A2 follow-up) - #182
Conversation
…(G-A2 follow-up) Refs #180 (A1 and minors 1-4 of the second review of #181). - A 404 at a remembered commit is no longer proof the commit is gone. The commit is doubted only when its listing answers 404/422, or when the project file is 404 and nothing has been read at it in this visit (from the cache or the network). Any other 404 is an absent file. - Asking again is asked once per commit. The persisted memory is dropped only after GitHub has answered (that the ref is gone or moved), for that ref only (new dropResolved), and replaced by the answer otherwise. A refusal or timeout keeps the remembered commit for the visit. - When the commit does change the whole visit moves: listing, files and decoded JSON read at the old commit are forgotten, reads still on their way are read again at the new one, and readInfo names the commit in use. - forget(org, repo) bumps a per-repository generation, so a resolve that started before it does not write its commit back. - Cache guard: the first call's wait (1500 ms) no longer turns the cache off for good. The calls after it answer empty at once, the opening has its own limit (5 s), and an answer within it switches the cache back on. The deletion of remembered answers is attempted even when the cache is off. - Raw refused and the mirror 404 at a pinned commit: an optional file is absent for this visit, not kept; the project file and unversioned reads keep the error. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… follow-up) Refs #180 (minor 6 of the second review of #181). - toGithubRepo no longer falls back to 'main' when GitHub's payload has no default_branch: the repository is incomplete. requireGithubRepo throws a GithubRepoError saying what GitHub did not return; createRepo and the project creation use it, and the new project form shows its message. (listRepos leaves out a repository it cannot commit to.) - DatatugStoreGithubService.getProjectSummary: the defer around getRawJson was redundant (the reader's observable is lazy and a failed read is read again by the next subscriber); the existing S2 test, which fails the project file once and then recovers, passes without it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
[review r1 #182] Adversarial review (Opus): 450 targeted tests, 54 mutations (47 killed), probes Q1-Q10 on an export of this head and of main. Reviewed-Head: 4ea3f69 A1 as reported is fixed, trust is intact, the Major
Minors
Judgement call (a), project file error when raw is refused and the mirror says 404: correct. VERDICT: blockers=0 majors=1 minors=8 land=no 🤖 Generated with Claude Code |
…182) Fix round on the review of #182 (M1, minors 1-5, 7, 8). Paths under libs/datatug/main/src/lib/services/repo/. - M1: a read that completes while "which commit?" is being asked is not delivered at the old commit. loadText and loadTree share readAtCommit, which waits for a pending doubt of the commit it read at (bounded by the 5 s resolve timeout) before the epoch check, and reads again if the visit moved. readInfo waits for the doubt too, so it never names a commit that is about to be replaced. - Minor 1: the project file being 404 at a remembered commit is always doubted (one API call; the same commit named again means the project is absent and the commit stands, asked once per commit). The "confirmed" commits bookkeeping is gone: a project pushed from elsewhere into a repo already viewed opens on the first try. - Minor 2: a gone commit (listing 404/422) whose re-resolve is refused or times out fails the listing read with the refused-listing error (rate limit) or the read error, never []; an unanswered doubt is not memoised, so a later read in the visit asks again and recovers. No fallback to HEAD. - Minor 4: a read at the old commit that fails after the visit moved is read again at the new one (bounded). - Minor 5: the wait of a cache call that began before the cache was proven no longer turns a proven cache off. - Minor 3 (second half): DatatugStoreGithubService keeps each cached summary with the reader's new read-only visitEpoch(projectId) and reads again when it changed (the visit moved, or the repository was forgotten). - Minor 7: tests pin that a re-resolved commit is not remembered. - Minor 8: an old-commit read after the move no longer sets mirrorUsed. Left as they are: minor 3 first half (a gone commit undetected while both the project file and the listing are cached, for at most the memo's 5 minutes) and minor 6 (slow device: memo and listing not kept across visits when the database opens late). The cache database's version and schema are unchanged. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
[fix r1 #182] Fix round for review r1, head M1. Minor 1. The project file 404 at a remembered commit is doubted whenever the commit is remembered. The Minor 2. Minor 4. Minor 5. Minor 3, second half. New read-only Minor 7. Test "a re-resolved commit is not marked as remembered" (a 404 of the project file at the commit GitHub named is not asked about again): fails with R32. Minor 8. API calls, from tests ( Left as they are, as agreed: minor 3 first half (a gone commit undetected while both the project file and the listing are cached, for at most the memo's 5 minutes) and minor 6 (slow device: memo and listing not kept across visits when the database opens late). The cache database's version and schema are unchanged. Trust is unchanged: after any re-resolve the commit comes only from the API's answer for the ref. One limit of M1 worth knowing: a read that completes at X before any question about X has been asked (for example a cache hit that finishes before the project file's 404 arrives) is delivered at X, as before; the fix covers reads that complete while the question is pending, as the review asked. Checks run locally: targeted specs for 🤖 Generated with Claude Code |
|
[review r2 #182] Second review (Opus): all earlier probes (P1-P12, Q1-Q10), seven new ones, a comparison on main, 26 mutations on the delta (25 killed), 393 targeted tests. Reviewed-Head: e37de9a M1 and the minors that were to be fixed are fixed; trust, the Minors, tracked on #180:
Not verified: a real browser (ordering of IndexedDB against the network is inferred from the call order with gated fakes). VERDICT: blockers=0 majors=0 minors=7 land=yes 🤖 Generated with Claude Code |
Refs #180. Closes the follow-ups of the second review of the GitHub project reader (G-A2, #181, review comment 5961426685): A1 and minors 1 to 4 and 6. Paths are under
libs/datatug/main/src/lib/services/repo/.A1: a 404 at a remembered commit is an absent file, not proof the commit is gone
github/github-project-reader.service.ts:563doubtedByProjectFile,:895-922(file) and:734(listing): a remembered commit is doubted only when its listing answers 404/422, or when the project file is 404 and nothing has been read at the commit in this visit (confirmed, set at:453by a cache hit with text, a file or a listing from the network). A 404 for any other file at a remembered commit is an absent file (and is remembered as absent, so a warm visit costs no API call, new absent files included).:576doubt/:588askAgain: asking again happens once per commit (memoised, whoever doubts it). If GitHub names another commit the visit moves; if it names the same one the commit stands (and is no longer "remembered"); if the call is refused or times out the remembered commit is kept for the visit and the 404 is absent, nothing persisted.:504-552resolveCommit: the persisted memory is no longer deleted before asking. It is replaced by the answer, or dropped (:549, for that ref only, newdropResolved) once GitHub has answered that the ref is gone or the repository moved.:609moveTo: on a change the whole visit moves: the listing, files and decoded JSON read at the old commit are forgotten,readInforeports the commit in use, and reads still on their way (epoch,:675loadTree,:825loadText) are read again at the new commit when they come back. One visit never serves two commits.commits/HEAD(or the ref) on the API; a trusted project's commit comes from nowhere else.Fix too
github/github-file-store-api.ts:96,119: the first call (chunk load and database open) no longer turns the cache off for good after 1500 ms. Reads still go on from the network after 1500 ms; the calls after it answer empty at once (not one wait each); the opening has its own named limitGITHUB_STORE_OPEN_TIMEOUT_MS(5 s), and an answer within it switches the cache back on for later calls. A late answer is never applied to a read that already completed. A store that had answered and then hangs is still off for the visit.forgetrace,github-project-reader.service.ts:464,475,539: a per-repository generation; a resolve that began beforeforgetdoes not write its commit back. With the cache off or pausedforget(anddropResolved) still attempt the persisted delete, with the same wait (github-file-store-api.ts, thethroughcalls).dropResolved(key)on the store (github-file-store-api.ts:41,github-file-store.ts:311). Tested with two refs.github-project-reader.service.ts:902): an optional file is absent for this visit, not persisted; the error naming both hosts stays for unversioned reads (HEAD). Decision to check: the project file keeps the error at a pinned commit too, because a lagging mirror is most likely to be missing exactly the project just created, and "No DataTug project here" would be the wrong answer for a retry-able failure.resolve(true)becomesresolve(false)(12 tests). The redundantdeferindatatug-store.service.github.ts:73is removed: the reader's observable is lazy and the existing S2 test (project file fails once, then recovers) passes without it.github/github-api.ts:54,77andnew-project/new-project-form.component.ts:255,291: no fallback to'main'when the payload has nodefault_branch;toGithubRepotreats it as incomplete,requireGithubRepothrows aGithubRepoErrorsaying what GitHub did not return, and the create form shows its message (repository just created, or chosen repository).listReposleaves out a repository it cannot commit to.Left as it is: a repository with no project file costs one API call per page load (the project file is the one 404 that asks again; accepted in the review).
Tests
New
github/github-project-reader.followup.spec.ts(34 tests), written first and failing onmain: the reviewer's two sequences; the push mid-visit with an absent file probed (also added to the existing commit spec); a gone commit (listing 422) recovering with one re-resolve; five absent optional files at no API call on a warm visit; refused and timed-out re-resolves; the whole-visit move including reads on their way; ref-only drop;forgetrace; slow cache. Guard, store, create-service, form,github-apiand repos-service specs extended or added. Two existing M7 tests were changed on purpose (an absent non-project file no longer asks again; a refused re-resolve keeps the remembered commit instead of degrading toHEAD). 35 mutations of the reader and the guard were run; 8 survived the first round, 6 got a test and 2 were removed as redundant code (a second epoch check on decoded JSON, a repeated doubt test); the 33 that remain are all killed.API calls (fake GitHub): cold visit 2 (commit, listing); warm within 5 minutes 0, absent files included; warm after 5 minutes 1 (the question); changed project 2; five new absent files on a warm visit within 5 minutes 0 API calls (5 file-host reads, then 0).
No change to the chat IndexedDB (still version 2) or to the cache database's version or schema.
🤖 Generated with Claude Code