fix(server): answer the editor's polls from bodies cached under a stat stamp #359
No reviewers
Labels
No labels
bug
enhancement
needs-triage
ready-for-agent
ready-for-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/deckle!359
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "afk/358"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #358
What changes
Server (
internal/server/derived.go,internal/gitrepo/stamp.go)Handler.derived(key, compute)is the one owner of "is the derived state current".GET /api/tree,/api/badgesand/api/publish/pendingcompute their body through it.ServeHTTPformutatingRoutes, andrunPublishJob;git.State()andSyncStatus().Tip, both held in memory;Repo.RefsStamp(), a stat ofHEAD,packed-refs, the reftable list and the loose main/draft refs, with no git spawn and nor.mu;content/,assets/media/,editor/, the root Hugo config files (pagetree.PathRulesFiles) and.gitignore.git diffrewrites it.server.New, so nothing is cached at that point./api/statusis untouched.docs/api.mdis unchanged.SPA (
web/src/poll.ts)singleFlight(run)returns{tick, now}:tickis skipped while the previous request is still pending;now(a mutation's refetch, a language or page change) always goes out.createPageTree(tree plus badges count as one unit),createPageLocks,createHugoStatus, both publish loops, andcreateModules, which loses its private copy of the guard.Docs
docs/architecture.md"Server" gains a paragraph on this.docs/adr/0030-polls-answer-from-bodies-cached-under-a-stat-stamp.mdrecords the stat walk over an inotify watcher, a directories-only walk and invalidation on mutation alone.Verification
make testis green: 3465 web tests and every Go package.go vetandgofmtare clean.-racepasses onserverandgitrepo.New Go tests:
TestPollHandlersGoThroughDerived(the single owner);TestPollsReuseUnchangedState(the second poll computes nothing; 8 concurrent cold requests compute once);TestSaveReflectedInNextPoll;TestHandEditReflectedInNextPoll(an in-place same-size edit, a new page directory, a hand-run commit);TestPublishReflectedInNextPoll;RefsStamptests.New web tests in
web/src/test/pollGuard.test.ts: a fetch that never resolves leaves at most one request in flight per loop.Benchmarks are in
internal/server/polls_bench_test.go(2,574 pages; dev machine):End to end against a real
harness servepinned withtaskset -c 0(2,500 bundles undernews/, 5,660 entries undercontent/):/api/badges/proc/<pid>/io); no git child/api/statusduring a cold badge computation on the same coresedof a title, and a new page directoryKnown trade-offs
git rm --cached, shows at the next mutation or content change, not the next poll.GET /api/page, a mutating route because it can repair uids) outdates the cache once.🤖 Generated with Claude Code
[autoland] verdict: pass
PASS — validated by the autoland lander.
Signal relied on:
ci / build-and-testsuccess on head392da49(webnpm ci && npm run build && npm test,go vet ./...,go test ./...including the docs, route, command and skills drift tests). gofmt checked locally on the changed packages: clean.Conventions: Conventional Commits title;
Closes #358present; branch is current with main (merge-base = main tipd788dc6).Scope matches #358: one owner
Handler.derived(internal/server/derived.go) for tree/badges/pending; generation bumped at the end of every mutMu scope (server.go ServeHTTP, publish.go runPublishJob including the panic path); the startup sync runs before server.New (cmd/harness/main.go:369 vs :390); the fingerprint covers content/, assets/media (= gitrepo publishRoots), editor/ (elements/pagetypes/modules dirs), the root Hugo config via the new pagetree.PathRulesFiles owner, and .gitignore; RefsStamp spawns no git. SPA loops go through singleFlight (web/src/poll.ts); modules.ts drops its private copy. Docs: architecture.md "Server" paragraph plus ADR 0030; api.md, AGENTS.md and the skills are correctly untouched (no wire, command or contract change). The edits to existing web tests only let the previous request settle before advancing timers, which the new guard requires; no existing Go endpoint test was edited.