Files
Maven/docs/architecture/diagrams/02-core-internals.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

161 lines
5.6 KiB
Plaintext

%% View 2 — Core internals of mavend.
%% The real path, in the order runTurn actually runs it. The sequence is NOT
%% input → routing → intent → state → tools → response: eleven stateful
%% pre-emptors get first refusal BEFORE routing, and a query intent then enters
%% a second, longer arbitration of its own.
%% Evidence: cmd/mavend/voice.go runTurn, cmd/mavend/turnroute.go,
%% cmd/mavend/actions.go, cmd/mavend/actions_query.go, internal/router/router.go.
flowchart TB
subgraph IN["input — three reaches, one pipeline"]
A1["voice.Server<br/>HandlePushToTalk"]
A2["daemonAPI.Chat<br/>mavweb /api/chat"]
A3["telegram poller<br/>getUpdates"]
STT["stt seam<br/>Remote mavsttd · CW2 · Stub"]
end
A1 --> STT --> RT
A2 --> RT
A3 --> A2
RT["runTurn<br/>cmd/mavend/voice.go"]
RT --> D0["decision.With<br/>one arbitration record per turn"]
D0 --> TR0["turnRoute created<br/>sync.Once, on the context"]
subgraph PRE["pre-route ladder — 11 rungs, order load-bearing"]
direction TB
P1["1 expired-clarify notice"]
P2["2 confirm answer<br/>resolveConfirm"]
P3["3 targeted repair"]
P4["3b untargeted repair"]
P5["3c command prohibition"]
P6["4 clarify answer"]
P7["5 quiet toggle"]
P8["5b snooze"]
P9["5c ack"]
P10["5d reminder cancellation"]
P11["5e ordinal selection"]
P1-->P2-->P3-->P4-->P5-->P6-->P7-->P8-->P9-->P10-->P11
end
TR0 --> PRE
PRE -->|"any rung claims"| OUT
subgraph ROUTE["step 6 — the cascade · internal/router"]
direction TB
CONT["continuationDecision<br/>an elliptical follow-up is answered<br/>from the previous turn, not routed"]
S0["stage 0 grammars<br/>StageZeroGrammars · first match wins at 1.0<br/>the ONLY arm that may set SourceAnchored"]
SH["stage 0b routing heads<br/>ONNX softmax over the label set"]
SL["stage 1a LLM router<br/>resident model, grammar-constrained"]
SC["stage 1 classifier<br/>nearest centroid · THE FLOOR<br/>names no destination"]
SE["stage 2 extractor + stage 3 gate"]
CONT -->|"not a continuation"| S0
S0 -->|"no match"| SH
SH -->|"declines"| SL
SL -->|"error or unparsable"| SC
SH --> SE
SL --> SE
SC --> SE
end
PRE -->|"nobody claimed"| ROUTE
ROUTE --> DLG["step 7 dialogue merge<br/>followUpMerge · rememberTurn"]
DLG --> CLAR{"step 8<br/>dec.Clarify OR a required slot missing?"}
CLAR -->|"yes"| ASK["askClarify<br/>park the request, ask one question"]
ASK --> OUT
CLAR -->|"no"| ACT
subgraph ACT["step 9 — actionHandlers, 7 intents"]
direction TB
HF["fact<br/>actions_fact.go"]
HR["reminder<br/>actions_reminder.go"]
HA["act<br/>actions_act.go"]
HN["note"]
HC["chat"]
HS["system"]
HQ["query → the chain"]
end
subgraph QC["the query chain — a SECOND arbitration, 22 sources"]
direction TB
QW["queryWalk<br/>removes only guesses:true sources<br/>when the cascade named a destination"]
Q1["his data<br/>fact-by-key · day-plan · habits · tasks<br/>attention · list · money · history · feeds<br/>home · network · calendar · weather · self<br/>embed · memory · notes"]
QB["personal boundary<br/>the only source a stage 0 anchor may drop"]
Q2["the world<br/>search → kiwix → web → general-knowledge"]
QW --> Q1 --> QB --> Q2
end
HQ --> QC
HF -->|"question-shaped ⇒ re-route"| QC
HF -->|"complaint ⇒ re-route"| HC
subgraph STATE["state and memory"]
direction TB
DB[("store · sqlite<br/>facts · reminders · notes · tools<br/>tasks · lists · nudges")]
VEC[("memory_vectors<br/>brute-force cosine")]
DLGS[("dialogue_sessions<br/>persisted, TTL 2m")]
CLS["clarifyStore<br/>IN MEMORY ONLY, by design"]
PEND["pending act / routine / hexis<br/>3 single-slot registers, one mutex"]
SURF["surfacedItems<br/>last Praxis read-out order"]
RING["decision.Ring<br/>bounded, in memory"]
end
HF --> DB
HF --> VEC
HR --> DB
HN --> DB
HN --> VEC
Q1 --> DB
Q1 --> VEC
DLG --> DLGS
ASK --> CLS
HA --> PEND
QC --> SURF
D0 --> RING
subgraph TOOLS["act execution"]
direction TB
ALLOW[("tools table<br/>only status='enabled' runs")]
EXEC["tool.Executor<br/>+ MCP + Home Assistant callers"]
CONF["destructive confirm turn<br/>binds capability, entity, args, requester, expiry"]
HEX["Hexis capability<br/>entity id resolved via Nexus first"]
end
HA --> ALLOW --> EXEC
HA --> CONF
HA --> HEX
subgraph RESP["response generation"]
direction TB
REP["replier<br/>only when the handler returned \"\""]
PHR["phraser<br/>parseResponseMood is the one parser"]
TTS["tts seam<br/>Remote mavttsd · Stub"]
end
ACT --> RESP
QC --> RESP
REP --> PHR
OUT["reply text<br/>+ notice + resumed question"]
RESP --> OUT
OUT -->|"voice path only"| TTS
subgraph PROACT["the other half of the process — nothing above touches it"]
direction TB
TICKL["tick loop · 60s<br/>13 jobs in one function"]
GTH["loop.Gatherer<br/>one consistent snapshot"]
RUL["loop rules + restraint gate<br/>pure"]
DISP["delivery.Dispatcher<br/>ChannelsFor severity,presence"]
SNK["sinks: voice · ntfy · telegram"]
TICKL --> GTH --> RUL --> TICKL
TICKL --> DISP --> SNK
end
TICKL --> DB
SNK -->|"PushToMostRecent on the request conn"| A1
classDef stage fill:#1f3a5f,stroke:#7fb3ff,color:#eaf2ff
classDef store fill:#1f4a3a,stroke:#6ed0a8,color:#e8fff5
classDef mem fill:#4a3a1f,stroke:#e0b050,color:#fff6e0
classDef danger fill:#4f2626,stroke:#e08080,color:#ffecec
class S0,SH,SL,SC,SE,CONT stage
class DB,VEC,DLGS,ALLOW store
class CLS,PEND,SURF,RING mem
class QB,CONF danger