CanonicalEvent {
eventId, facilityId, eventType, occurredAt,
licencePlate?, externalSessionId?,
location?: { levelId?, zoneId?, spaceId? },
equipment?: { equipmentId?, type? },
requestId?, movementId?, vehicle?, pricing?,
fault?, sourceSystem?, metadata?
}
Required for every event:
eventId + facilityId + eventType + occurredAt
Vehicle events additionally require licencePlate.ParkingSession {
internalSessionId, externalSessionId?, licencePlate,
status, completeness, events[], issues[],
arrivalAt?, storedAt?, retrievalRequestedAt?,
readyAt?, exitedAt?, levelId?, zoneId?, spaceId?
}
DataIssue {
type, sessionId?, eventIds[], missingRequirements[],
candidates[], affectedMetrics[], explanation
}Facility {
id, name, levels[], accessPoints[], equipment[]
}
Level { id, facilityId, zones[] }
Zone { id, levelId, spaces[] }
Space {
id, zoneId, usable,
maxWidth?, maxHeight?, maxWeight?
}
Equipment {
id, facilityId, type, location?, label
}MetricResult<T> {
value?: T, availability,
numerator?, denominator?, sampleSize?,
coveragePercent, requiredEvents[],
missingRequirements[], range, comparison?,
methodologyVersion
}
Never encode unavailable as zero.
Never describe time overlap as causation.