shutdown: close the sockets, or the database never gets sealed
mavend seals its encrypted database in `defer st.Close()` when run() returns. It had not returned since 2026-07-21. Every restart since then decrypted the same eleven-day-old ciphertext and rolled back everything written in between: the Telegram nudge that kept firing was a fact being un-written on each boot. The goroutine dump named it. main → srv.Close() → ipc.(*Server).Close → wg.Wait(), waiting on per-connection goroutines parked in readFrame. Close shut the listener and nothing else, so the idle persistent sockets held by mavweb, mavpoll, mavcaldav and mavmaild blocked shutdown forever. `docker compose stop -t 60` spent the whole sixty seconds and then took a SIGKILL. So: track the accepted conns and close them, in ipc and in voice, which had the identical defect. Bound all three waits — the two per-server ones and the worker wait in main — because the seal matters more than any single in-flight call. A dropped RPC costs one reply; a missed seal costs a session. The regression test leaves a client connected and idle, which is the case the old tests avoided by closing the client first. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TrVSBKe3RFDF4fGYKWYQnX
This commit is contained in:
+120
@@ -0,0 +1,120 @@
|
||||
# Handoff
|
||||
|
||||
Uncommitted scratch file. Delete it once the work below is finished.
|
||||
|
||||
Written 2026-08-01. Kami is away for about an hour and will start a new session.
|
||||
|
||||
## Where things stand
|
||||
|
||||
The 35-PR stack (50 to 84 on gitea, one linear chain) has been reviewed and the
|
||||
findings have been fixed. Two things are done and one is not.
|
||||
|
||||
**Done: reviews.** One review posted on every PR from 50 to 84, as the `claude`
|
||||
login. Review ids 58 to 92.
|
||||
|
||||
**Done: fixes.** Eleven agents fixed the findings in parallel git worktrees.
|
||||
All eleven branches are merged onto **`fix/integrated`**, which is 68 commits
|
||||
ahead of the tip. `make test` and `make build` both pass on it.
|
||||
|
||||
**Not done: landing them.** `overnight/eco-versioned-traces` (the stack tip) has
|
||||
NOT been moved. Kami chose to land the fixes as commits on that tip. The final
|
||||
step is a fast-forward, once he has answered the open questions below.
|
||||
|
||||
git checkout overnight/eco-versioned-traces
|
||||
git merge --ff-only fix/integrated
|
||||
|
||||
Do not push. He merges the stack himself.
|
||||
|
||||
## Ask him these first
|
||||
|
||||
He asked for the list and then left, so none of it is answered. Nothing below
|
||||
is a blocker for the fast-forward, but all of it is easier to change before the
|
||||
tip moves than after.
|
||||
|
||||
1. **Hexis refuses to wire when a token is configured.** It used to log once and
|
||||
then call unauthenticated forever. Fail closed, or warn and continue?
|
||||
2. **`MethodIngestMail` stayed at `AuthRead`** while `SetTaskStatus` moved to
|
||||
`AuthWrite`. Those two now disagree about the same kind of question.
|
||||
3. **"Прости" in `clarifyGaveUp` and one expiry variant.** `CheckCringe` bans
|
||||
apologies. The fix scoped the ban to nudges and kept his wording, with the
|
||||
reasoning in a test skip. Absolute ban is the other reading.
|
||||
4. **Memory evaluation timeout is 60s.** Two agents disagreed here. The merge
|
||||
kept the short budget plus the gate that yields the slot to voice turns. Five
|
||||
minutes is safe again now that the gate exists.
|
||||
5. **Cold-start v1 recovery is narrow.** It fires only when an assertion carries
|
||||
a PRF secret and that unlock fails. A pre-existing box whose only
|
||||
authenticator lacks PRF still needs `MAVEN_DB_KEY`.
|
||||
|
||||
## Two things to know before deploy
|
||||
|
||||
**The update block.** The self-update fix refuses at startup any
|
||||
build-from-source deployment that cannot say how to undo the source.
|
||||
`deploy/mavend.json` has no `update` block today, so nothing breaks. Adding one
|
||||
for the docker layout without `source_rollback` will stop the daemon booting.
|
||||
That is intended. It should not be a surprise.
|
||||
|
||||
**Three migrations became four numbers.** Three agents each wrote a migration
|
||||
15. Tasks kept 15, ecosystem traces became 16, MCP tool fingerprints became 17.
|
||||
Any box already carrying an unreleased 15 from a worktree build needs its
|
||||
schema version checked by hand.
|
||||
|
||||
## Merge decisions already made
|
||||
|
||||
Two agents independently added `llm.Gate`. One is priority between a voice turn
|
||||
and background work. The other is admission control while the resident model is
|
||||
swapped. Both were kept. The swap one is now `SwapGate` with `SetSwapGate`.
|
||||
`Complete` takes priority first and the drain second, so a background request
|
||||
waiting on priority cannot stall a swap.
|
||||
|
||||
## Still open in the code, on purpose
|
||||
|
||||
- Ambient calendar events never reach the `calendar_busy` gate. `calendar_busy`
|
||||
is a level, so an ambient writer needs an expiry. Recorded as a comment at the
|
||||
top of `cmd/mavweb/ambient.go`.
|
||||
- Hands-free has no session-scoped voice assertion. Noted in the mavweb route
|
||||
table.
|
||||
- The Hexis capabilities call sends no correlation id. The vendored client has
|
||||
no header hook, so closing it means re-vendoring.
|
||||
- Re-running a stored audio blob by id does not exist. The comments that claimed
|
||||
the wire offered it were corrected.
|
||||
- Simulator persona checks read a Go constant on one step, because chat there
|
||||
goes through `phraser.NewStub()` rather than the replier.
|
||||
- The PRF value is client-supplied and unbound to the assertion signature. This
|
||||
is inherent to PRF key wrapping, which needs a fixed salt. Documented in
|
||||
`cmd/mavweb/webauthn.go`. Do not try to bind it.
|
||||
- `safeKey` drops Cyrillic, so Russian calendar events on one day collide. Filed
|
||||
as Vikunja #443 with three fix options. It is a migration, not a patch.
|
||||
|
||||
## The one task left
|
||||
|
||||
Audit what the agents filed in Vikunja. They created QA tasks on their own
|
||||
initiative, which nobody asked them to do. Kami saw them and said some are new
|
||||
bugs worth a later sweep. Dedupe against existing tasks, and separate genuine
|
||||
new bugs from restatements of findings the commits already fixed. That produces
|
||||
the second sweep list without re-reading 35 PRs.
|
||||
|
||||
## Recipes
|
||||
|
||||
Gitea is `https://gitea.kvmx.ru`, repo `kami/Maven`. Tokens are in
|
||||
`~/.config/tea/config.yml`: the `homesrv` login reads, the `claude` login posts.
|
||||
`tea` cannot list review comments, so use the REST API.
|
||||
|
||||
Read the reviews for one PR:
|
||||
|
||||
curl -s -H "Authorization: token <homesrv-token>" \
|
||||
"https://gitea.kvmx.ru/api/v1/repos/kami/Maven/pulls/<n>/reviews"
|
||||
|
||||
Do not fetch `/issues/comments` without a `since` filter. It returns 50 stale
|
||||
comments from a superseded stack.
|
||||
|
||||
The scratchpad from this session holds `RECIPE.md` (how the reviews were done),
|
||||
`FIXBRIEF.md` (how the fixes were done) and `postreview.sh`. Worktrees are under
|
||||
`scratchpad/wt/g01` to `g11` and can be removed with `git worktree remove` once
|
||||
the tip has moved.
|
||||
|
||||
## Constraints that do not change
|
||||
|
||||
Read `CLAUDE.md`. Maven is feminine and calls him "ты". The eval enforces both.
|
||||
Not a nag, not autonomous. No telemetry, no cloud model, no third-party account.
|
||||
His notes and facts are never search input. Use `make`, never bare `go build` on
|
||||
a CGO daemon.
|
||||
Reference in New Issue
Block a user