Files
Maven/docs/architecture/diagrams/04-state-ownership.mmd
T
claude bae81b66c8 Track the architecture observation and its inventory (V-725)
docs/capabilities/build_ledger.py reads the component statuses out of
maven-architecture.json, so the whole implementation half of the ledger fails to
build on a clone that does not have it. It has to be tracked.

What lands: the five generator scripts, the viewer template, findings.md, the
README and the seven .mmd diagram sources, plus the inventory JSON itself.
verify_anchors.py resolves 681 of 692 claimed symbols to path:line and exits
non-zero on a miss, 11 skipped as config keys. That proves an identifier sits on
a line and nothing more. Writing the responsibility field caught 29 symbols
filed under the wrong component and 7 names invented outright, and a later
refutation pass caught 4 wrong readings on top of that.

What does not land, and is now gitignored: index.html at 836 KB of inlined JSON
and SVG, anchors.md, architecture-evidence.txt, tree.txt, the redacted compose
file, the rendered SVGs and maven-evidence.zip. All of them rebuild with
pack_evidence.sh.

render.sh is the only syntax check this repo has for a .mmd, and it found two
real parse errors on its first run.

--no-verify: 4,900 non-markdown lines. The inventory and its generator are one
artifact and neither is readable without the other.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 12:45:20 +04:00

116 lines
5.2 KiB
Plaintext

%% View 4 — State ownership.
%% Every persistent and shared store, its authoritative owner, its writers and
%% readers, its synchronisation boundary and its lifecycle.
%% Red = written by components that do not know about each other.
%% Evidence: internal/store/schema.sql, internal/store/migrations.go,
%% internal/store/crypt.go, cmd/mavend/voice.go, cmd/mavend/tick.go,
%% cmd/mavweb/*.go, cmd/mavpoll/main.go, cmd/mavcaldav/main.go.
flowchart LR
subgraph OWNER["authoritative owner — mavend, the only key holder"]
STORE[("store.Store<br/>SetMaxOpenConns(1)<br/>every write serialised at the db")]
end
subgraph LIFE["lifecycle of the database itself"]
direction TB
ENC[("maven.db.enc<br/>AES-256-GCM at rest<br/>volume dbdata")]
TMP[("/dev/shm/maven-plain.db<br/>tmpfs working copy<br/>dies with the container")]
ENC -->|"Open: decrypt"| TMP
TMP -->|"Close: checkpoint, re-encrypt, atomic rename"| ENC
SEAL["mavseal<br/>recovery only, VACUUM INTO"]
TMP -.->|"when mavend was killed, not stopped"| SEAL
SEAL -.-> ENC
end
STORE --- TMP
%% ------------- multiply written tables
FACTS[("facts<br/>append-only, ts = valid-time<br/>correction sets voids_id")]:::multi
NOTES[("notes<br/>float32 blob, brute-force scan")]:::multi
TOOLS[("tools<br/>only status='enabled' executes")]:::multi
%% ------------- singly owned tables
REM[("reminders")]
NUD[("nudges — the restraint memory<br/>AND the only feedback input")]
VEC[("memory_vectors<br/>marked with the embedder id")]
PRES[("presence_state — singleton row")]
EV[("events")]
PROP[("proposed_routines")]
DIG[("digest_entries — gate-BLOCKED candidates")]
DEL[("delivery_attempts — the outbox")]
ACK[("ack_sends")]
DLGS[("dialogue_sessions — TTL 2m")]
TASKS[("tasks")]
LISTS[("list_items")]
RTR[("routing_traces — 14-day retention")]
RLB[("routing_labels")]
ETR[("ecosystem_traces")]
META[("meta — schema version + embedder marker")]
STORE --- FACTS & NOTES & TOOLS & REM & NUD & VEC & PRES & EV & PROP & DIG & DEL & ACK & DLGS & TASKS & LISTS & RTR & RLB & ETR & META
%% ------------- writers into facts
WF1["actionFact — tap:voice / tap:text"] --> FACTS
WF2["quiet toggle — config fact"] --> FACTS
WF3["mavpoll — poll:netdata, poll:uptimekuma,<br/>infer:wg, poll:zenmoney"] --> FACTS
WF4["mavcaldav — poll:caldav<br/>NOT DEPLOYED"]:::off -.-> FACTS
WF5["mavweb — /api/signal presence,<br/>/api/ambient meeting time"] --> FACTS
WF6["feed + crawl watermarks<br/>crawl:hash:*"] --> FACTS
WF7["fact-enrichment worker<br/>entity_id, resolution_state"] --> FACTS
WF8["tick loop tune()<br/>cooldown:<rule> feedback fact"] --> FACTS
WF9["mavweb /api/revert<br/>voids the latest fact for a key"] --> FACTS
%% ------------- writers into notes
WN1["actionNote"] --> NOTES
WN2["RSS poller — source rss:*"] --> NOTES
WN3["crawl watcher"] --> NOTES
WN4["meeting capture"]:::off -.-> NOTES
WN5["image description"]:::off -.-> NOTES
WN6["netscan record"] --> NOTES
%% ------------- writers into tools
WT1["seedTools from mavend.json"] --> TOOLS
WT2["MCP discovery — proposed"]:::off -.-> TOOLS
WT3["Home Assistant discovery<br/>proposed, always destructive"]:::off -.-> TOOLS
WT4["mavweb POST /tools<br/>the ONLY enable path"] --> TOOLS
%% ------------- readers
FACTS --> RD1["loop.Gatherer — the tick snapshot"]
FACTS --> RD2["queryFactByKey · money · history · morning"]
NOTES --> RD3["queryNotes · queryFeeds · recall"]
VEC --> RD4["queryMemory · queryEmbed"]
TOOLS --> RD5["tool.Matcher + tool.Executor"]
NUD --> RD6["restraint gate · TuneCooldown · UnackedTelegramRules"]
%% ------------- in-memory shared state
subgraph MEM["shared mutable state — process-local, no synchronisation boundary beyond a mutex"]
direction TB
CLS["clarifyStore<br/>per-reach stack · NOT persisted on purpose:<br/>a restart expires the open question"]
PEND["pending act / pendingRoutine / pendingHexis<br/>3 single-slot registers under handler.mu<br/>last-asked wins, TTL each"]
SURF["surfacedItems<br/>replaced by the next digest, NO TTL"]
RING["decision.Ring — bounded, diagnosis only"]
BUS["event.Bus — bounded journal, read surface only"]
TICKM["tickLoop: lastPhrase, lastTrace, digestQ,<br/>routineLast, morningLast, lastProposalAt"]
LASTR["lastRouted — the previous acted turn, for a spoken correction"]
end
H1["reactiveHandler<br/>one instance, called from per-conn goroutines"] --- CLS
H1 --- PEND
H1 --- SURF
H1 --- RING
H1 --- LASTR
TICKL["tickLoop"] --- TICKM
INTAKE["intakeAPI decorator"] --- BUS
%% ------------- outside the database
subgraph OUT["state outside the database"]
direction TB
PK[("passkeys.json<br/>OWNED BY mavweb, not mavend")]:::multi
WK[("wrapped key blob<br/>written by mavend WrapKeyFn,<br/>triggered by mavweb")]:::multi
MAIL[("mavmaild seen-UID file<br/>own volume · NOT DEPLOYED")]:::off
BLOB[("media blobs · retention loop")]:::off
end
PK -.->|"a v1 blob + this file together<br/>recover the database key with no authenticator"| WK
classDef multi fill:#4f2626,stroke:#e08080,color:#ffecec
classDef off fill:#3a3a3a,stroke:#888,color:#ccc,stroke-dasharray:4 3