feat(iot): Wave 4 Round 1 — B12/B4/B5 告警状态机 + 规则引擎 SPI

主会话 Opus:
- B12 iot_alarm_record 正交状态机(ack_state + clear_state + archived)
  * V2.0.4__iot_alarm_record.sql:主表 + iot_alarm_propagation 关联表
  * 评审 C1 正交三字段(替代线性 4 枚举,表达"已清除未确认")
  * 评审 C2 联合 UK (device_id, alarm_config_id, tenant_id, deleted)
  * 评审 C3 传播关联表(替代 propagated_to JSON 查询)
  * Service 5 方法:triggerAlarm / ackAlarm / unackAlarm / clearAlarm / archiveAlarm
  * 幂等 upsert(trigger_count++)+ 归档后禁止修改
  * 13 单元测试全绿
  * TODO B14 分布式锁 / B15 传播 / B16 通知

Sonnet subagent B4:TriggerProvider SPI + 5 内置触发器
  * spi/TriggerProvider + TriggerProviderManager(@Component + getType 索引,fail-fast 重复 type)
  * trigger/DeviceState / DeviceProperty / DeviceEvent / DeviceService / Timer(Spring TaskScheduler)
  * 评审 A3 落地:禁 ServiceLoader / @SPI
  * 44 单元测试全绿

Sonnet subagent B5:ConditionEvaluator SPI + 3 条件 + 统一模板变量
  * spi/ConditionEvaluator + condition/Manager
  * condition/Expression(Aviator + LRU(256) 编译缓存)
  * condition/TimeRange(跨午夜支持)
  * condition/DeviceState(Redis 查询,空值按 offline)
  * template/TemplateResolver:\${namespace.key},拒绝 \$[...] 旧语法(评审 B5)
  * TODO B44 完整 8 层 Aviator 沙箱
  * 50 单元测试全绿(TemplateResolver 16 + 条件 3x ≈ 34)

测试汇总:rule 136 全绿 / server 13 新增全绿

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet (subagent) <noreply@anthropic.com>
This commit is contained in:
lzh
2026-04-24 00:35:14 +08:00
parent 1f87d599c0
commit 42466363c7
38 changed files with 3900 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
-- [B12] iot_alarm_record + iot_alarm_propagation 正交状态机
-- 版本: V2.0.4(任务卡命名 V2.0.0,但已有 V2.0.1-V2.0.3 故递增至 V2.0.4
-- 评审修正:
-- C1ack_state + clear_state + archived 三字段正交替代线性 4 枚举
-- C2联合 UK 替代 MD5 哈希列
-- C3iot_alarm_propagation 关联表替代 propagated_to JSON
CREATE TABLE IF NOT EXISTS iot_alarm_record (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
alarm_config_id BIGINT NOT NULL COMMENT '告警配置 ID',
alarm_name VARCHAR(128) COMMENT '告警名称(冗余 config.name避免反查',
severity TINYINT NOT NULL COMMENT '严重度 1-5CRITICAL/MAJOR/MINOR/WARNING/INFO',
-- 【评审 C1】正交三字段替代线性状态机
ack_state TINYINT NOT NULL DEFAULT 0 COMMENT '确认状态 0=未确认 1=已确认',
clear_state TINYINT NOT NULL DEFAULT 0 COMMENT '清除状态 0=活跃 1=已清除',
archived TINYINT NOT NULL DEFAULT 0 COMMENT '归档 0=未归档 1=已归档(归档后不可修改)',
device_id BIGINT NOT NULL COMMENT '设备编号',
product_id BIGINT COMMENT '产品编号(冗余)',
subsystem_id BIGINT COMMENT '归属子系统(评审 R2',
rule_chain_id BIGINT COMMENT '触发此告警的 v2 规则链',
scene_rule_id BIGINT COMMENT '触发此告警的 v1 场景规则(灰度期兼容)',
start_ts DATETIME NOT NULL COMMENT '首次触发时间',
end_ts DATETIME COMMENT '最近触发时间',
clear_ts DATETIME COMMENT '清除时间',
ack_ts DATETIME COMMENT '确认时间',
archive_ts DATETIME COMMENT '归档时间',
details JSON COMMENT '告警详情(可累积)',
trigger_count INT NOT NULL DEFAULT 1 COMMENT '持续触发次数',
process_remark TEXT COMMENT '处理备注',
tenant_id BIGINT NOT NULL COMMENT '租户编号',
creator VARCHAR(64) COMMENT '创建者',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updater VARCHAR(64) COMMENT '更新者',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted BIT NOT NULL DEFAULT b'0' COMMENT '是否删除',
-- 【评审 C2】联合 UK 替代 MD5 哈希列
UNIQUE KEY uk_device_config (device_id, alarm_config_id, tenant_id, deleted),
-- 查询优化索引(状态组合 + 租户 + 时间)
INDEX idx_state (tenant_id, clear_state, ack_state, archived, start_ts),
INDEX idx_severity (tenant_id, severity, start_ts),
INDEX idx_subsystem (tenant_id, subsystem_id, start_ts),
INDEX idx_rule_chain(rule_chain_id),
INDEX idx_device (device_id, start_ts)
) COMMENT = '告警记录v2.0 正交状态机)';
-- 【评审 C3】告警传播关联表替代 propagated_to JSON 高频查询)
CREATE TABLE IF NOT EXISTS iot_alarm_propagation (
alarm_record_id BIGINT NOT NULL COMMENT '告警记录 ID',
asset_type VARCHAR(32) NOT NULL COMMENT 'SUBSYSTEM / FLOOR / BUILDING',
asset_id BIGINT NOT NULL COMMENT '资产 ID',
asset_name VARCHAR(128) COMMENT '资产名称冗余',
tenant_id BIGINT NOT NULL COMMENT '租户编号',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (alarm_record_id, asset_type, asset_id),
INDEX idx_asset (asset_type, asset_id, tenant_id),
INDEX idx_record (alarm_record_id)
) COMMENT = '告警沿资产层级传播关联表(评审 C3';