Phase 29.1 — SelfModel: Internal Representation of System Capabilities & Architecture
Parent discussion: #626 (Phase 29 Planning)
Depends on: Phase 13 WorldModel (#383), Phase 16 PerformanceProfiler (#416)
Depended on by: 29.2 IntrospectionEngine, 29.5 SelfAwarenessOrchestrator
Overview
The SelfModel maintains an internal representation of the system's own capabilities, architectural topology, resource inventory, and competence boundaries. Inspired by Metzinger's (2003) phenomenal self-model theory — the system constructs a transparent model of itself that enables higher layers to reason about what it can and cannot do.
Data Structures
from enum import Enum, auto
from dataclasses import dataclass, field
from datetime import datetime
from typing import FrozenSet, Optional
import uuid
class SelfModelDomain(Enum):
"""Domains of self-knowledge."""
ARCHITECTURE = auto() # Module topology & connectivity
CAPABILITY = auto() # What the system can do
RESOURCE = auto() # CPU, memory, attention budgets
COMPETENCE = auto() # Proficiency scores per task type
LIMITATION = auto() # Known boundaries & failure modes
@dataclass(frozen=True)
class CapabilityProfile:
"""Profile of a single system capability."""
domain: SelfModelDomain
name: str
proficiency_score: float # 0.0 = no ability, 1.0 = expert
latency_ms: float # Expected execution time
reliability: float # Success rate 0.0-1.0
dependencies: FrozenSet[str] = frozenset()
last_assessed: datetime = field(default_factory=datetime.utcnow)
@dataclass(frozen=True)
class ResourceInventory:
"""Snapshot of available vs. consumed resources."""
cpu_budget: float # Total CPU units available
memory_budget: float # Total memory MB
attention_budget: float # Attention slots (from Phase 28)
used_cpu: float
used_memory: float
used_attention: float
timestamp: datetime = field(default_factory=datetime.utcnow)
@dataclass(frozen=True)
class ArchitectureNode:
"""A single module in the architecture graph."""
module_id: str
module_type: str
connections: FrozenSet[str] = frozenset()
health_score: float = 1.0
version: str = "0.0.0"
@dataclass(frozen=True)
class ArchitectureMap:
"""Complete system architecture as a directed graph."""
nodes: tuple # tuple[ArchitectureNode, ...]
edges: tuple # tuple[tuple[str, str], ...] (source_id, target_id)
created_at: datetime = field(default_factory=datetime.utcnow)
Protocol
from typing import Protocol, runtime_checkable
@runtime_checkable
class SelfModel(Protocol):
"""Internal representation of system capabilities & architecture."""
async def get_capabilities(self, domain: SelfModelDomain) -> tuple[CapabilityProfile, ...]:
"""Return all capabilities in the given domain."""
...
async def get_architecture(self) -> ArchitectureMap:
"""Return current architecture topology."""
...
async def get_resources(self) -> ResourceInventory:
"""Return current resource inventory snapshot."""
...
async def assess_competence(self, task_description: str) -> float:
"""Estimate competence (0-1) for the described task."""
...
async def identify_limitations(self) -> tuple[str, ...]:
"""Return known limitations and failure modes."""
...
async def update_model(self) -> None:
"""Trigger a full self-model refresh."""
...
Implementation — DynamicSelfModel
Key design decisions:
_capabilities: dict[SelfModelDomain, list[CapabilityProfile]] — mutable internal store, frozen on read
_architecture: ArchitectureMap — rebuilt on update_model() by querying ModuleRegistry (Phase 15) health endpoints
_resources: ResourceInventory — refreshed from PerformanceProfiler (Phase 16) and AttentionOrchestrator (Phase 28)
- Auto-refresh:
_refresh_interval (default 30s) triggers background update_model() via asyncio.create_task
- WorldModel integration: Queries Phase 13 WorldModel for environment constraints that affect capabilities
- Competence assessment: Fuzzy matching of
task_description against capability names + dependency check; returns weighted average of matching proficiency scores
- Limitation detection: Scans for capabilities with
proficiency_score < 0.3 or reliability < 0.5; also checks resource utilization > 90%
- Thread safety:
asyncio.Lock on _capabilities and _architecture mutations
Null Implementation
class NullSelfModel:
"""No-op self-model for testing and graceful degradation."""
async def get_capabilities(self, domain): return ()
async def get_architecture(self): return ArchitectureMap(nodes=(), edges=())
async def get_resources(self): return ResourceInventory(0,0,0,0,0,0)
async def assess_competence(self, task_description): return 0.0
async def identify_limitations(self): return ()
async def update_model(self): pass
Factory
def make_self_model(
*,
world_model=None,
performance_profiler=None,
module_registry=None,
attention_orchestrator=None,
refresh_interval: float = 30.0,
null: bool = False,
) -> SelfModel:
if null:
return NullSelfModel()
return DynamicSelfModel(
world_model=world_model,
performance_profiler=performance_profiler,
module_registry=module_registry,
attention_orchestrator=attention_orchestrator,
refresh_interval=refresh_interval,
)
Prometheus Metrics
| Metric |
Type |
Labels |
Description |
self_model_assessments_total |
Counter |
domain |
Number of competence assessments |
self_model_capability_score |
Gauge |
domain, name |
Current proficiency score per capability |
self_model_resource_utilization |
Gauge |
resource_type |
Utilization ratio (0-1) per resource |
self_model_staleness_seconds |
Gauge |
— |
Time since last model refresh |
self_model_limitations_detected |
Gauge |
— |
Count of currently identified limitations |
Test Targets (12)
test_self_model_protocol_runtime_checkable — isinstance(DynamicSelfModel(...), SelfModel)
test_get_capabilities_filters_by_domain — returns only matching domain
test_get_capabilities_returns_frozen_tuples — immutability check
test_get_architecture_returns_valid_graph — all edge endpoints exist in nodes
test_get_resources_snapshot_is_frozen — ResourceInventory is immutable
test_assess_competence_returns_bounded_float — 0.0 ≤ result ≤ 1.0
test_assess_competence_unknown_task_returns_low — unfamiliar task → score < 0.3
test_identify_limitations_detects_low_proficiency — capabilities with score < 0.3 listed
test_identify_limitations_detects_resource_exhaustion — utilization > 90% reported
test_update_model_refreshes_all_components — architecture + capabilities + resources updated
test_auto_refresh_fires_on_interval — mock clock advancement triggers update
test_null_self_model_returns_defaults — NullSelfModel returns empty tuples / zeros
Phase 29.1 —
SelfModel: Internal Representation of System Capabilities & ArchitectureOverview
The
SelfModelmaintains an internal representation of the system's own capabilities, architectural topology, resource inventory, and competence boundaries. Inspired by Metzinger's (2003) phenomenal self-model theory — the system constructs a transparent model of itself that enables higher layers to reason about what it can and cannot do.Data Structures
Protocol
Implementation —
DynamicSelfModelKey design decisions:
_capabilities:dict[SelfModelDomain, list[CapabilityProfile]]— mutable internal store, frozen on read_architecture:ArchitectureMap— rebuilt onupdate_model()by querying ModuleRegistry (Phase 15) health endpoints_resources:ResourceInventory— refreshed from PerformanceProfiler (Phase 16) and AttentionOrchestrator (Phase 28)_refresh_interval(default 30s) triggers backgroundupdate_model()viaasyncio.create_tasktask_descriptionagainst capability names + dependency check; returns weighted average of matching proficiency scoresproficiency_score < 0.3orreliability < 0.5; also checks resource utilization > 90%asyncio.Lockon_capabilitiesand_architecturemutationsNull Implementation
Factory
Prometheus Metrics
self_model_assessments_totaldomainself_model_capability_scoredomain,nameself_model_resource_utilizationresource_typeself_model_staleness_secondsself_model_limitations_detectedTest Targets (12)
test_self_model_protocol_runtime_checkable—isinstance(DynamicSelfModel(...), SelfModel)test_get_capabilities_filters_by_domain— returns only matching domaintest_get_capabilities_returns_frozen_tuples— immutability checktest_get_architecture_returns_valid_graph— all edge endpoints exist in nodestest_get_resources_snapshot_is_frozen— ResourceInventory is immutabletest_assess_competence_returns_bounded_float— 0.0 ≤ result ≤ 1.0test_assess_competence_unknown_task_returns_low— unfamiliar task → score < 0.3test_identify_limitations_detects_low_proficiency— capabilities with score < 0.3 listedtest_identify_limitations_detects_resource_exhaustion— utilization > 90% reportedtest_update_model_refreshes_all_components— architecture + capabilities + resources updatedtest_auto_refresh_fires_on_interval— mock clock advancement triggers updatetest_null_self_model_returns_defaults— NullSelfModel returns empty tuples / zeros