STEP 1593 — Signal/Device 2 層化 Phase 1 Pilot
要旨
benchtop-mcp Signal/Device 2 層化 Phase 1 pilot 実装 (STEP 1536 spec の 具体化 第 1 段)。 別 tab STEP 1571 no-data-primitives.ts (Ophyd NotConnectedError 2-layer distinction) を 認識 + 上位 Signal/Device interface layer を 追加 = 補完 role で collision zero。 pilot example = createDiskHealthDevice() (STEP 1567 disk_health_verdict adapter、 backward compat 完全維持)。
2 層 architecture (実装)
| Layer | Type + Factory | Quality range |
|---|---|---|
| L1 Signal | Signal<T> + createValueSignal({name, unit, fetcher, inRange, connectedProbe}) | {TRUE, NEITHER, INFINITY, ZERO} |
| L2 Device | Device + createVerdictDevice({name, signals, verdictComputer}) | full 8 値 (BOTH / FLOWING / SELF 含む) |
| Pilot | createDiskHealthDevice({smartReader, thresholds}) | STEP 1567 5-case (TRUE/NEITHER/FALSE/INFINITY/ZERO) |
Signal factory quality logic
createValueSignal({name, fetcher, inRange, connectedProbe})
→ SignalReading<T> {value, timestamp, quality, detail?}
Quality mapping:
fetcher returns undefined / null → ZERO (STEP 1571 SensorNoData 相当、 Ophyd NotConnectedError)
fetcher throws → NEITHER (read attempted but failed、 detail に exception message)
fetcher returns value + inRange OK → TRUE
fetcher returns value + out of range → INFINITY (sensor-limit-exceeded、 value 保持で audit 可能)
Device factory quality propagation
createVerdictDevice({name, signals, verdictComputer})
→ DeviceVerdict {device, verdict, reason, signalReadings, timestamp}
Propagation rules:
1. All signals ZERO → device ZERO (no_data、 Ophyd NotConnectedError propagation)
2. Any INFINITY + verdictComputer returns TRUE → auto-promote to INFINITY
3. verdictComputer が INFINITY 認識 or FALSE (safety) 返す → verdictComputer 尊重
4. Otherwise → verdictComputer delegate for full 8 値 range
Test coverage (32/32 PASS)
- Signal: TRUE / ZERO (undefined + null) / INFINITY (out-of-range) / NEITHER (exception) / sync fetcher (6 assertion)
- Device: all-ZERO → device ZERO / any INFINITY + naive TRUE → auto-promote / verdictComputer FALSE override / BOTH 8 値 full range (5 assertion)
- disk_health adapter: no-data ZERO / healthy TRUE / warning NEITHER / critical FALSE / extreme INFINITY (5 case × 2 = 10 assertion)
- isConnected propagation (device connected if any signal connected、 3 assertion)
- SMART reader caching (per emitVerdict cycle、 2 assertion)
Honest scope (Phase 1 spike)
- Backend polymorphism (mock / benchtop_uart / ni_daq / replay) は Signal factory で 抽象化されているが、 実 benchtop UART backend 実装 は 別 STEP defer
- disk_health_verdict.ts 本体 の 完全 refactor は 別 STEP、 本 file は adapter primitive + example wrapping のみ (backward compat 完全維持)
- Movable / Configurable protocol (Ophyd の 残 protocol) は 本 Phase 1 scope 外
- benchtop-mcp 別 repo への 移植 は 別 STEP allocate、 本 STEP は rei-aios 内 で interface + pilot まで
- STEP 1584 SafetyGate 統合 (Device.emitVerdict の 前段 に SafetyGate.check 挿入) は 別 STEP
- STEP 1536 spec doc は STEP 1571 primitive 未認識 で 起草 = 本 STEP で 認識 + 補完 だが spec doc 自体 の update は 別 STEP defer
Related
src/mcp/signal-device.ts— 実装 (~265 行)test/step1593-signal-device-pilot-test.ts— test 32/32 PASSsrc/mcp/no-data-primitives.ts— 別 tab STEP 1571 (a) の primitive layer (本 file は 上位 補完)- STEP 1536 — benchtop 2 層化 spec (本 STEP の spec source)
- STEP 1573 — Tango 5 → Rei 8 mapping (Signal quality 4 subset semantic source)
- STEP 1567 — disk_health_verdict (adapter example base)
- bluesky/ophyd-async: BSD-3-Clause、 NSLS-II 発、 Signal/Device 参照実装