Skip to main content

AI_INTEGRATION — analytics-service

Sibling: APPLICATION_LOGIC · DOMAIN_MODEL · DATA_MODEL §5.6 · platform anchors: docs/08 AI Architecture, docs/07 §11

analytics-service is the read-side data plane for the platform's AI stack. It does not run inference itself. Two relationships matter:

  • Outbound: we publish aggregated, AI-ready signals (metric.computed.v1) and expose curated tables that ai-orchestrator-service queries through its own service account.
  • Inbound: we consume melmastoon.ai.forecast.produced.v1 and writeback model outputs into fact_demand_forecast_v1 so dashboards and reporting-service can show forecasts side-by-side with actuals.

We also use the platform AIClient for two narrowly scoped capabilities used inside analytics-service itself.


1. Capabilities exposed to the platform

CapabilityProducerConsumerPurpose
metric.computed.v1 events for a forecast feature setthis serviceai-orchestrator-serviceInputs to demand-forecast model
Curated read access to fact_reservation_v1, fact_payment_v1, dim_*this service (BigQuery view binding)ai-orchestrator-service (own GSA)Training and feature extraction
dim_calendar_v1 shared dimensionthis serviceall model consumersStable date attributes, holidays
Write-target fact_demand_forecast_v1this serviceai-orchestrator-service (event-driven writeback)Forecast outputs

The orchestrator's GSA is granted roles/bigquery.dataViewer on the curated dataset and on per-tenant authorized views; it does not have access to events_raw.* to limit raw PII exposure.


2. Capabilities used by analytics-service

Capability keyGoalPatternSurface
analytics.metric_explainer.v1Plain-language explanation of a metric value & trend ("Occupancy fell 18 % vs 4-week median; explained by a 30 % drop in OTA bookings on Sun")LLM with grounded numeric factsAPI: GET /api/v1/analytics/metrics/{key}/explain?from=…&to=…
analytics.dashboard_assistant.v1Convert a natural-language ask ("show me last month's RevPAR vs forecast for Property A") into a widget specLLM tool-use over metric registryAPI: POST /api/v1/analytics/ai/widget-draft

Both flow through ai-orchestrator-service over the AIClient port. They are off by default and enabled per tenant in tenant settings.


3. Capability invariants

  1. Tenant-scoped. Every call carries tenantId, optional userId, correlationId. Orchestrator enforces tenant model allow-list and data residency.
  2. No raw PII as prompt context. Prompts include only aggregated values, dimensions, and metric metadata. We never send guest names, document numbers, or raw event payloads.
  3. Citations required. Outputs are stored with AIProvenance (DOMAIN_MODEL §2) and rendered with an "AI-generated · review before sharing" badge. Explanations include numeric citations referenced back to the underlying fact rows by (metric_key, window, dimension_value).
  4. HITL for write actions. "Apply this draft widget" creates a draft Widget with a flag and never mutates the live dashboard until a human confirms (POST /api/v1/analytics/widgets/{id}:confirm).
  5. Budget guardrails. Per-tenant monthly cap configured via tenant-service. Orchestrator returns 429 MELMASTOON.AI.BUDGET_EXHAUSTED and we degrade gracefully (skip explanation; surface raw values).
  6. Off-switch. Tenant admin can disable any capability under Settings → AI; the off-switch is enforced server-side.

4. Outbound feature signal pipeline

[ETL completes]

[ComputeMetricUseCase] computes the forecast feature set per (tenant, property, room_type, business_date) at 06:00 local

publish: melmastoon.analytics.metric.computed.v1 (one envelope per feature batch)

[ai-orchestrator-service] subscribes selectively to feature metric keys

[forecast-model] produces predictions + confidence intervals

publish: melmastoon.ai.forecast.produced.v1

[analytics-service.IngestForecastWritebackUseCase]

MERGE INTO fact_demand_forecast_v1 …

publish: melmastoon.analytics.projection.refreshed.v1 (target: fact_demand_forecast_v1)

Feature set keys (default): reservation.occupancy_pct, reservation.adr, reservation.alos_nights, reservation.cancellation_rate, funnel.meta_to_book_pct, channel.revenue_mix_pct, housekeeping.task_throughput. Lead times, day-of-week, and holiday flags come from dim_calendar_v1.


5. Forecast writeback contract

Inbound payload melmastoon.ai.forecast.produced.v1:

interface AIForecastProducedV1 {
tenantId: string;
forecastId: string; // fcs_<ulid>
modelId: string; // 'demand_forecast'
modelVersion: string; // '2026.04.01-v3'
producedAt: string;
predictions: Array<{
propertyId: string;
roomTypeId: string;
businessDate: string;
horizonDays: number;
predictedOccupancyPct: number;
predictedAdr: number;
ci80LowOccupancy: number;
ci80HighOccupancy: number;
}>;
provenance: AIProvenance;
}

Writeback logic:

  • Validate tenant and property scope (every prediction must belong to the envelope's tenant).
  • Idempotency: MERGE on (tenant_id, property_id, room_type_id, business_date, horizon_days, model_version).
  • Bound batch sizes (≤ 5,000 rows per envelope). Larger payloads are split by the publisher.
  • Reject (MELMASTOON.ANALYTICS.FORECAST_INVALID_TENANT) if the envelope's tenantId mismatches a row.

6. Provenance & audit

Every AI-affected analytics output stores a non-null aiProvenance on the relevant entity (widget snapshot, metric explanation, widget draft). The completed event payloads include metadata.ai. Acceptance is measured by the platform-shared metric ai_orchestrator.acceptance_rate:

  • For analytics.dashboard_assistant.v1: drafted widgets that are subsequently confirmed.
  • For analytics.metric_explainer.v1: explanations that the user kept (vs dismissed).

7. Privacy & residency

  • AI calls inherit tenant.dataResidency. If a tenant's residency is KSA and the only model satisfying the capability is EU-hosted, the orchestrator returns MELMASTOON.AI.RESIDENCY_VIOLATION and we degrade.
  • Explanations cite numeric facts present in the rendered widget; the renderer rejects any citation whose factRef does not resolve.
  • Tenant admin can require that prompts never be retained by the orchestrator (tenant.aiSettings.retainPrompts === false).

8. Failure & degradation matrix

FailureEffectUX
Orchestrator timeout (> maxLatencyMs)Skip explanation; emit warningWidget renders without AI block
Orchestrator 5xxSkip + structured warn log; circuit-breaker opens for 60 s
Budget exhaustedSkip + once-per-day notify tenant.owner
Residency violationSkip; structured warn log
Forecast writeback validation failDrop the offending row; log; emit data_quality.alert.v1 { severity: 'critical' }Operator alerted
Forecast writeback partial failMERGE within tx; partial commit not allowed; entire envelope rejected for retryn/a

9. Cross-references