bae81b66c8
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>
116 lines
5.2 KiB
Plaintext
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
|