Architecture Validation Report (2026-05-05)
Automated validation detected 3 invariant violations and 2 doc-drift items requiring attention.
Invariant Compliance
| # |
Invariant |
Status |
Details |
| 1 |
Three-Layer Backend: Router → Service → DB |
PASS |
pipe.execute() calls are Redis pipeline, not SQL. DB layer has no FastAPI imports. |
| 2 |
DB Layer: Class-per-domain with Mixin Composition |
PASS |
All db/*.py files define *Operations classes; all db/agent_settings/*.py define *Mixin classes. |
| 3 |
Schema in db/schema.py, Migrations in db/migrations.py |
PASS |
No CREATE TABLE found outside schema.py/migrations.py. |
| 4 |
Router Registration Order |
PASS |
/context-stats, /autonomy-status, /sync-health, /slots, /permissions-edges all registered before /{agent_name} catch-all. |
| 5 |
Agent Server Mirrors Backend (Subset) |
PASS |
Agent server has snapshot.py, trinity.py, info.py, activity.py, dashboard.py which are legitimate agent-internal-only routers (not required to have backend mirrors). |
| 6 |
Frontend: Store = Domain, View = Page |
PASS |
No views import api directly or make API calls via stores. |
| 7 |
Single API Client (api.js) |
FAIL |
20+ files bypass api.js singleton: stores (agents.js, auth.js, operatorQueue.js, monitoring.js, network.js, etc.) import raw axios with manual auth headers; views (AgentDetail.vue, ApiKeys.vue) use raw fetch() with manual Authorization headers. This means token refresh logic in api.js interceptors is skipped. |
| 8 |
Auth Pattern: Depends(get_current_user) + AuthorizedAgent |
FAIL |
51 inline raise HTTPException(status_code=403) calls across 19 router files (threshold: 5). internal.py correctly has no get_current_user. High-volume sites: agent_config.py (6 sites), avatar.py (5 sites), agent_files.py (3 sites), chat.py (2 sites), plus 14 more files. Authorization logic is duplicated across routers instead of being centralized in AuthorizedAgent/dependency factories. |
| 9 |
Channel Adapter ABC |
PASS |
adapters/base.py defines ChannelAdapter ABC. SlackAdapter, TelegramAdapter, and WhatsappAdapter all inherit from it. |
| 10 |
WebSocket Events for Real-Time |
WARN |
operatorQueue.js uses setInterval polling the /api/operator-queue REST endpoint every N seconds. HostTelemetry.vue polls /api/telemetry/host every 5000ms with raw fetch. websocket.js exists. These are minor exceptions (operator queue and host telemetry are not agent-state push events) but are noted. |
| 11 |
Docker as Source of Truth |
PASS |
No module-level container state dicts found. docker_service.py exists. |
| 12 |
Credentials: File Injection, Never Stored in DB |
PASS |
No credential values in schema.py tables. |
| 13 |
MCP Server = Third Surface in Sync |
PASS |
16 tool modules present. tags.ts is registered in server.ts but not exported from tools/index.ts (stale re-export index — minor). |
| 14 |
Pydantic Models Centralized in models.py |
FAIL |
71 Pydantic BaseModel class definitions found scattered across router files (audit_log.py, fan_out.py, git.py, internal.py, avatar.py, event_subscriptions.py, image_generation.py, logs.py, messages.py, and more). These should live in models.py. |
| 15 |
API URL Nesting Convention |
PASS |
Agent-scoped resources correctly nest under /api/agents/{name}/. |
Result: 11/15 PASS, 3/15 FAIL, 1/15 WARN
Violations
INV-8 (P1): Auth Sprawl — Inline Authorization in 19 Router Files (51 sites)
51 raise HTTPException(status_code=403) calls spread across 19 router files including agent_config.py, avatar.py, chat.py, logs.py, sharing.py, slack.py, operator_queue.py, settings.py, system_agent.py, system_views.py, whatsapp.py, and more.
Fix: Consolidate into AuthorizedAgent, OwnedAgentByName, or require_role() dependencies in dependencies.py. Each new inline auth check increases the attack surface for auth bypass and makes auditing harder.
INV-7 (P1): API Client Fragmentation — Raw axios and fetch Bypass api.js
20+ frontend files import axios directly or use fetch() instead of the api.js Axios singleton that handles token refresh and auth interceptors:
- Stores:
agents.js, auth.js, operatorQueue.js, monitoring.js, observability.js, network.js, settings.js, notifications.js, systemViews.js
- Components:
ChatPanel.vue, PlaybooksPanel.vue, PublicLinksPanel.vue, SkillsPanel.vue, CreateAgentModal.vue, NavBar.vue, HostTelemetry.vue (raw fetch)
- Views:
AgentDetail.vue (raw fetch for autonomy, read-only, rename endpoints), ApiKeys.vue (raw fetch for all MCP key operations)
Fix: Migrate all API calls to import and use the api singleton from src/api.js.
INV-14 (P1): Pydantic Model Sprawl — 71 Models Outside models.py
71 BaseModel class definitions found in router files. Significant violators: fan_out.py (4 models), git.py (5 models), internal.py (5 models), audit_log.py (4 models), logs.py (2 models).
Fix: Move all request/response models to src/backend/models.py and import from there.
Doc Drift — Suggested architecture.md Edits
| Item |
Doc Claims |
Actual |
Action |
| D1: Service module count |
"37 service modules" |
47 modules |
Update to 47; document 10 undocumented services: fan_out_service, fleet_audit_service, gemini_voice, github_pat_propagation_service, platform_audit_service, platform_prompt_service, pre_check_service, subscription_auto_switch, upload_service, validation_service, ws_ticket_service, sync_waiter, telegram_media |
| D1: Router module count |
"53 router modules" |
52 modules |
Update to 52 |
| D1: MCP tool count |
"62 tools" (CLAUDE.md) |
73 tools |
Update to 73; chat.ts has 4 tools (doc says 3 — fan_out is undocumented) |
D1: agents.py line count |
"642 lines" |
799 lines |
Update to ~800 lines |
D1: main.py reference |
(implicit) |
973 lines |
No claim to update, but doc says "300+ endpoints across 40+ routers" — routers is now 52 |
D2: audit_retention_service |
Listed in Background Services table but missing from Services module list |
Exists as active service |
Add to Services section |
D2: sync_health_service |
Listed in Background Services table but missing from Services module list |
Exists as active service |
Add to Services section |
Architecture Validation Report (2026-05-05)
Automated validation detected 3 invariant violations and 2 doc-drift items requiring attention.
Invariant Compliance
pipe.execute()calls are Redis pipeline, not SQL. DB layer has no FastAPI imports.db/*.pyfiles define*Operationsclasses; alldb/agent_settings/*.pydefine*Mixinclasses.db/schema.py, Migrations indb/migrations.pyCREATE TABLEfound outsideschema.py/migrations.py./context-stats,/autonomy-status,/sync-health,/slots,/permissions-edgesall registered before/{agent_name}catch-all.snapshot.py,trinity.py,info.py,activity.py,dashboard.pywhich are legitimate agent-internal-only routers (not required to have backend mirrors).apidirectly or make API calls via stores.api.js)api.jssingleton: stores (agents.js,auth.js,operatorQueue.js,monitoring.js,network.js, etc.) import rawaxioswith manual auth headers; views (AgentDetail.vue,ApiKeys.vue) use rawfetch()with manualAuthorizationheaders. This means token refresh logic inapi.jsinterceptors is skipped.Depends(get_current_user)+AuthorizedAgentraise HTTPException(status_code=403)calls across 19 router files (threshold: 5).internal.pycorrectly has noget_current_user. High-volume sites:agent_config.py(6 sites),avatar.py(5 sites),agent_files.py(3 sites),chat.py(2 sites), plus 14 more files. Authorization logic is duplicated across routers instead of being centralized inAuthorizedAgent/dependency factories.adapters/base.pydefinesChannelAdapterABC.SlackAdapter,TelegramAdapter, andWhatsappAdapterall inherit from it.operatorQueue.jsusessetIntervalpolling the/api/operator-queueREST endpoint every N seconds.HostTelemetry.vuepolls/api/telemetry/hostevery 5000ms with rawfetch.websocket.jsexists. These are minor exceptions (operator queue and host telemetry are not agent-state push events) but are noted.docker_service.pyexists.schema.pytables.tags.tsis registered inserver.tsbut not exported fromtools/index.ts(stale re-export index — minor).models.pyBaseModelclass definitions found scattered across router files (audit_log.py,fan_out.py,git.py,internal.py,avatar.py,event_subscriptions.py,image_generation.py,logs.py,messages.py, and more). These should live inmodels.py./api/agents/{name}/.Result: 11/15 PASS, 3/15 FAIL, 1/15 WARN
Violations
INV-8 (P1): Auth Sprawl — Inline Authorization in 19 Router Files (51 sites)
51
raise HTTPException(status_code=403)calls spread across 19 router files includingagent_config.py,avatar.py,chat.py,logs.py,sharing.py,slack.py,operator_queue.py,settings.py,system_agent.py,system_views.py,whatsapp.py, and more.Fix: Consolidate into
AuthorizedAgent,OwnedAgentByName, orrequire_role()dependencies independencies.py. Each new inline auth check increases the attack surface for auth bypass and makes auditing harder.INV-7 (P1): API Client Fragmentation — Raw
axiosandfetchBypassapi.js20+ frontend files import
axiosdirectly or usefetch()instead of theapi.jsAxios singleton that handles token refresh and auth interceptors:agents.js,auth.js,operatorQueue.js,monitoring.js,observability.js,network.js,settings.js,notifications.js,systemViews.jsChatPanel.vue,PlaybooksPanel.vue,PublicLinksPanel.vue,SkillsPanel.vue,CreateAgentModal.vue,NavBar.vue,HostTelemetry.vue(rawfetch)AgentDetail.vue(rawfetchfor autonomy, read-only, rename endpoints),ApiKeys.vue(rawfetchfor all MCP key operations)Fix: Migrate all API calls to import and use the
apisingleton fromsrc/api.js.INV-14 (P1): Pydantic Model Sprawl — 71 Models Outside
models.py71
BaseModelclass definitions found in router files. Significant violators:fan_out.py(4 models),git.py(5 models),internal.py(5 models),audit_log.py(4 models),logs.py(2 models).Fix: Move all request/response models to
src/backend/models.pyand import from there.Doc Drift — Suggested
architecture.mdEditsfan_out_service,fleet_audit_service,gemini_voice,github_pat_propagation_service,platform_audit_service,platform_prompt_service,pre_check_service,subscription_auto_switch,upload_service,validation_service,ws_ticket_service,sync_waiter,telegram_mediachat.tshas 4 tools (doc says 3 —fan_outis undocumented)agents.pyline countmain.pyreferenceaudit_retention_servicesync_health_service