Model monitoring¶
truthound.ml.monitoring.ModelMonitor collects performance, prediction/feature
drift and labelled quality metrics. It owns a metric store, registered models,
alert rules and selected notification handlers. This advanced subsystem is
separate from the truthound.core validation kernel.
Native lifecycle¶
import asyncio
from truthound.ml.monitoring import ModelMonitor, MonitorConfig
from truthound.ml.monitoring.alerting.rules import ThresholdConfig, ThresholdRule
from truthound.ml.monitoring.collectors.quality import QualityConfig
async def main():
monitor = ModelMonitor() # native in-memory metric store; no external delivery
monitor.register_model("classifier", MonitorConfig(
batch_size=10,
collect_interval_seconds=60,
alert_evaluation_interval_seconds=30,
quality=QualityConfig(window_size=1000, task_type="binary"),
))
monitor.add_rule(ThresholdRule("latency", ThresholdConfig("latency_ms", 100)))
async with monitor:
identity = await monitor.record_prediction(
"classifier", {"age": 25}, prediction=1, latency_ms=5,
)
await monitor.record_actual("classifier", identity, actual=1)
collected = await monitor.collect_now("classifier")
metrics = await monitor.get_metrics("classifier")
assert collected == 1 and metrics.accuracy == 1.0
asyncio.run(main())
record_prediction returns a native prediction identity. Feedback is accepted
only while that prediction is buffered; missing or already collected identities
raise KeyError. collect_now returns the number of confirmed buffered records
collected. Model IDs must be unique. Registering a second time does not replace
pending state. unregister_model explicitly discards that model's pending records
and stops its timers; stored metrics are retained.
start() starts the selected store and one collection timer and one evaluation
timer for each model. Models registered while running receive both timers.
Collection also runs when batch_size is reached, including before start().
Each model serializes recording, feedback, reference changes and collection so
records appended during a store await cannot enter two batches.
| Configuration | Behavior |
|---|---|
batch_size |
Positive integer threshold for immediate collection; default 100. |
collect_interval_seconds |
Positive finite interval for collecting an incomplete batch while started; default 60. |
alert_evaluation_interval_seconds |
Positive finite interval for observing the latest stored snapshot and applying per-model retention; default 30. |
retention_hours |
Positive finite model history window and deletion cutoff; default 24. The selected store may impose additional retention or entry limits. |
enable_drift_detection, enable_quality_metrics |
Actual booleans selecting native collectors; both default to true. |
performance, drift, quality |
Optional native PerformanceConfig, DriftConfig, QualityConfig. Registration captures independent configuration copies. |
Performance latency uses window_size and configured percentiles. Drift uses the
last reference_window_size reference records and a rolling
detection_window_size detection window. set_reference_data requires nonempty
native PredictionRecord objects belonging to that registered model and enabled
drift collection. Quality uses a rolling window of labelled records across
batches. QualityConfig.task_type selects binary, multiclass, regression
or the default auto heuristic; select a task explicitly when probability-like
regression values or numeric class labels would make inference ambiguous.
Alerts, failure and cleanup¶
Rules must return actual boolean verdicts. A new stored snapshot is evaluated
once; periodic reads of the same snapshot do not add anomaly/trend observations
or redeliver an alert. Duration thresholds require subsequent fresh observations
above the threshold after the configured elapsed duration. Native rule names and
handler names must be unique. remove_rule and remove_handler remove explicitly
selected components. Removing a rule resolves its active state locally without
sending a resolution notification.
Each selected handler's handle or resolve must return True. False, missing
receipts and exceptions are failures. An alert is recorded when triggered;
history is not proof that every handler received it. The rule engine keeps at
most 10,000 triggers in memory by default, including later resolutions. Dashboard
data includes current metrics, metric history, active alerts and that real alert
history. Backend and handler persistence belong to their selected implementations.
A collection/evaluation error or cancellation latches that model's outcome as
uncertain. Pending predictions remain available for inspection by count and ID;
new collection and recording are blocked, and timers do not resend unknown
effects. get_status() reports the latch, buffer count and store lifecycle.
After investigation, discard_uncertain(model_id) explicitly discards pending
records, resets collectors and reference state, and marks the current stored
snapshot observed without sending it. It does not undo stored metrics or
notifications. Set reference data again before further drift detection.
stop() cancels and awaits owned timers, then stops the selected store. It does
not flush pending records or send new alerts. Failed cleanup remains visible;
start() rejects restart until store cleanup is confirmed. The native
MonitoringPipeline also propagates failed storage/delivery and blocks further
processing of the affected model until explicit discard_uncertain(model_id).
It does not automatically retry unknown effects.
The default prediction buffer, metric store, rule history and failure latch are in memory. They do not provide recovery after process loss or exactly-once external notification delivery. Configure and verify external stores/handlers under their own operational contracts.
Approved MCP bindings¶
The unreleased Core profile exposes ml_services_open and ml_services_execute.
An approved installed factory yields MLRuntime(monitor, models, rules, handlers).
Each model alias selects MonitoringModel(native_id, config, features,
prediction_column, actual_column=None, latency_column=None). features maps
public feature aliases to fixed asset columns. Rules and handlers are factory
objects selected by aliases; caller code, native identities, connection settings
and endpoints are not wire inputs. The monitor must initially be stopped and
have no registered models, rules or handlers. Map the binding alias to its
installed capability under private ml_services bindings.
Commands are inspect, status, register, unregister, start, stop,
shutdown, record, feedback, reference, collect, evaluate,
discard_uncertain, metrics, dashboard, rule_add, rule_remove,
handler_add and handler_remove. Every command has exact approval and sensitive
disclosure requirements. Starting approves future periodic collection,
evaluation, retention deletion and selected handler delivery until stop, release
or expiry. The operator remains responsible for what the installed factory does
while entering and exiting its lifetime.
record and reference read pinned asset handles with bounded offset/limit;
feedback reads one row's fixed actual column at offset and requires an
owner-local prediction reference returned by record. Returned references state
whether the corresponding prediction remains pending after batching.
Releasing any bound input revokes the monitor and its derived artifacts. Cleanup
stops timers without flushing records. Metric output projects finite standard
fields, built-in aggregate metrics (including regression errors and configured
latency percentiles), configured feature aliases and optional factory-selected
MonitoringModel.metric_aliases mappings; arbitrary custom metric names, alert
messages, native IDs, handler metadata and endpoints are omitted.
An unconfirmed native operation returns a failed native_monitor_incomplete
artifact with current state. Reusing its approval key replays that result and
does not repeat collection/delivery. Inspect state before explicitly discarding
unknown pending work. A successful shutdown is acknowledged only after monitor
and factory cleanup finish. The same key may replay that result; further native
commands are rejected. Resource release alone is not proof that a slow factory
finalizer completed. These source features are not part of the published 3.2.0
package. See the MCP guide.
Stopping also waits for in-flight foreground model operations before stopping the
store. New model work is blocked while cleanup is in progress; an already started
write is not rolled back, and later alert handlers are not started after stop.
Calling stop from inside that model's own operation is rejected to avoid waiting
on itself. unregister_model rejects a busy model. Handler edits affect subsequent
alerts; delivery iterates a snapshot so removing one handler during its await does
not silently skip another selected handler. Status includes stopping.