{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://yovision.local/contracts/event-v0.1.schema.json", "title": "YoVision Event Instance v0.1", "description": "推理侧 → 平台侧的唯一契约。冻结于 2026-08-03。所有顶层键必须存在(可为 null),不允许省略——省略与显式 null 无法区分,是这类系统最常见的排查陷阱。", "type": "object", "additionalProperties": false, "required": [ "schema_version", "id", "source_event_id", "tenant_id", "site_id", "device_id", "sensors", "kind", "severity", "confidence", "occurred_at", "detected_at", "latency_seconds", "config_version", "rule", "subject", "observation", "evidence", "dedup_key", "aggregated_into", "outcome", "outcome_source", "outcome_reason", "diagnostics", "ext" ], "properties": { "schema_version": { "description": "契约版本。破坏性变更必须递增主版本。", "const": "0.1" }, "id": { "description": "平台侧生成的全局唯一事件 ID(ULID)。推理侧不得自行生成。", "type": "string", "pattern": "^evt_[0-9A-HJKMNP-TV-Z]{26}$" }, "source_event_id": { "description": "推理侧原始事件 ID,如 silver_pose 的 FALL--000001。用于回溯本地截图文件名(截图即按它命名)。会话内唯一,全局不保证唯一——不得用作主键。", "type": "string", "pattern": "^[A-Za-z0-9_-]{1,128}$" }, "tenant_id": { "type": "integer", "minimum": 1 }, "site_id": { "type": "integer", "minimum": 1 }, "device_id": { "description": "主传感器的平台设备实体主键。由推理侧的 source_id 经平台映射表解析得到。事件中不得冗余 RTSP 地址或任何凭据。多传感器融合事件的完整来源见 sensors。", "type": "integer", "minimum": 1 }, "sensors": { "description": "参与本次判定的全部传感器。单摄像头事件为单元素数组。恰好一个元素的 role 为 primary,且其 device_id 必须等于顶层 device_id。", "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["device_id", "modality", "role"], "properties": { "device_id": { "type": "integer", "minimum": 1 }, "modality": { "description": "设备模态。决定隐私区域准入:privacy_flag 为真的区域只允许非成像模态。", "type": "string", "enum": ["video", "radar", "contact", "button", "wearable", "other"] }, "role": { "description": "primary=判定主依据;corroborating=佐证(如雷达判跌倒、门磁佐证无人离开)。", "type": "string", "enum": ["primary", "corroborating"] } } } }, "kind": { "description": "事件类型。取值登记在 contracts/README.md 的类型注册表中,新增类型不需要升 schema 版本。v0.1 已登记:fall。", "type": "string", "pattern": "^[a-z][a-z0-9_]{2,63}$" }, "severity": { "type": "string", "enum": ["low", "medium", "high", "critical"] }, "confidence": { "description": "模型置信度。几何+状态机判定链路没有天然来源,必须填 null——不得用任意常量或阈值余量伪造。", "type": ["number", "null"], "minimum": 0, "maximum": 1 }, "occurred_at": { "description": "事发时刻(墙钟 UTC)。决定证据回捞窗口。推理侧若只有单调时钟,按 detected_at - latency_seconds 换算。", "type": "string", "format": "date-time" }, "detected_at": { "description": "判定成立时刻(墙钟 UTC)。决定 SLA 计算。必须 >= occurred_at。", "type": "string", "format": "date-time" }, "latency_seconds": { "description": "从可疑到确认的耗时。可由两时间戳相减,但显式存储:它是判定质量的直接指标——贴近确认窗口下限说明证据干脆,贴近上限是误报高发区,为误报排查的首选排序键。", "type": "number", "minimum": 0 }, "config_version": { "description": "产出本事件时整套判定配置的版本。粒度高于 rule.version(阈值往往是全局的),用于调参后的回归对比。不得为空串。", "type": "string", "minLength": 1, "maxLength": 128 }, "rule": { "description": "命中的规则实体。推理侧无规则引擎时为 null,由平台侧按 kind 反查补全。", "type": ["object", "null"], "additionalProperties": false, "required": ["id", "version", "code"], "properties": { "id": { "type": "string" }, "version": { "type": "integer", "minimum": 1 }, "code": { "type": "string" } } }, "subject": { "type": "object", "additionalProperties": false, "required": ["class", "track_id", "attributes", "anon_id", "identity", "identity_status"], "properties": { "class": { "type": "string", "enum": ["person", "vehicle", "object"] }, "track_id": { "description": "跟踪器内的短期标识,跨会话不保证稳定。", "type": "string", "minLength": 1 }, "attributes": { "description": "A 类属性(年龄段、着装等)。未启用时为空对象,不是 null。", "type": "object" }, "anon_id": { "description": "B+ 类 ReID 匿名标识,站点内会话级有效(≤30min),不做跨日长期关联。未启用为 null。", "type": ["string", "null"] }, "identity": { "description": "C 类人脸身份。仅在租户已授权且比对命中时非 null。", "type": ["object", "null"], "additionalProperties": false, "required": ["person_id", "library_id", "score"], "properties": { "person_id": { "type": "string" }, "library_id": { "type": "string" }, "score": { "type": "number", "minimum": 0, "maximum": 1 } } }, "identity_status": { "description": "必须显式。只写 null 无法区分「没开这功能」与「比对失败」,后者是需要排查的故障。", "type": "string", "enum": ["not_enabled", "pending", "matched", "below_threshold", "no_candidate", "timeout"] } } }, "observation": { "description": "结构化观测。bbox/keypoint 序列是数据闭环的唯一原料——只有视频与截图无法用于训练。", "type": ["object", "null"], "additionalProperties": false, "required": ["zone", "dwell_sec", "bbox_seq_uri", "keypoint_seq_uri", "signal_seq_uri"], "properties": { "zone": { "type": ["string", "null"] }, "dwell_sec": { "type": ["number", "null"], "minimum": 0 }, "bbox_seq_uri": { "description": "视觉模态专用。非视觉事件为 null。", "type": ["string", "null"], "format": "uri" }, "keypoint_seq_uri": { "description": "COCO-17 关键点逐帧序列(JSONL)。视觉模态专用,P1 必补项。", "type": ["string", "null"], "format": "uri" }, "signal_seq_uri": { "description": "非视觉模态的结构化序列(雷达点云轨迹与多普勒、门磁状态变迁等,JSONL)。与 keypoint_seq_uri 平级——两者是各自模态的数据闭环原料,缺任一模态的序列,该模态就无法参与模型迭代。", "type": ["string", "null"], "format": "uri" } } }, "evidence": { "type": "object", "additionalProperties": false, "required": ["snapshot_uris", "clip_uri", "clip_range"], "properties": { "snapshot_uris": { "description": "证据截图。**允许为空数组**:非成像模态(雷达、门磁)产出的事件本就没有画面,隐私区域更是禁止成像。不得据此假设每个事件都有图可看——值班台 UI 必须能渲染无画面事件。文件命名只允许包含事件 ID 与日期目录,绝不得含 RTSP 地址、凭据或客户名称,文件名会出现在日志、URL 与工单中。", "type": "array", "minItems": 0, "items": { "type": "string", "format": "uri" } }, "clip_uri": { "description": "含 pre-roll 的证据片段。仅有截图不足以让值班员判断真假,是误报反馈闭环的前置条件。P1 必补项。", "type": ["string", "null"], "format": "uri" }, "clip_range": { "type": ["array", "null"], "minItems": 2, "maxItems": 2, "items": { "type": "string", "format": "date-time" } } } }, "dedup_key": { "description": "跨机位/跨时间去重键,由平台侧构造。推理侧进程内按 source_event_id 的去重仍保留——它防的是同帧重复写盘,属不同层次。", "type": ["string", "null"] }, "aggregated_into": { "description": "被合并入的事件 ID。非 null 时本事件不独立触发告警。", "type": ["string", "null"], "pattern": "^evt_[0-9A-HJKMNP-TV-Z]{26}$" }, "outcome": { "description": "处置结果。事件不可变,误判只能通过本字段标记,不得删改。subject_recovered 由推理侧状态机自动回传(确认后自行起身),无需等人工。", "type": "string", "enum": [ "unknown", "true_positive", "false_positive", "subject_recovered", "duplicate", "test" ] }, "outcome_source": { "type": ["string", "null"], "enum": ["auto", "manual", null] }, "outcome_reason": { "type": ["string", "null"] }, "diagnostics": { "description": "推理侧内部诊断量,仅用于排查,平台不得依赖其语义。单调时钟跨进程无意义,不得用于任何时间计算。", "type": ["object", "null"], "additionalProperties": true, "properties": { "fsm_state": { "type": "string", "enum": ["NORMAL", "SUSPECT", "CONFIRMED", "RECOVERING"] }, "suspected_at_monotonic": { "type": "number" }, "confirmed_at_monotonic": { "type": "number" }, "horizontal_angle_degrees": { "type": ["number", "null"] }, "visible_joint_count": { "type": ["integer", "null"], "minimum": 0, "maximum": 17 } } }, "ext": { "description": "厂商/场景扩展位。根对象 additionalProperties=false,任何未登记字段一律放这里,避免为实验性字段升版本。", "type": "object" } } }