Skip to content

Code-Derived Architecture Risks

Status: Current audit register
Audit baseline: release/v0.13.0 architecture, verified against commit 890e1ad
Last verified: 2026-07-26

This register records architectural constraints observed directly in code. It is not a substitute for issues or ROADMAP.md; it ensures future architecture work does not lose the evidence discovered during the code audit.

How to use this register

  • Open: Verified behavior with unresolved architectural consequence.
  • Proposed: A shaped release direction exists but code is unchanged.
  • Accepted: Deliberate constraint with documented operating guidance.
  • Resolved: Code and tests close the risk; retain the row and link evidence.

When implementation begins, add the roadmap/issue reference and target release. Do not mark a row resolved from prose alone.

Rows resolved by v0.13 link to ADR-0001 and the release-branch tests that prove the boundary. Remaining open rows are inputs to future roadmap work.

Multi-tenancy and state integrity

ID Status Observation Consequence Primary evidence
AR-001 Resolved — v0.13 Session/message/run/event storage methods commonly accept an ID without effective scope; routes fetch and check afterward Storage-level methods now carry exact scope for runtime access; wrong-scope identifiers return not-found tests/unit/test_v013_storage_isolation.py; ADR-0001
AR-002 Open Session idempotency lookup scans all sessions and does not apply its scope argument Identical builder idempotency keys can collide across scopes api/routes/sessions.py::_find_session_by_idempotency_key
AR-003 Resolved — v0.13 runtime records Session deletion removes the session row but has no schema cascade or complete service cleanup Scoped cleanup now covers runtime-owned records and cache/session-service teardown; deployment storage retention remains an operator concern tests/unit/test_v013_storage_isolation.py; tests/unit/test_v013_cache_bounds.py
AR-004 Open One active run per session is check-then-insert without a database uniqueness invariant Concurrent requests can create competing foreground attempts runtime_projection.py::begin_run; storage/schema.py::session_runs_table
AR-005 Open Run creation, task link, session update, and event append are separate storage calls Failure can leave partially projected lifecycle state runtime_projection.py::begin_run, transition_run_with_event
AR-006 Open SQLite allocates event sequence with MAX+1 and no retry; PostgreSQL uses an advisory lock Concurrent SQLite event appends can collide storage/sqlite.py::append_event; storage/postgres.py::append_event
AR-007 Open Config subset resolution has no deterministic tie-break for same-depth incomparable scopes Two valid visible definitions can resolve differently by row order storage/config_registry.py adapter _get_entity implementations
AR-008 Resolved — v0.13 API-created Agents currently use hierarchical ConfigRegistry fallback API-created Agents resolve only at the exact trusted scope; shared file Agents are explicit read-only fallbacks tests/unit/api/test_agents_crud.py; tests/e2e/test_scenarios/p3_agents/test_explicit_agent_provisioning.py; ADR-0001
AR-009 Open Checkpoints are keyed by globally unique thread_id, not scope; surrounding code supplies isolation A missed outer scope check reaches the checkpoint namespace directly agent/runtime.py; storage checkpointer methods

Configuration and runtime composition

ID Status Observation Consequence Primary evidence
AR-010 Resolved — v0.13 Compiled graph cache keys include tool/middleware/subagent counts rather than full resolved contents; skill/MCP/profile contents are absent Runtime manifest digests, Agent revisions, model identity, sandbox backend identity, and scope fingerprints isolate graph reuse tests/unit/test_runtime_manifest.py; tests/unit/test_v013_cache_bounds.py; ADR-0001
AR-011 Resolved — v0.13 Production wiring subscribes only DefaultConfigStore.on_config_change; graph cache invalidation has no caller Agent revisions and manifest digests make changed definitions compile under new cache identities; bounded TTL/LRU limits stale residency tests/unit/test_runtime_manifest.py; tests/unit/test_v013_cache_bounds.py
AR-012 Open SQLite/memory registry writes do not emit through the created in-process dispatcher Claimed immediate local hot reload is not wired storage/config_registry.py; config_dispatcher.py
AR-013 Open PostgreSQL listeners share one global processed flag One replica can consume a change before another sees it; invalidation is best effort config_dispatcher.py::PostgresListenDispatcher._process_pending
AR-014 Resolved — v0.13 Cache hits return a fresh sandbox handle alongside a graph compiled with the original backend Cached graphs route dynamically to the current run sandbox and cannot retain another session's backend tests/unit/test_v013_cache_bounds.py; tests/unit/test_v013_strict_execution.py
AR-015 Open Empty Agent tool allow-list loads every enabled visible registry tool “No selected tools” does not mean no registry tools agent/resolver.py::RuntimeResolver.build_tools
AR-016 Accepted constraint — unsafe opt-in Registry Python tool source is compiled/executed in the server process API Python tools are rejected in strict production mode and require explicit unsafe development configuration tests/unit/test_v013_strict_execution.py; ADR-0001
AR-017 Open Runtime delegation is built from other visible Agents, including hidden/mode variants; explicit Agent subagent fields are not the sole selection source Delegation surface can exceed the definition a builder expects llm/deep_agent_service.py::_resolve_agent_config
AR-018 Open MCP trusted-scope interceptor fills absent keys but does not overwrite conflicts Model-supplied conflicting scope arguments may survive agent/mcp_client.py interceptor construction

