Timeline Architecture

Audience: developers integrating with the audit/timeline APIs, and operators reasoning about tamper-evident audit, anomaly detection, and event replay. For the module overview and quick links, see ./README.md.

Unified audit sink plus query/presentation service for HLC-ordered cross-service event timelines.

Overview

Timeline is a single deployable Stella Ops service (StellaOps.Timeline.WebService) that fulfils two related responsibilities:

  1. Unified audit sink. It owns the platform-wide, tamper-evident audit log in timeline.unified_audit_events. Every Stella Ops service emits audit events here (for example, Authority login/auth events, Policy governance changes, JobEngine/Release operations, EvidenceLocker, Notify). Events are pushed to POST /api/v1/audit/ingest and persisted with a per-tenant SHA-256 hash chain for tamper evidence. The /api/v1/audit/* API serves filtered event lists, statistics, correlation clusters, chain verification, retention policies, GDPR redaction, and an anomaly-detection (anomaly v2) subsystem.
  2. HLC event timeline. It provides a REST API for querying, analyzing, and replaying events indexed by the TimelineIndexer (consolidated into this module). All such events carry Hybrid Logical Clock (HLC) timestamps that establish causal ordering across distributed services. The service supports correlation-based queries, critical path analysis for latency diagnosis, and deterministic event replay/export.

The TimelineIndexer ingestion side (NATS/Redis subscribers, the timeline.timeline_events store, and query/evidence endpoints) was merged into StellaOps.Timeline.WebService and is co-hosted in the same process. The separate StellaOps.TimelineIndexer.WebService and StellaOps.TimelineIndexer.Worker projects exist but are dormant — their logic now runs inside the unified WebService (see Components).

Production Timeline hosts do not use process-local replay/export state. The in-memory replay orchestrator and export bundle builder are registered only in Development and Testing (AddTimelineServices); other environments fall back to UnsupportedTimelineReplayOrchestrator / UnsupportedTimelineBundleBuilder, so replay/export operations return 501 problem+json (timeline_replay_unavailable / timeline_export_unavailable) until durable operation storage and worker-backed execution are configured.

Components

src/Timeline/
  StellaOps.Timeline.WebService/              # Unified WebService (audit sink + HLC timeline + indexer)
    Audit/                                    # Unified audit store, providers, aggregation, retention, classifier
      PostgresUnifiedAuditEventStore.cs       # Hash-chained Postgres store (primary source of truth)
      PostgresUnifiedAuditStateStore.cs       # Durable ack/export operation state
      CompositeUnifiedAuditEventProvider.cs   # Merges Postgres store + (neutered) HTTP provider
      HttpUnifiedAuditEventProvider.cs        # Legacy per-service poller (neutered, DEPRECATE-002)
      UnifiedAuditAggregationService.cs       # Stats, correlations, timeline search, export
      AuditDataClassifier.cs                  # GDPR classification (none/personal/sensitive/restricted)
      AuditRetentionPurgeService.cs           # Scheduled per-classification retention purge (hosted)
      TimelineAuthorizationAuditSink.cs       # IAuthEventSink logging auth outcomes
      UnifiedAuditContracts.cs                # Event model + module/action/severity catalogs
    Anomalies/                                # Anomaly v2 rule engine + evaluators + escalation chains
    HostedServices/                           # AnomalyDefaultRuleSeed, ActorBehaviorBaselineRollup
    Authorization/TimelineAuthorizationMiddleware.cs
    Security/TimelinePolicies.cs              # Read/Write/Admin policy names (timeline:read/write/admin)
    Endpoints/
      TimelineEndpoints.cs                    # HLC query endpoints (/api/v1/timeline/hlc/*)
      ExportEndpoints.cs                      # HLC event export endpoints
      ReplayEndpoints.cs                      # Deterministic replay endpoints
      UnifiedAuditEndpoints.cs                # Unified /api/v1/audit ingest + query endpoints
      HealthEndpoints.cs                      # /health, /health/ready, /health/live
    Program.cs                                # Host configuration; also defines /api/v1/timeline indexer routes
  StellaOps.TimelineIndexer.WebService/       # Dormant (logic merged into Timeline.WebService)
  StellaOps.TimelineIndexer.Worker/           # Dormant standalone worker (logic merged; runs in-process)
  __Libraries/
    StellaOps.Timeline.Core/                  # HLC query/replay/export + unified-audit persistence + anomalies
      ITimelineQueryService.cs                # HLC query interface
      TimelineQueryService.cs                 # HLC query implementation (over StellaOps.Eventing store)
      Migrations/                             # timeline schema: ONE live file, 001_v1_timeline_core_baseline.sql
                                              #   (collapsed 002-010: critical-path view, unified_audit_events,
                                              #    GIN/retention/operation-state/baseline/rules/alerts).
                                              #   Pre-collapse files live in _archived/ and are NOT embedded.
      Postgres/                               # TimelineCoreDataSource + anomaly/baseline/alert repositories
      Replay/                                 # ITimelineReplayOrchestrator (+ Unsupported fallback)
      Export/                                 # ITimelineBundleBuilder (+ Unsupported fallback)
      Anomalies/                              # Contracts, default rules, baseline calculator/repository
    StellaOps.TimelineIndexer.Core/           # Ingestion domain logic
      Abstractions/                           # ITimelineEventStore, ITimelineIngestionService, etc.
      Models/                                 # TimelineEventEnvelope, TimelineEventView, etc.
      Services/                               # TimelineIngestionService, TimelineQueryService
    StellaOps.TimelineIndexer.Infrastructure/ # Persistence, EfCore, messaging subscribers
      Db/                                     # Migrations (001_initial_schema.sql), event store, query store
      EfCore/                                 # Compiled models, context, entity models
      Subscriptions/                          # NATS, Redis, Null subscribers, envelope parser, ingestion worker
      Options/TimelineIngestionOptions.cs     # Ingestion:Nats / Ingestion:Redis transport config
  __Tests/
    StellaOps.Timeline.Core.Tests/            # HLC query tests
    StellaOps.Timeline.WebService.Tests/      # API integration, audit store, anomaly, replay tests
    StellaOps.TimelineIndexer.Tests/          # Indexer unit and integration tests

Data Flow

HLC Timeline Flow

  1. Events are produced by various Stella Ops services and carry HLC timestamps.
  2. The in-process ingestion worker (TimelineIngestionWorker) consumes events from the message bus (NATS or Redis subscriber) and writes indexed events to the timeline.timeline_events store.
  3. Timeline WebService receives HLC query requests (Platform, CLI, Web) under /api/v1/timeline/hlc/*.
  4. TimelineQueryService (StellaOps.Timeline.Core) executes queries against the StellaOps.Eventing event store (ITimelineEventStore), applying correlation, service, kind, and HLC-range filters.
  5. Results are returned in HLC-sorted order, with optional critical path analysis computing latency stages between correlated events. The timeline.critical_path materialized view (Timeline.Core baseline 001_v1_timeline_core_baseline.sql:28) pre-computes stage transitions over timeline.timeline_events for performance.

Unified Audit Ingest + Query Flow

  1. Ingest. Any service emits an audit event by POSTing to /api/v1/audit/ingest (wire-compatible with the AuditEventPayload from the shared StellaOps.Audit.Emission library, timeline:write scope). IngestEventAsync normalizes the module/action/severity (UnifiedAuditValueMapper against UnifiedAuditCatalog) and persists via PostgresUnifiedAuditEventStore.AddAsync, which appends to timeline.unified_audit_events under SERIALIZABLE isolation with a per-tenant SHA-256 hash chain (content_hash linked to previous_entry_hash, monotonic sequence_number). PostgreSQL serialization/deadlock aborts retry the whole transaction with bounded deterministic backoff, so sequence allocation and hash computation are repeated against the current chain head. Duplicate event IDs roll back their sequence allocation and return idempotently instead of leaving a gap in the chain head. Returns 202 Accepted.
  2. Read. UnifiedAuditEndpoints serves /api/v1/audit/* read requests from Web/CLI clients.
  3. UnifiedAuditAggregationService routes event-list requests through the optional IUnifiedAuditPagedEventProvider capability implemented by the production CompositeUnifiedAuditEventProvider. PostgresUnifiedAuditEventStore.GetPageAsync applies the public filters, exact total count, and stable (timestamp DESC, id ASC) cursor paging in PostgreSQL; the event-list path is not bounded by the legacy 10,000-row snapshot.
  4. The composite provider merges two sources: the PostgresUnifiedAuditEventStore (primary source of truth) and the HttpUnifiedAuditEventProvider. Note (orphaned/transitional): the HTTP provider is neutered as of DEPRECATE-002 — its GetEventsAsync returns an empty list because the per-service audit endpoints it used to poll (Authority, Policy, Notify, JobEngine, EvidenceLocker) now proxy into Timeline, so polling them would self-loop. In effect, Postgres is the sole live source; the HTTP path is retained dead code pending DEPRECATE-003 removal.
  5. The production query capabilities remove the legacy fixed snapshot from the remaining reads: event lookup and export count execute directly in PostgreSQL, statistics are aggregated in PostgreSQL, and timeline search plus seven-day anomaly evaluation receive the complete tenant-filtered PostgreSQL result. Correlation listing uses IUnifiedAuditCorrelationEventProvider: PostgreSQL selects at most the requested 1-200 newest multi-event correlation IDs by root-event time, then returns only the events for those clusters. This preserves complete selected clusters without materializing the tenant/date event set in service memory or silently truncating at the legacy 10,000-event boundary. Anomaly acknowledgements and unified audit export status are persisted per tenant in PostgreSQL (PostgresUnifiedAuditStateStore); they are not process-local service memory.
  6. If a source is unavailable, the composite provider logs the failure and continues with whatever source returned data instead of failing the unified endpoint.

Anomaly v2 Flow

  1. Audit events feed deterministic per-actor behavior baselines, materialized by ActorBehaviorBaselineRollupHostedService into timeline.actor_behavior_baseline. Source rows are keyset-paged and folded immediately into ActorBehaviorBaselineAccumulator; each page is consumed before the next read, while the accumulator retains only per-group hourly counters plus the deterministic 50-value IP/user-agent caps. One pass retains at most Timeline:BaselineRollup:MaxDistinctGroups distinct (tenant, actor, action, resource type) groups (default 10,000; clamped to 20,000). After saturation, already-admitted groups remain complete, later-group source events are omitted, and the result, warning log, and metrics explicitly report a degraded distinct_group_limit state rather than risking unbounded memory growth or claiming a complete projection.
  2. The AnomalyRuleEngine evaluates tenant-scoped, configurable rules (timeline.anomaly_rules, seeded by AnomalyDefaultRuleSeedHostedService) using a set of registered IAnomalyRuleEvaluators (unusual volume, failed-auth spike, privilege escalation, off-hours activity, per-actor z-score, new actor/IP, action novelty, escalation chains, etc.).
  3. Detected anomalies are persisted to timeline.audit_anomaly_alerts with a dispatch-state worklist (pending → dispatched → failed). Notify polls pending, unacknowledged alerts via the admin dispatch endpoints and fans out notifications.

Database Schema

Everything lives under the timeline PostgreSQL schema. Two independent migration runners converge it on startup (both wired via AddStartupMigrations in Program.cs, against the Postgres:Timeline connection):

The library also ships TimelineIndexerMigrationHostedService, but Program.cs removes that duplicate registration so a single serialized runner owns the timeline schema (avoids two competing runners).

Migration-filename note (2026-07-12). The Timeline.Core chain formerly numbered 002010 was collapsed into 001_v1_timeline_core_baseline.sql; those files now exist only under Migrations/_archived/pre_1.0/mig061/ and are excluded from embedding. The parenthetical “(from NNN_*)” markers below are provenance of the folded-in DDL, not live filenames. The TimelineIndexer side is different: its 001_initial_schema.sql is still a real, live migration.

Unified audit sink: timeline.unified_audit_events (baseline line 87; from 003_unified_audit_events.sql)

The platform-wide tamper-evident audit log. Immutable append-only; primary key (id, tenant_id).

ColumnTypeDescription
idTEXTEvent ID (caller-supplied or minted ingest-<guid>)
tenant_idTEXTOwning tenant
timestampTIMESTAMPTZEvent time
moduleTEXTOriginating module (normalized against UnifiedAuditCatalog)
actionTEXTAction verb (normalized)
severityTEXTinfo / warning / error / critical
actor_*TEXTactor_id, actor_name, actor_email, actor_type, actor_ip, actor_user_agent
resource_*TEXTresource_type, resource_id, resource_name
descriptionTEXTHuman-readable description (GIN full-text index)
details_jsonbJSONBStructured details (GIN index; folded in from the archived 004_details_gin_index.sql)
diff_jsonbJSONBOptional before/after diff
correlation_idTEXTCross-service correlation identifier
parent_event_idTEXTHierarchy link
tagsTEXT[]Tags (GIN index)
content_hashTEXTSHA-256 of canonical event JSON (tamper evidence)
previous_entry_hashTEXTPrior event’s content_hash (hash chain link)
sequence_numberBIGINTMonotonic per-tenant sequence
data_classificationTEXTnone / personal / sensitive / restricted (from 005_*)
compliance_holdBOOLEANLegal hold — exempt from retention purge (from 005_*)
pii_redacted_atTIMESTAMPTZSet when PII columns redacted (GDPR Art. 17; from 005_*)
created_atTIMESTAMPTZWall-clock ingestion time

Supporting objects: timeline.unified_audit_sequences (per-tenant chain head + next_unified_audit_sequence / update_unified_audit_sequence_hash functions) and verify_unified_audit_chain(tenant, from_seq, to_seq) which backs GET /api/v1/audit/chain/verify.

Retention + GDPR (baseline line 326; folded in from the archived 005_audit_data_classification_retention.sql)

ObjectDescription
timeline.audit_retention_policiesPer-tenant/per-classification retention windows; tenant_id = '*' is the platform default (none/personal 365d, sensitive 730d, restricted 2555d).
resolve_audit_retention_days(tenant, class)Resolves the effective retention, falling back to the platform default.
purge_expired_audit_events(tenant, dry_run)Deletes events older than the per-classification window, honouring compliance_hold. Driven by AuditRetentionPurgeService.
redact_actor_pii(tenant, actor)Right-to-erasure: replaces PII columns with [REDACTED] while preserving actor_id so the hash chain stays verifiable.

Durable operation state (folded in from the archived 006_unified_audit_operation_state.sql)

Table / ObjectDescription
unified_audit_anomaly_acknowledgementsPer-tenant acknowledgement records for computed anomaly alert IDs.
unified_audit_exportsPer-tenant unified audit export status records, including filters, format, event count, and retention timestamps.
unified_audit_export_sequenceMonotonic sequence used to mint stable export IDs without process-local counters.

Anomaly v2 (baseline lines 538-640; from 007010)

TableDescription
actor_behavior_baselineDeterministic per-actor hourly behavior baselines (p50/p95/p99, sample counts, last-seen IPs/UAs). Materialized by the rollup hosted service.
anomaly_rulesTenant-scoped, configurable anomaly rules (rule kind + JSONB params + severity).
tenant_business_hoursTimeline-owned fallback for tenant timezone/business-hours policy (off-hours detection).
audit_anomaly_alertsPersisted anomaly alerts with a dispatch-state worklist (pending/dispatched/failed/suppressed) consumed by Notify.
anomaly_subscriptionsReserved placeholder for subscription/dispatcher coordination — not present in the baseline; no live schema yet.

Indexer tables: HLC timeline (TimelineIndexer 001_initial_schema.sql — a live migration)

TableDescription
timeline_eventsCore event header (event_seq bigserial, event_id, source, event_type, occurred_at, correlation_id, trace_id, severity enum, payload_hash, attributes). Row-Level Security enforces tenant isolation via app.current_tenant.
timeline_event_detailsRaw + normalized payloads per event.
timeline_event_digestsEvidence linkage (bundle/attestation digests, manifest URI).
critical_path (materialized view; Timeline.Core baseline line 28, from 002_create_critical_path_view.sql)Pre-computed stage transitions and wall-clock durations over timeline_events.

HLC event store (Eventing)

The HLC query path (/api/v1/timeline/hlc/*) reads through the StellaOps.Eventing infrastructure (ITimelineEventStore). Runtime Eventing registration is PostgreSQL-only: AddStellaOpsEventing(IConfiguration) registers PostgresTimelineEventStore plus PostgresHlcStateStore. Test harnesses that need volatile storage must call AddStellaOpsEventingInMemory(...) explicitly; setting Eventing:UseInMemoryStore=true on the runtime configuration path fails closed.

Dependencies

Service/LibraryPurpose
StellaOps.EventingHLC event store access and query primitives
StellaOps.HybridLogicalClockHLC timestamp parsing and comparison
StellaOps.TimelineIndexer.*In-process ingestion (NATS/Redis subscribers, indexer query/evidence)
StellaOps.Infrastructure.Postgres.MigrationsAddStartupMigrations auto-migration of the timeline schema
StellaOps.Audit.EmissionShared library other services use to push events to /api/v1/audit/ingest (wire contract)
RouterService mesh routing and discovery
AuthorityJWT/OAuth token validation and scope policies
NotifyDownstream consumer of pending anomaly alerts (dispatch worklist)

Configuration

KeyPurpose
Postgres:Timeline:ConnectionString (+ SchemaName, CommandTimeoutSeconds)timeline schema connection used by both migration runners, the audit store, and the indexer.
Eventing:* (ServiceName, UseInMemoryStore, ConnectionString, SignEvents, EnableOutbox)HLC event store wiring. UseInMemoryStore=true fails closed at runtime.
Ingestion:Nats:Enabled / Ingestion:Redis:Enabled (+ Url/ConnectionString, Subject/Stream, queue/consumer group, batch/prefetch)Ingestion transports. Outside Testing, at least one must be enabled or startup fails (ValidateOnStart).
UnifiedAudit:Sources:{Authority,JobEngine,Policy,EvidenceLocker,Notify} (or STELLAOPS_*_URL)Base URLs for the legacy HTTP audit poller (now neutered, retained for transition).
UnifiedAudit:FetchLimitPerModule, UnifiedAudit:RequestTimeoutSecondsLegacy HTTP poller tuning.
AuditRetentionPurge:{Enabled,DryRun,InitialDelay,Interval}Scheduled retention purge service.
Timeline:BaselineRollup:{Enabled,IntervalSeconds,BatchSize,MaxDistinctGroups} (or TIMELINE_BASELINE_ROLLUP_INTERVAL_SECONDS / TIMELINE_BASELINE_ROLLUP_MAX_DISTINCT_GROUPS)Actor-behavior baseline rollup hosted service. MaxDistinctGroups defaults to 10,000 and is clamped to 20,000 as the per-pass memory safety ceiling.
Router:*, Cors, localizationStandard Stella service wiring. Env vars are also bound with the TIMELINE_ prefix.

Endpoints

Scopes: timeline:read, timeline:write, timeline:admin (mapped to the Timeline.Read/Timeline.Write/Timeline.Admin policies), plus the narrow audit:ingest machine scope accepted by the ingest policy. Interactive callers authenticate with an Authority JWT. Router-forwarded internal callers use a verified, short-lived signed identity envelope. Direct service HTTP callers use an Authority-issued bearer token: ExportCenter’s audit-bundle reader requests only tenant-bound timeline:read, while emitters use tenant-bound audit:ingest. Neither path may derive tenant identity from a raw header.

HLC timeline — /api/v1/timeline/hlc/*

MethodPathScopeDescription
GET/api/v1/timeline/hlc/{correlationId}readQuery events by correlation ID (HLC-ordered); supports limit/offset/fromHlc/toHlc/services/kinds.
GET/api/v1/timeline/hlc/{correlationId}/critical-pathreadCritical path analysis (longest latency stages) for a correlation.
POST/api/v1/timeline/hlc/{correlationId}/replaywriteInitiate deterministic replay (dry-run/verify). 501 outside Dev/Test.
GET/api/v1/timeline/hlc/replay/{replayId}writeReplay status lookup.
POST/api/v1/timeline/hlc/replay/{replayId}/cancelwriteCancel replay operation.
DELETE/api/v1/timeline/hlc/replay/{replayId}writeDelete/cancel a replay operation.
POST/api/v1/timeline/hlc/{correlationId}/exportwriteInitiate timeline export (NDJSON/JSON, optional DSSE signing). 501 outside Dev/Test.
GET/api/v1/timeline/hlc/export/{exportId}writeExport status lookup.
GET/api/v1/timeline/hlc/export/{exportId}/downloadwriteDownload the completed export bundle.

Indexer event queries — /api/v1/timeline/* (and bare /timeline/*)

MethodPathScopeDescription
GET/api/v1/timelinereadList indexer events for the tenant (filters: eventType, source, correlationId, traceId, severity, since, after, limit).
GET/api/v1/timeline/{eventId}readGet a single indexer event.
GET/api/v1/timeline/{eventId}/evidencereadGet evidence linkage (bundle/attestation digests) for an event.
POST/api/v1/timeline/eventswriteIngests a TimelineEventEnvelope through the same scoped ITimelineIngestionService the message-bus worker (TimelineIngestionWorker) uses: validates required fields, enforces tenant ownership against the authenticated tenant, and persists via the indexer store. Returns 202 Accepted with { "status": "accepted", "eventId": … } on insert, 200 OK with { "status": "duplicate", … } on an idempotent re-submit, 400 for a missing body / missing required field, and 403 if the body tenant differs from the caller’s tenant.

Unified audit — /api/v1/audit/*

MethodPathScopeDescription
POST/api/v1/audit/ingestaudit:ingest or writeIngest a single audit event from any service (202 Accepted); the authenticated tenant is bound to the payload tenant.
GET/api/v1/audit/eventsreadPostgreSQL-filtered event list with exact total count and stable (timestamp DESC, id ASC) cursor pagination. An unknown cursor preserves first-page behavior.
GET/api/v1/audit/events/{eventId}readEvent-by-id lookup.
GET/api/v1/audit/statsreadExact tenant-scoped PostgreSQL summary statistics, including top actors/resources.
GET/api/v1/audit/timeline/searchreadTenant-filtered timeline search (q, date range, limit) without the legacy 10,000-event truncation.
GET/api/v1/audit/correlationsreadTenant-filtered correlation cluster list without the legacy 10,000-event truncation.
GET/api/v1/audit/correlations/{correlationId}readCorrelation cluster details.
GET/api/v1/audit/chain/verifyreadVerify the SHA-256 hash chain integrity for a tenant (optional sequence range).
GET/api/v1/audit/anomaliesreadList anomaly alerts (acknowledged, limit).
POST/api/v1/audit/anomalies/{alertId}/acknowledgewriteAcknowledge an anomaly alert.
GET/api/v1/audit/anomalies/_pending-dispatchadminPending, unacknowledged alerts for Notify dispatch fan-out.
POST/api/v1/audit/anomalies/{alertId}/dispatchedadminMark an alert dispatched after Notify fan-out succeeds.
POST/api/v1/audit/anomalies/{alertId}/dispatch-failedadminTerminally mark an alert failed after Notify exhausts retries.
GET/api/v1/audit/anomalies/rulesadminList tenant-scoped anomaly rule configuration.
POST/api/v1/audit/anomalies/rulesadminCreate an anomaly rule.
PUT/api/v1/audit/anomalies/rules/{id}adminUpdate an anomaly rule.
DELETE/api/v1/audit/anomalies/rules/{id}adminDelete an anomaly rule.
POST/api/v1/audit/exportwriteRequest a unified audit export with an exact PostgreSQL-filtered event count.
GET/api/v1/audit/export/{exportId}readExport status lookup.
GET/api/v1/audit/retention-policiesreadEffective retention window (days) per classification for the tenant.
DELETE/api/v1/audit/actors/{actorId}/piiadminGDPR Art. 17 right-to-erasure: redact actor PII while keeping the hash chain verifiable.

Health

MethodPathDescription
GET/healthRuns the registered TimelineHealthCheck, which probes the StellaOps.Eventing event store (CountByCorrelationIdAsync).
GET/health/ready, /health/livePredicate-filtered (ready/live tags). TimelineHealthCheck is registered without tags, so no checks currently match either predicate and both return healthy once the host is up.

Observability

Metrics and traces are emitted from the StellaOps.Timeline meter / ActivitySource (both version 1.0.0), defined in TimelineMetrics (StellaOps.Timeline.Core/Telemetry/TimelineMetrics.cs).

Metrics

InstrumentTypeUnitTagsDescription
stellaops_timeline_queries_totalCounterquery_typeHLC timeline queries.
stellaops_timeline_query_duration_secondsHistogramsquery_type, event_count_bucketHLC query latency.
stellaops_timeline_replays_totalCountermode, statusReplay operations.
stellaops_timeline_replay_duration_secondsHistogramsmode, event_count_bucketReplay latency.
stellaops_timeline_exports_totalCounterformat, signedExport operations.
stellaops_timeline_export_size_bytesHistogramByformat, event_count_bucketExported bundle size.
stellaops_timeline_cache_hits_total / stellaops_timeline_cache_misses_totalCountercache_typeQuery cache hit/miss.
timeline_baseline_rollup_duration_secondsHistogramsAnomaly v2 actor-baseline rollup pass duration.
timeline_baseline_rollup_rows_upserted_totalCounterActor-baseline rows upserted by rollups.
timeline_baseline_rollup_degraded_totalCounterreasonRollup passes that completed with an explicitly partial projection.
timeline_baseline_rollup_omitted_source_events_totalCounterreasonSource events omitted from partial rollups after the distinct-group hard bound was reached.
timeline_baseline_actor_countObservableGaugetenant_idPer-tenant actor count from the latest baseline rollup.

event_count_bucket is bucketed as 1-10 / 11-100 / 101-1000 / 1001-10000 / 10000+.

Traces

SpanKindTags
timeline.queryServercorrelation_id, query_type
timeline.replayServercorrelation_id, mode

Security Considerations

TimelineIndexer (Event Ingestion and Indexing)

TimelineIndexer was consolidated into the Timeline module (Sprint 210, 2026-03-04). It provides the write/ingestion side of the CQRS pattern while Timeline provides the read/query side. Both share the same schema domain and live under src/Timeline/.

TimelineIndexer Responsibilities

Ingestion Transport Contract

Deployable Services

The merged design keeps ingestion and query co-hosted while sharing domain libraries under a single module boundary. (Roadmap: the dormant projects are retained should ingestion ever need to scale out as a separate container again.)