ai-orchestrator-service — Event Schemas
Companion to:
DOMAIN_MODEL.md·APPLICATION_LOGIC.md· Standards: 04 Event-Driven Architecture · NAMING
All events follow the platform CloudEvents-compatible envelope (see 04-event-driven-architecture.md §3). Subjects follow melmastoon.<service>.<aggregate>.<verb-past-tense>.v<n>. Service prefix is ai_orchestrator. Schemas are version-controlled in @ghasi/event-envelope/schemas/ai-orchestrator/ and registered with the platform schema registry. Breaking changes require a v<n+1> topic.
1. Envelope (reference)
interface DomainEvent<T> {
id: string; // 'evt_<ULID>'
subject: string; // 'melmastoon.ai_orchestrator.inference.completed.v1'
source: 'ai-orchestrator-service';
specVersion: '1.0';
type: string; // mirrors subject
time: string; // ISO-8601
tenantId: string; // 'tnt_<ULID>'
correlation: { traceId: string; requestId: string; causationId?: string };
data: T; // event-specific payload (schemas below)
retention: 'operational' | 'regulated' | 'audit';
schemaUri: string; // 'https://schemas.melmastoon.ghasi.io/ai-orchestrator/inference-completed.v1.json'
}
2. Retention classes
| Class | TTL | Examples |
|---|---|---|
operational | 30 d | inference.requested, inference.cached_hit, model.deployment_changed |
regulated | 7 y (BigQuery long-term) | inference.completed, hitl.gate_decided, budget.exceeded, moderation.flagged (carry decisions/cost/risk material) |
audit | 7 y (audit-service) | All events with HITL outcomes, all prompt.version_published, all edge_model.manifest_updated |
3. Events Published
3.1 melmastoon.ai_orchestrator.inference.requested.v1
Fires on every accepted call to /api/v1/ai/complete, /embed, /rag/query, /vision, /transcribe (one per accepted request).
interface InferenceRequested {
requestId: string; // 'ifr_<ULID>'
capability: string; // 'pricing.suggest'
callerService: string;
callerSurface?: 'consumer' | 'tenant-booking' | 'backoffice';
inputBytes: number;
inputHash: string; // 'sha256:...'
redactedInputHash: string;
promptVersionId?: string;
abBucket?: number; // 0..99 (sticky-by-tenant)
context: { local: boolean; regionPin?: string; timeoutMs: number };
}
Retention: operational.
3.2 melmastoon.ai_orchestrator.inference.completed.v1
Fires on every successful return (including cache hit and deterministic fallback paths).
interface InferenceCompleted {
requestId: string; // 'ifr_...'
resultId: string; // 'ifs_...'
capability: string;
promptVersionId?: string;
model: { provider: 'vertex'|'anthropic'|'openai'|'onnx-edge'; name: string; version?: string };
tokens: { input: number; output: number };
costMicros: number;
latencyMs: number;
cacheHit: boolean;
fallbackApplied: boolean;
fallbackReason?: 'budget_hard_cap' | 'all_providers_unhealthy' | 'moderation_block' | 'schema_invalid';
hitl?: { gateId: string; slaDeadline: string };
provenanceId: string;
outputSummary?: string; // ≤ 256 chars; never raw PII
}
Retention: regulated.
3.3 melmastoon.ai_orchestrator.inference.failed.v1
Fires when the fallback chain is exhausted or the request is otherwise unrecoverable.
interface InferenceFailed {
requestId: string;
capability: string;
errorCode: string; // 'MELMASTOON.AI.PROVIDER_UNAVAILABLE' etc.
attempts: { provider: string; modelName: string; errorCode: string; latencyMs: number }[];
}
Retention: regulated.
3.4 melmastoon.ai_orchestrator.inference.cached_hit.v1
Lightweight signal for the cache-hit dashboard. Also produced as part of inference.completed.v1 flag, but a separate event keeps the cache-rate fact table simple.
interface InferenceCachedHit {
requestId: string;
capability: string;
inputHash: string;
cachedAt: string; // when the original result was cached
ttlRemainingSec: number;
}
Retention: operational.
3.5 Capability-specific signal events
These wrap the validated structured output of a capability call so subscribers don't need to re-fetch the artifact. They are emitted in addition to inference.completed.v1 and carry the same requestId for correlation.
melmastoon.ai_orchestrator.suggestion.dynamic_pricing.v1
interface DynamicPricingSuggested {
requestId: string;
propertyId: string;
roomTypeId: string;
date: string; // ISO date
baselineAmountMicros: number;
suggestedAmountMicros: number;
currency: string; // ISO 4217
deviationPctFromBaseline: number;
rationale: string;
confidence: number;
hitl: { required: boolean; gateId?: string };
provenanceId: string;
}
Retention: regulated.
melmastoon.ai_orchestrator.suggestion.demand_forecast.v1
interface DemandForecast {
propertyId: string;
horizonDays: 30 | 60 | 90;
buckets: { date: string; expectedOccupancyPct: number; p10: number; p90: number }[];
notes?: string;
provenanceId: string;
}
Retention: regulated.
melmastoon.ai_orchestrator.suggestion.housekeeping_routing.v1
interface HousekeepingRouting {
propertyId: string;
shiftId: string;
routes: { staffId: string; orderedTaskIds: string[]; estimatedMinutes: number }[];
hitl: { required: boolean; gateId?: string };
provenanceId: string;
}
Retention: operational.
melmastoon.ai_orchestrator.suggestion.shift_optimization.v1
interface ShiftOptimization {
propertyId: string;
weekStartDate: string;
shifts: { staffId: string; date: string; startHHMM: string; endHHMM: string; role: string }[];
hitl: { required: boolean; gateId?: string };
provenanceId: string;
}
Retention: operational.
melmastoon.ai_orchestrator.anomaly.detected.v1
interface AnomalyDetected {
domain: 'booking'|'payment'|'lock'|'login'|'occupancy';
subjectRef: { kind: string; id: string };
riskScore: number; // 0..1
signals: string[]; // ['rapid_fire_booking', 'same_ip', ...]
recommendedAction: 'monitor'|'hold'|'block'|'page';
hitl: { required: boolean; gateId?: string };
provenanceId: string;
}
Retention: regulated.
melmastoon.ai_orchestrator.upsell.recommended.v1
interface UpsellRecommended {
reservationId: string;
guestId: string;
offers: { kind: 'room_upgrade'|'breakfast'|'late_checkout'|'transfer'|'spa'; priceMicros: number; currency: string; rationale: string }[];
channelHint: 'email'|'sms'|'whatsapp'|'in_app';
provenanceId: string;
}
Retention: operational.
melmastoon.ai_orchestrator.message.drafted.v1
interface MessageDrafted {
intent: 'pre_arrival'|'post_stay'|'apology'|'upsell'|'reminder'|'custom';
targetRecipientId: string;
locale: string; // 'ps' | 'fa-AF' | 'ar' | 'en' | 'fr'
subject?: string;
bodyDraft: string; // post-moderation; HITL-gated
hitl: { required: true; gateId: string };
provenanceId: string;
}
Retention: regulated.
melmastoon.ai_orchestrator.review.summarized.v1
interface ReviewSummarized {
propertyId: string;
windowDays: 30 | 90 | 365;
reviewCount: number;
summary: { themes: string[]; sentiment: 'pos'|'neg'|'mixed'; actionable: string[]; topQuotes: string[] };
provenanceId: string;
}
Retention: operational.
melmastoon.ai_orchestrator.ocr.completed.v1
interface OcrCompleted {
guestId?: string; // pre-create flow may not have id yet
documentRef: { kind: 'passport'|'national_id'|'drivers_license'; uri: string };
extractedFields: { fullName: string; dateOfBirth: string; documentNumber: string; nationality: string; expiry: string };
fieldConfidences: Record<string, number>;
hitl: { required: true; gateId: string };
provenanceId: string;
}
Retention: regulated. PII fields are encrypted at rest in audit-service.
melmastoon.ai_orchestrator.transcription.completed.v1
interface TranscriptionCompleted {
audioRef: { uri: string; durationMs: number };
transcript: string;
language: string;
intent?: { action: string; params: Record<string, string> };
provenanceId: string;
}
Retention: operational.
melmastoon.ai_orchestrator.description.drafted.v1
interface DescriptionDrafted {
targetRef: { kind: 'property'|'room_type'|'amenity'|'policy'; id: string };
locale: string;
draft: string;
hitl: { required: true; gateId: string };
provenanceId: string;
}
Retention: operational.
melmastoon.ai_orchestrator.translation.drafted.v1
interface TranslationDrafted {
sourceRef: { kind: string; id: string };
sourceLocale: string;
targetLocale: string;
draft: string;
untranslatableTerms: string[];
hitl: { required: true; gateId: string };
provenanceId: string;
}
Retention: operational.
3.6 melmastoon.ai_orchestrator.hitl.gate_opened.v1
interface HitlGateOpened {
gateId: string; // 'hgt_...'
capability: string;
artifactRef: { kind: string; id: string };
reviewerRoles: string[];
slaDeadline: string;
draftJson: unknown; // size-bounded (≤ 16 KB)
}
Retention: audit.
3.7 melmastoon.ai_orchestrator.hitl.gate_decided.v1
interface HitlGateDecided {
gateId: string;
decisionId: string; // 'dec_...'
outcome: 'accepted' | 'modified' | 'rejected';
modifiedJson?: unknown;
justification?: string;
reviewerUserId: string;
reviewerRole: string;
decidedAt: string;
auto: boolean; // true on timeout-default
}
Retention: audit. Sibling services subscribe to this event to commit the gated state change (e.g., pricing-service publishes the price; notification-service dispatches the message).
3.8 melmastoon.ai_orchestrator.budget.warning.v1
interface BudgetWarning {
scope: { kind: 'tenant_total' | 'capability' | 'feature'; key?: string };
periodKey: string;
tokensUsed: number;
tokensCap: number;
costMicrosUsed: number;
costMicrosCap: number;
pctConsumed: number; // 0.80..0.99
}
Retention: operational.
3.9 melmastoon.ai_orchestrator.budget.exceeded.v1
interface BudgetExceeded {
scope: { kind: 'tenant_total' | 'capability' | 'feature'; key?: string };
periodKey: string;
trippedAt: string;
fallbackBehavior: 'deterministic' | 'refuse';
resetsAt: string;
}
Retention: regulated.
3.10 melmastoon.ai_orchestrator.eval.run_completed.v1
interface EvalRunCompleted {
runId: string; // 'evr_...'
suiteId: string; // 'eva_...'
promptVersionId: string;
modelRef: { provider: string; name: string; version?: string };
scores: Record<string, number>;
verdict: 'green' | 'red' | 'inconclusive';
comparison?: { baselineVersionId: string; deltas: Record<string, number> };
durationMs: number;
}
Retention: audit.
3.11 melmastoon.ai_orchestrator.prompt.version_published.v1
interface PromptVersionPublished {
promptVersionId: string; // 'pmv_...'
canonicalCode: string; // 'PRMP_PRICING_001_v3'
capabilityKey: string;
deprecatedVersionId?: string;
evalRunId: string;
publishedAt: string;
publishedBy: string; // 'usr_...'
}
Retention: audit.
3.12 melmastoon.ai_orchestrator.model.deployment_changed.v1
interface ModelDeploymentChanged {
changeKind: 'health' | 'traffic_share' | 'lifecycle';
modelRef: { provider: string; name: string; version?: string };
region?: string;
before: { health?: string; trafficSharePct?: number; status?: string };
after: { health?: string; trafficSharePct?: number; status?: string };
reason?: string; // e.g. 'circuit_open_5_consecutive_errors'
}
Retention: operational.
3.13 melmastoon.ai_orchestrator.edge_model.manifest_updated.v1
interface EdgeModelManifestUpdated {
manifestId: string; // 'emm_...'
version: string; // semver
supersedesId?: string;
modelKeys: string[];
publishedAt: string;
}
Retention: audit.
3.14 melmastoon.ai_orchestrator.moderation.flagged.v1
interface ModerationFlagged {
requestId: string;
capability: string;
side: 'input' | 'output';
verdict: 'flag_low' | 'flag_high' | 'block';
axes: Record<string, number>; // 'hate', 'sexual', 'dangerous', 'self_harm', 'pii_exposed'
action: 'allowed_with_warning' | 'blocked';
}
Retention: regulated.
4. Events Consumed
These events trigger inference jobs. Subscriber names follow the convention ai-orchestrator.<topic> (e.g., ai-orchestrator.melmastoon.reservation.booking.confirmed.v1).
| Source event | Triggered capability | Notes |
|---|---|---|
melmastoon.reservation.booking.confirmed.v1 | upsell.recommend (immediate); schedule upsell.recommend (T-48h via Cloud Scheduler) | One inference per reservation |
melmastoon.reservation.booking.cancelled.v1 | anomaly.detect (cancellation pattern signal) | Aggregated daily for tenant |
melmastoon.iam.user.login_failed.v1 | anomaly.detect (credential stuffing) | Edge classifier on tenant tally; cloud explanation if riskScore ≥ 0.7 |
melmastoon.payment.transaction.failed.v1 | anomaly.detect (payment fraud) | Edge classifier; HITL on auto-block |
melmastoon.payment.intent.captured.v1 | anomaly.detect (rapid-fire pattern) | Sliding window per IP / payment method |
melmastoon.lock_integration.key_credential.issued.v1 | anomaly.detect (key issuance pattern) | |
melmastoon.lock_integration.key_credential.not_returned.v1 | anomaly.detect (key-not-returned > 24 h) | Daily aggregation job |
melmastoon.housekeeping.task.assigned.v1 (batch flush) | housekeeping.route | One inference per shift assignment batch |
melmastoon.inventory.allocation.committed.v1 (occupancy ≥ 70%) | pricing.suggest for tomorrow | Threshold filter applied in subscriber |
melmastoon.tenant.guest.erasure_requested.v1 | Purge per-tenant embeddings + cached prompt artifacts + redacted inference rows referencing the guest within 7 days | Saga participant; emits melmastoon.audit.guest.erasure_acknowledged.v1 |
melmastoon.tenant.suspended.v1 | Flip per-tenant capability allowlist to read-only | Gateway refuses inference with MELMASTOON.TENANT.SUSPENDED |
melmastoon.tenant.created.v1 | Bootstrap default BudgetCounter rows for tenant + standard RAGCorpus namespaces (policies, faq, sop, amenity) |
5. Schema evolution
- Additive only within a
v<n>topic: new optional fields permitted; required-field changes, type changes, enum-value removals requirev<n+1>. - New topic version is published in parallel for ≥ 30 days. Subscribers migrate; the old topic is then drained and retired.
- The schema registry CI gate fails any PR that publishes a breaking change without a topic bump.
6. Idempotency on consumption
- Inbox table dedupes by Pub/Sub
message.id. - Effective key for AI-triggered inference is
(source.subject, source.event.id, capability)so the same source event won't fire twopricing.suggestcalls. - Capability-specific events carry
requestIdso downstream subscribers (e.g.,notification-serviceconsumingmessage.drafted.v1) dedupe on that.
7. Sample envelope (full)
{
"id": "evt_01H8...",
"subject": "melmastoon.ai_orchestrator.suggestion.dynamic_pricing.v1",
"source": "ai-orchestrator-service",
"specVersion": "1.0",
"type": "melmastoon.ai_orchestrator.suggestion.dynamic_pricing.v1",
"time": "2026-05-12T01:31:09.412Z",
"tenantId": "tnt_01H8...",
"correlation": { "traceId": "00-...-00", "requestId": "req_01H8...", "causationId": "evt_01H8...source" },
"data": {
"requestId": "ifr_01H8...",
"propertyId": "ppt_01H8...",
"roomTypeId": "rmt_01H8...",
"date": "2026-05-13",
"baselineAmountMicros": 4500000000,
"suggestedAmountMicros": 4725000000,
"currency": "USD",
"deviationPctFromBaseline": 0.05,
"rationale": "Occupancy 78% with shoulder-season trend; +5% recommended.",
"confidence": 0.74,
"hitl": { "required": true, "gateId": "hgt_01H8..." },
"provenanceId": "prv_p_01H8..."
},
"retention": "regulated",
"schemaUri": "https://schemas.melmastoon.ghasi.io/ai-orchestrator/suggestion-dynamic-pricing.v1.json"
}