Replica, streaming, and lifecycle

ID Status Observation Consequence Primary evidence
AR-019 Open Active runtimes, abort handles, graph cache, rate limits, sandbox handles, watchers, and native SSE buffers are process-local while Helm defaults to three replicas Immediate abort, rate limiting, file config, and in-flight recovery are not deployment-wide deep_agent_service.py::SessionAgentManager; rate_limiter.py; Helm values
AR-020 Open Native SSE creates a new replay buffer per request Last-Event-ID cannot replay the prior request across reconnects or replicas api/sse.py::SSEStream; message route construction
AR-021 Accepted constraint A2A retention runs opportunistically per active Agent/scope rather than from a global scheduler Inactive scopes are not cleaned until another matching A2A request protocols/a2a/retention.py::A2ARetentionManager
AR-022 Open Separately created ConfigRegistry and ArtifactStore pools are not explicitly closed by lifespan Shutdown can leave connections to process teardown rather than orderly close main.py::lifespan; storage/factory.py

Execution and security

ID Status Observation Consequence Primary evidence
AR-023 Open Docker execution accepts a timeout but does not apply it to exec_run A command can outlive the requested deadline execution/backend.py::DockerExecutionBackend.execute
AR-024 Open Docker sandbox wrapper has no manager-visible terminate() Session release does not close the corresponding container through the common path agent/sandbox_backend.py::CognitionDockerSandboxBackend; SessionAgentManager
AR-025 Accepted constraint Direct write guards do not constrain arbitrary shell commands Protected paths are policy for file APIs, not a security boundary for trusted command execution Sandbox adapter write, edit, and execute methods
AR-026 Open Kubernetes labels copy raw effective-scope values Values can violate label constraints or expose scope in cluster metadata agent/cognition_agent.py::create_cognition_agent
AR-027 Resolved — v0.13 origin gate Completion callback accepts caller-provided HTTP/S destinations without allowlist, private-address defense, or signature Completion callbacks default denied and require exact operator-approved HTTPS origins before execution starts tests/unit/test_v013_strict_execution.py; api/routes/messages.py::_approved_callback_origin

Operability and delivery

ID Status Observation Consequence Primary evidence
AR-028 Open /ready always reports true; /health lists every session Readiness does not prove dependencies and health cost grows with data main.py::ready_check, health_check
AR-029 Resolved — v0.13 HTTP metric endpoint label used concrete URL paths Metrics now use the matched route template or unmatched and status class labels, avoiding resource-ID cardinality api/middleware.py::ObservabilityMiddleware; tests/unit/test_observability_cardinality.py
AR-030 Resolved — v0.13 Metrics startup was coupled to the OpenTelemetry enabled flag COGNITION_METRICS_ENABLED controls Prometheus startup independently from trace export main.py::lifespan; settings.py; tests/unit/test_observability_config.py
AR-031 Resolved — v0.13 Cognition startup carried an obsolete MLflow tracing shim while semantic traces already flowed through canonical OTLP and the Collector Removed the MLflow startup shim; MLflow is now only a Collector destination with the experiment id configured by the operator-owned pipeline observability/__init__.py; docker/otel-collector-config.yml; tests/unit/test_observability_config.py
AR-032 Resolved — v0.13 General 500 responses included str(exc) Unhandled 500 responses now return a generic error body and log only redacted error classification with route-template context main.py::general_exception_handler; tests/unit/test_rest_api.py
AR-033 Open FastAPI startup uses create_all/manual checks rather than Alembic upgrade A new image can start against a partially upgraded schema unless operators migrate first main.py; backend initialize; storage/migrations.py
AR-034 Open CI omits full E2E, migration-upgrade, Helm lint, and image vulnerability gates Release automation does not prove every documented deployment path .github/workflows/ci.yml; pre-release-images.yml
AR-035 Open cognition-client entry point references a TUI module absent from the inspected client tree A published console entry point may be unusable pyproject.toml; client/
AR-036 Resolved — v0.13 branch A measured short Agent run produced 209 spans, 172 routine middleware-hook spans, and 742,119 bytes of attributes, including repeated Agent content; a later smoke test also exposed separate Cognition and LangGraph traces for one turn The final local Compose trace tr-f0174459e7d636b60018689dfe78b4aa has one cognition.agent.run root, the native LangGraph/model tree beneath it, 20 spans, no orphaned children, no duplicate metrics-adapter spans, and a persisted matching durable trace ID. Raw content remains builder-owned and byte-bounded at export. curated tracing proposal; ADR-0002
AR-037 Resolved — v0.13 branch Usage Events counted generated text and applied a hard-coded price estimate instead of projecting provider-reported usage metadata The final local provider run reports a complete Usage Event of 8,996 input and 30 output tokens, the MLflow trace total matches exactly, Prometheus receives the same automatic histogram values, the final message keeps token_count=null, and estimated_cost remains null. curated tracing proposal; ADR-0002

Review rules

  • Link a roadmap item or issue before changing a row to Proposed.
  • Add regression/isolation evidence before changing a row to Resolved.
  • Move deliberate permanent behavior to an ADR and mark it Accepted.
  • Review this register during every minor-release architecture audit.