fix: 对齐多配置运行状态语义 (#149)
This commit is contained in:
@@ -25,9 +25,14 @@ Brain 报告的 `runtime.state` 和每个输入的 `state` 使用同一枚举:
|
||||
|
||||
首次有效消息可为任一状态;Sense 只校验同实例连续消息的迁移。`stale`、`offline_*` 不参与 Brain 状态迁移。恢复连接后,只有 schema、时间、sequence 和状态迁移均有效的新消息才能更新投影。
|
||||
|
||||
## 配置 revision
|
||||
## 配置流与 revision
|
||||
|
||||
`configuration.applied_revision` 只表示 Brain 已实际应用的配置。Sense 将它与自己投递成功的期望 revision 比较:相等为 synchronized,不相等为 mismatch。Sense 的期望 revision 不进入本消息,避免产生第二事实源。`not_configured` 时 revision 必须为 null;`applied` 时必须非空;`rejected` 必须带错误码。
|
||||
`configurations` 按 #148 的配置流报告,可以为空,也可以包含多个配置。每项 `config_id` 必须唯一,并与 `yovision.source-config/v1` 的 `config_id` 一致;重复 ID 使整条状态无效,不能覆盖最后已知投影。`applied_revision` 是 Brain 对该配置流已实际应用的 integer revision。Sense 必须逐个 `config_id` 与自己已投递的期望 revision 比较:相等为 synchronized,不相等为 mismatch;Sense 的期望 revision 不进入本消息,避免产生第二事实源。
|
||||
|
||||
- `not_configured`:尚未应用该配置,revision 必须为 null。
|
||||
- `applying`:正在应用;revision 为 null 或仍在运行的上一个 revision。
|
||||
- `applied`:应用成功,revision 必须是大于等于 1 的整数。
|
||||
- `rejected`:本次应用被拒绝;revision 为 null 或最后成功 revision,且必须带稳定错误码。
|
||||
|
||||
## 兼容与回退
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
"observed_at": "2026-08-31T00:00:00Z",
|
||||
"runtime": { "state": "running", "version": "1.0.0", "started_at": null },
|
||||
"model": { "model_ref": "people-detection", "version": "1.0.0" },
|
||||
"configuration": { "apply_state": "applied", "applied_revision": "rev-1", "error_code": null },
|
||||
"configurations": [
|
||||
{ "config_id": "gate-primary", "apply_state": "applied", "applied_revision": 1, "error_code": null }
|
||||
],
|
||||
"health": { "overall": "healthy", "error_codes": [], "metrics": { "load_percent": 1, "queue_depth": 0, "latency_ms": 1 } },
|
||||
"inputs": [],
|
||||
"alert": { "kind": "intrusion" }
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
"observed_at": "2026-08-31T00:00:00Z",
|
||||
"runtime": { "state": "running", "version": "1.0.0", "started_at": null },
|
||||
"model": { "model_ref": "people-detection", "version": "1.0.0" },
|
||||
"configuration": { "apply_state": "applied", "applied_revision": "rev-1", "error_code": null },
|
||||
"configurations": [
|
||||
{ "config_id": "gate-primary", "apply_state": "applied", "applied_revision": 1, "error_code": null }
|
||||
],
|
||||
"health": { "overall": "healthy", "error_codes": [], "metrics": { "load_percent": 1, "queue_depth": 0, "latency_ms": 1 } },
|
||||
"inputs": [],
|
||||
"access_token": "forbidden-example"
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"schema_version": "yovision.runtime-status/v1",
|
||||
"status_id": "018f4d6a-8d1b-4a25-8b37-9085f9c0d206",
|
||||
"brain_instance_ref": "brain-east-01",
|
||||
"sequence": 47,
|
||||
"observed_at": "2026-08-31T00:05:00Z",
|
||||
"runtime": { "state": "degraded", "version": "1.0.0", "started_at": "2026-08-30T23:55:00Z" },
|
||||
"model": { "model_ref": "people-detection", "version": "2026.08.1" },
|
||||
"configurations": [
|
||||
{ "config_id": "gate-primary", "apply_state": "applied", "applied_revision": 21, "error_code": null },
|
||||
{ "config_id": "gate-primary", "apply_state": "rejected", "applied_revision": 20, "error_code": "CONFIG_INVALID" }
|
||||
],
|
||||
"health": {
|
||||
"overall": "degraded",
|
||||
"error_codes": ["CONFIG_INVALID"],
|
||||
"metrics": { "load_percent": 42, "queue_depth": 1, "latency_ms": 31 }
|
||||
},
|
||||
"inputs": []
|
||||
}
|
||||
@@ -6,7 +6,9 @@
|
||||
"observed_at": "2026-08-31T00:00:00Z",
|
||||
"runtime": { "state": "running", "version": "1.0.0", "started_at": null },
|
||||
"model": { "model_ref": "C:\\models\\private.pt", "version": "1.0.0" },
|
||||
"configuration": { "apply_state": "applied", "applied_revision": "rev-1", "error_code": null },
|
||||
"configurations": [
|
||||
{ "config_id": "gate-primary", "apply_state": "applied", "applied_revision": 1, "error_code": null }
|
||||
],
|
||||
"health": { "overall": "healthy", "error_codes": [], "metrics": { "load_percent": 1, "queue_depth": 0, "latency_ms": 1 } },
|
||||
"inputs": []
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
"observed_at": "2026-08-31T00:00:00Z",
|
||||
"runtime": { "state": "running", "version": "1.0.0", "started_at": null },
|
||||
"model": { "model_ref": "people-detection", "version": "1.0.0" },
|
||||
"configuration": { "apply_state": "applied", "applied_revision": "rev-1", "error_code": null },
|
||||
"configurations": [
|
||||
{ "config_id": "gate-primary", "apply_state": "applied", "applied_revision": 1, "error_code": null }
|
||||
],
|
||||
"health": { "overall": "healthy", "error_codes": [], "metrics": { "load_percent": 1, "queue_depth": 0, "latency_ms": 1 } },
|
||||
"inputs": []
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
"observed_at": "2026-08-31T00:00:00Z",
|
||||
"runtime": { "state": "running", "version": "1.0.0", "started_at": null },
|
||||
"model": { "model_ref": "people-detection", "version": "1.0.0" },
|
||||
"configuration": { "apply_state": "applied", "applied_revision": "rev-1", "error_code": null },
|
||||
"configurations": [
|
||||
{ "config_id": "gate-primary", "apply_state": "applied", "applied_revision": 1, "error_code": null }
|
||||
],
|
||||
"health": { "overall": "healthy", "error_codes": [], "metrics": { "load_percent": 1, "queue_depth": 0, "latency_ms": 1 } },
|
||||
"inputs": [],
|
||||
"user_session": { "user": "forbidden" }
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
"observed_at": "2026-08-31T00:01:00Z",
|
||||
"runtime": { "state": "running", "version": "1.0.0", "started_at": "2026-08-30T23:55:00Z" },
|
||||
"model": { "model_ref": "people-detection", "version": "2026.08.1" },
|
||||
"configuration": { "apply_state": "applied", "applied_revision": "sense-rev-20", "error_code": null },
|
||||
"configurations": [
|
||||
{ "config_id": "gate-primary", "apply_state": "applied", "applied_revision": 20, "error_code": null }
|
||||
],
|
||||
"health": {
|
||||
"overall": "healthy",
|
||||
"error_codes": [],
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"schema_version": "yovision.runtime-status/v1",
|
||||
"status_id": "018f4d6a-8d1b-4a25-8b37-9085f9c0d107",
|
||||
"brain_instance_ref": "brain-east-01",
|
||||
"sequence": 46,
|
||||
"observed_at": "2026-08-31T00:04:30Z",
|
||||
"runtime": { "state": "degraded", "version": "1.0.0", "started_at": "2026-08-30T23:55:00Z" },
|
||||
"model": { "model_ref": "people-detection", "version": "2026.08.1" },
|
||||
"configurations": [
|
||||
{ "config_id": "new-stream", "apply_state": "not_configured", "applied_revision": null, "error_code": null },
|
||||
{ "config_id": "yard-secondary", "apply_state": "applying", "applied_revision": 8, "error_code": null },
|
||||
{ "config_id": "gate-primary", "apply_state": "applied", "applied_revision": 21, "error_code": null },
|
||||
{ "config_id": "warehouse", "apply_state": "rejected", "applied_revision": 3, "error_code": "CONFIG_INVALID" }
|
||||
],
|
||||
"health": {
|
||||
"overall": "degraded",
|
||||
"error_codes": ["CONFIG_INVALID"],
|
||||
"metrics": { "load_percent": 42, "queue_depth": 1, "latency_ms": 31 }
|
||||
},
|
||||
"inputs": []
|
||||
}
|
||||
@@ -6,7 +6,10 @@
|
||||
"observed_at": "2026-08-31T00:00:30Z",
|
||||
"runtime": { "state": "degraded", "version": "1.0.0", "started_at": "2026-08-30T23:55:00Z" },
|
||||
"model": { "model_ref": "people-detection", "version": "2026.08.1" },
|
||||
"configuration": { "apply_state": "applied", "applied_revision": "sense-rev-21", "error_code": null },
|
||||
"configurations": [
|
||||
{ "config_id": "gate-primary", "apply_state": "applied", "applied_revision": 21, "error_code": null },
|
||||
{ "config_id": "yard-secondary", "apply_state": "applying", "applied_revision": 8, "error_code": null }
|
||||
],
|
||||
"health": {
|
||||
"overall": "degraded",
|
||||
"error_codes": ["RESOURCE_PRESSURE"],
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"schema_version": "yovision.runtime-status/v1",
|
||||
"status_id": "018f4d6a-8d1b-4a25-8b37-9085f9c0d106",
|
||||
"brain_instance_ref": "brain-east-02",
|
||||
"sequence": 1,
|
||||
"observed_at": "2026-08-31T00:00:00Z",
|
||||
"runtime": { "state": "unconfigured", "version": "1.0.0", "started_at": null },
|
||||
"model": { "model_ref": "people-detection", "version": "2026.08.1" },
|
||||
"configurations": [],
|
||||
"health": {
|
||||
"overall": "healthy",
|
||||
"error_codes": [],
|
||||
"metrics": { "load_percent": 0, "queue_depth": 0, "latency_ms": 0 }
|
||||
},
|
||||
"inputs": []
|
||||
}
|
||||
@@ -6,7 +6,9 @@
|
||||
"observed_at": "2026-08-31T00:01:30Z",
|
||||
"runtime": { "state": "degraded", "version": "1.0.0", "started_at": "2026-08-30T23:55:00Z" },
|
||||
"model": { "model_ref": "people-detection", "version": "2026.08.1" },
|
||||
"configuration": { "apply_state": "applied", "applied_revision": "sense-rev-21", "error_code": null },
|
||||
"configurations": [
|
||||
{ "config_id": "gate-primary", "apply_state": "applied", "applied_revision": 21, "error_code": null }
|
||||
],
|
||||
"health": {
|
||||
"overall": "degraded",
|
||||
"error_codes": ["INPUT_UNREACHABLE"],
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
"observed_at": "2026-08-31T00:04:00Z",
|
||||
"runtime": { "state": "running", "version": "1.0.0", "started_at": "2026-08-30T23:55:00Z" },
|
||||
"model": { "model_ref": "people-detection", "version": "2026.08.1" },
|
||||
"configuration": { "apply_state": "applied", "applied_revision": "sense-rev-21", "error_code": null },
|
||||
"configurations": [
|
||||
{ "config_id": "gate-primary", "apply_state": "applied", "applied_revision": 21, "error_code": null }
|
||||
],
|
||||
"health": {
|
||||
"overall": "healthy",
|
||||
"error_codes": [],
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
"observed_at": "2026-08-31T00:00:00Z",
|
||||
"runtime": { "state": "running", "version": "1.0.0", "started_at": "2026-08-30T23:55:00Z" },
|
||||
"model": { "model_ref": "people-detection", "version": "2026.08.1" },
|
||||
"configuration": { "apply_state": "applied", "applied_revision": "sense-rev-21", "error_code": null },
|
||||
"configurations": [
|
||||
{ "config_id": "gate-primary", "apply_state": "applied", "applied_revision": 21, "error_code": null }
|
||||
],
|
||||
"health": {
|
||||
"overall": "healthy",
|
||||
"error_codes": [],
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
| `observed_at` | 发布观测完成时间 | 校验未来偏差;用它推导 fresh/stale,不用接收时间覆盖 |
|
||||
| `runtime.*` | 报告真实运行状态和脱敏版本 | 校验迁移并形成只读运维状态 |
|
||||
| `model.*` | 报告逻辑模型引用及版本,不报告文件路径 | 显示版本差异,不推导模型下载或重启命令 |
|
||||
| `configuration.*` | 报告真实应用结果和 revision | 与 Sense 内部期望 revision 比较;不回写 Brain 状态 |
|
||||
| `configurations[]` | 每个 `config_id` 报告真实应用结果和 integer revision;同一消息内 ID 唯一 | 按 `config_id` 与 Sense 内部期望 revision 比较;拒绝重复 ID,不回写 Brain 状态 |
|
||||
| `health.*` | 聚合无敏感健康与有界指标 | 展示健康、指标和稳定错误码,不生成业务 Alert |
|
||||
| `inputs[]` | 按逻辑输入发布安全摘要 | 按 `input_ref` 映射运维投影,不读取视频或检测内容 |
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"observed_at",
|
||||
"runtime",
|
||||
"model",
|
||||
"configuration",
|
||||
"configurations",
|
||||
"health",
|
||||
"inputs"
|
||||
],
|
||||
@@ -44,47 +44,49 @@
|
||||
"version": { "$ref": "#/$defs/version" }
|
||||
}
|
||||
},
|
||||
"configuration": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["apply_state", "applied_revision"],
|
||||
"properties": {
|
||||
"apply_state": {
|
||||
"type": "string",
|
||||
"enum": ["not_configured", "applying", "applied", "rejected"]
|
||||
},
|
||||
"applied_revision": {
|
||||
"type": ["string", "null"],
|
||||
"pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$"
|
||||
},
|
||||
"error_code": { "$ref": "#/$defs/nullableErrorCode" }
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"if": {
|
||||
"required": ["apply_state"],
|
||||
"properties": { "apply_state": { "const": "not_configured" } }
|
||||
"configurations": {
|
||||
"type": "array",
|
||||
"maxItems": 4096,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["config_id", "apply_state", "applied_revision", "error_code"],
|
||||
"properties": {
|
||||
"config_id": { "$ref": "#/$defs/configId" },
|
||||
"apply_state": {
|
||||
"type": "string",
|
||||
"enum": ["not_configured", "applying", "applied", "rejected"]
|
||||
},
|
||||
"then": { "properties": { "applied_revision": { "type": "null" } } }
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"required": ["apply_state"],
|
||||
"properties": { "apply_state": { "const": "applied" } }
|
||||
"applied_revision": {
|
||||
"type": ["integer", "null"],
|
||||
"minimum": 1
|
||||
},
|
||||
"then": { "properties": { "applied_revision": { "type": "string", "minLength": 1 } } }
|
||||
"error_code": { "$ref": "#/$defs/nullableErrorCode" }
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"required": ["apply_state"],
|
||||
"properties": { "apply_state": { "const": "rejected" } }
|
||||
"allOf": [
|
||||
{
|
||||
"if": {
|
||||
"required": ["apply_state"],
|
||||
"properties": { "apply_state": { "const": "not_configured" } }
|
||||
},
|
||||
"then": { "properties": { "applied_revision": { "type": "null" } } }
|
||||
},
|
||||
"then": {
|
||||
"required": ["error_code"],
|
||||
"properties": { "error_code": { "$ref": "#/$defs/errorCode" } }
|
||||
{
|
||||
"if": {
|
||||
"required": ["apply_state"],
|
||||
"properties": { "apply_state": { "const": "applied" } }
|
||||
},
|
||||
"then": { "properties": { "applied_revision": { "type": "integer", "minimum": 1 } } }
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"required": ["apply_state"],
|
||||
"properties": { "apply_state": { "const": "rejected" } }
|
||||
},
|
||||
"then": { "properties": { "error_code": { "$ref": "#/$defs/errorCode" } } }
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"health": {
|
||||
"type": "object",
|
||||
@@ -126,6 +128,12 @@
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"configId": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 128,
|
||||
"pattern": "^[A-Za-z0-9][A-Za-z0-9._~-]*$"
|
||||
},
|
||||
"logicalRef": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
|
||||
Reference in New Issue
Block a user