『FEELCYCLE 次世代AI実装大全』――Python・Rust・TypeScript・Swift・SQL・AWS・Hardwareで、人・音楽・身体・空間・会社を接続する(第6回)(第Ⅴ部 Physical Reality――コードを音・光・身体・空間へ変換する 第6章 Physical Runtime――音響・照明・センサー・機材を動かす)
第Ⅴ部 Physical Reality
――コードを音・光・身体・空間へ変換する
ここまでFEELCYCLE AIは、Softwareとして大きく完成へ近づいてきた。
Python Intelligenceは、Music、Program、身体運動、Member、Instructor、Sessionを理解する。
Rust Runtimeは、それらを45分の時間の中で低遅延かつ安全に実行する。
TypeScript Interfaceは、Machine StateをInstructor、Studio、本部が理解できるMeaningへ変換する。
Swift Mobileは、MemberとInstructorの日常を45分の前後へ接続する。
SQLとAWSは、一回のRealityをMemoryとして保持し、次の45分へLearningを継承する。
しかし、ここまでのSystemには決定的な境界が残されている。
CodeとRealityの境界である。
Databaseに、
lighting_state = peak
と記録されても、Studioが明るくなるわけではない。
Rust Runtimeが、
audio_command = play
を生成しても、Speakerから音が出るわけではない。
Python Intelligenceが、
collective_state = synchronized
と推定しても、実際の空間を観測するSensorが存在しなければ、その推定をRealityと接続できない。
SoftwareだけではPhysical Experienceは成立しない。
必要なのは、
Code
↓
Signal
↓
Device
↓
Physical Change
というTranslationである。
同時に逆方向も必要になる。
Physical Reality
↓
Sensor
↓
Signal
↓
Data
↓
Runtime / Intelligence
である。
つまりPhysical Runtimeは、Softwareから物理世界へ命令を送る一方向のControllerではない。
Software
⇄
Physical Reality
を接続する双方向の実行層である。
第Ⅴ部では、この境界を実装する。
Audio System。
Lighting System。
Microphone。
Sensor。
Edge Device。
Network。
Controller。
Protocol。
そしてStudio Integration。
これらを一つのPhysical Runtimeへ接続する。
最終的には、
Python
↓
Rust
↓
Physical Runtime
↓
音・光・空間
だけではなく、
音・光・身体・空間
↓
Sensor
↓
Rust
↓
Python
まで一周させる。
1 Physical Realityとは何か
本書でいうPhysical Realityとは、単にHardwareの集合ではない。
FEELCYCLEの45分が実際に成立する場である。
その中心には、
Music。
身体。
暗闇。
光。
Instructor。
Member。
他者。
空間。
時間。
が存在する。
Technologyは、このRealityを置き換えるものではない。
Realityを支える。
観測する。
必要な変化を実行する。
そして、なるべく人間のAttentionを奪わず背景へ退く。
したがってPhysical Runtimeの設計原則は、
Technology First
ではなく、
Experience First
である。
どのHardwareが最先端かから始めない。
45分に何が必要かから始める。
2 Software CommandからPhysical Actionへ
Rust RuntimeではSemantic Commandを扱ってきた。
たとえばLightingなら、
Dark
Focus
Build
Peak
Release
である。
これはHardware Commandではない。
実際のLighting Systemは、
DMX。
Art-Net。
sACN。
Vendor API。
など具体的なProtocolを要求する可能性がある。
そこでTranslation Layerを置く。
Rust Runtime
↓
Semantic Command
↓
Physical Adapter
↓
Hardware Protocol
↓
Controller
↓
Lighting Fixture
重要なのは、Rust Runtime自身に特定メーカーのHardware仕様を埋め込まないことである。
Runtimeは、
Peakにしたい
と指示する。
Physical Adapterが、
どのFixtureを。
どのChannelへ。
どの値で。
動かすかを決定する。
これによってHardware交換時にもIntelligenceやRuntimeの中心を維持できる。
3 Audioも同じである
Music Playbackを考える。
Runtimeに必要なのは、
Trackを開始する。
停止する。
Positionを確認する。
同期する。
Volume Stateを変更する。
などの意味操作である。
一方、Physical Audio Systemには、
Audio Interface。
Mixer。
DSP。
Amplifier。
Speaker。
Playback Computer。
Network Audio。
などが存在する。
したがって、
Music Runtime
↓
Playback Command
↓
Audio Adapter
↓
Playback Engine
↓
Audio Interface / DSP
↓
Amplifier
↓
Speaker
↓
Studio
と分離する。
Music Fileの再生と、Studio全体の音響を同一Componentにしない。
4 Physical Runtimeの中心はEdgeに置く
StudioのAudioやLightingを、毎回AWSへ送ってから制御する設計にはしない。
Cloudへの往復にはNetwork DelayとFailureがある。
Physical RealityはStudio内で完結できなければならない。
そこでEdge Deviceを置く。
概念的には、
AWS Cloud
↕
Studio Edge
├── Rust Runtime
├── Audio Adapter
├── Lighting Adapter
├── Sensor Gateway
└── Local Buffer
↓
Physical Devices
となる。
CloudはMemoryとLearningを担当する。
EdgeはRealityを担当する。
この境界は重要である。
Cloud Intelligenceが高度になっても、
Physical Execution Authority
はLocalへ残す。
5 Edge Deviceの役割
Edge Deviceには最低限、
Rust Runtime。
Device Adapter。
Network Client。
Local Event Buffer。
Health Monitor。
Fallback Configuration。
を持たせる。
Edge Runtime
│
├── Clock
├── Event Engine
├── Safety Manager
├── Audio Adapter
├── Lighting Adapter
├── Sensor Gateway
├── Device Health
└── Cloud Sync
これによってStudioはCloudから一時的に切り離されても継続できる。
Cloud Failure
≠
Physical Failure
である。
6 Audio System
第6章では、まずAudio Systemを設計する。
扱う対象はMusic Playerだけではない。
Playback。
Mixing。
Signal Routing。
Output。
Monitoring。
Synchronization。
Fallback。
である。
FEELCYCLE AIがMusicを理解しても、Physical Audioが不安定ならExperienceは崩れる。
したがってAudio Runtimeでは、
音質
だけでなく、
Latency。
Continuity。
Synchronization。
Failure Recovery。
を扱う。
MusicはFEELCYCLEの時間基準でもある。
Audio SystemはPhysical RuntimeのClockと密接に接続される。
7 Lighting System
LightingはFEELCYCLEの空間状態を変える。
しかしAIがFixtureを一つずつ直接操作するのではない。
Semantic Stateを使う。
AI / Program
↓
Lighting Intent
↓
Semantic Scene
↓
Physical Adapter
↓
Lighting Controller
↓
Fixtures
たとえば、
Peak
という一つのStateが、
複数Fixture。
Intensity。
Position。
Timing。
Transition。
へ展開される。
これによってProgram CreatorはHardware ParameterではなくExperience Meaningを設計できる。
8 MicrophoneとSensor
次にRealityを観測する。
Microphone。
Environmental Sensor。
Device Telemetry。
Optional Wearable Aggregate。
などである。
しかしSensor Architectureでも、
More Sensors
≠
Better Reality
である。
必要な観測だけを使う。
特にMicrophoneは、音響状態やCollective Featureを分析できる可能性がある一方、音声を扱うためPrivacy上の慎重な設計が必要になる。
目的が音響Featureなら、
Raw Audio
↓
Edge Processing
↓
Feature
↓
Raw Audio破棄
という設計を優先できる。
人の会話内容をCloudへ記録する必要はない。
9 SensorはRealityではない
Sensorが示した値はObservationである。
Realityそのものではない。
Microphoneが音圧を測る。
Motion SensorがMovementを推定する。
WearableがHeart Rateを測る。
しかし、
Sensor Value
≠
Human Experience
である。
したがって、
Observed。
Estimated。
Reported。
を分離するMemory PrincipleをPhysical Runtimeでも維持する。
10 Protocol
Physical Runtimeには複数のProtocolが存在する可能性がある。
Audio Network。
Lighting Control。
Bluetooth。
OSC。
MIDI。
HTTP。
WebSocket。
Vendor Protocol。
しかしFEELCYCLE Runtimeがそれらを直接すべて知る必要はない。
Adapter Patternを使う。
trait PhysicalAdapter {
fn health(
&self
) -> DeviceHealth;
fn safe_state(
&mut self
) -> Result<(), DeviceError>;
}
Lighting Adapter。
Audio Adapter。
Sensor Adapter。
がそれぞれ実装する。
この共通境界によって、Physical DeviceをRuntimeへ統合できる。
11 Device Identity
HardwareにもIdentityを持たせる。
device_id
device_type
studio_id
hardware_reference
firmware_version
configuration_version
health_state
これによって、
何が故障したのか。
どのFirmwareだったのか。
どのSessionへ影響したのか。
をMemoryへ戻せる。
Physical DeviceもFEELCYCLE AIのVersioned Systemの一部になる。
12 Physical State
Runtime Stateとは別にPhysical Stateを持つ。
Desired State
↓
Command
↓
Physical Device
↓
Observed State
たとえば、
Desired Lighting = Peak
でも、
Actual Lighting Controller = Unavailable
かもしれない。
したがって、
Desired
≠
Observed
を分ける。
SoftwareがCommandを送ったからといって、Physical Realityが変化したと仮定してはいけない。
Device ResponseをVerificationへ戻す。
13 Command Acknowledgement
Physical Commandには結果を返す。
概念的には、
struct DeviceCommandResult {
command_id: uuid::Uuid,
accepted: bool,
applied: bool,
message: Option<String>,
}
とする。
これによって、
Command Sent。
Command Accepted。
Command Applied。
を分離できる。
Human IntentとPhysical Executionを分離したのと同じである。
14 Latency Budget
Physical SystemではLatencyがより重要になる。
MusicとLightingのTiming。
SensorからRuntimeまでのDelay。
Network ControllerのResponse。
それぞれにLatencyが存在する。
したがって、
Detection Latency
+
Processing Latency
+
Network Latency
+
Device Latency
=
End-to-End Latency
として測定する。
低遅延とはRustの処理速度だけではない。
Physical Chain全体で決まる。
15 Synchronization
第Ⅱ部ではSoftware上でMusic、Movement、Lightingを同期した。
第Ⅴ部ではPhysical Deviceまで含めて同期する。
Music Timeline
↓
Rust Runtime
↓
┌─────┼─────┐
↓ ↓ ↓
Audio Light Cue
↓ ↓
Physical Output
しかしAudio DeviceとLighting DeviceのResponse Timeは異なる。
そこでDeviceごとのLatency Compensationを持てる。
Target Physical Time
-
Expected Device Latency
=
Command Dispatch Time
Program TimeとCommand Timeを分離する。
これによってPhysical Outputを同じMomentへ近づける。
16 Fallback
Physical RuntimeではFallbackがより具体的になる。
Lighting Controllerが落ちる。
Sensorが切れる。
Network Audioが失われる。
Edge Deviceの一部が異常になる。
その場合、
Safe Static Lighting。
Manual Audio Control。
Sensor-independent Runtime。
Local Program Execution。
などへ移る。
つまり、
Physical Failure
↓
Fallback
↓
Reduced Experience
とし、
Physical Failure
↓
Uncontrolled State
にはしない。
17 Manual Override
Physical RealityではHuman Overrideが最も重要になる。
Instructor。
Studio Operator。
設備側Operator。
がAutomationを切り離せる。
AIが、
Lighting = Peak
を提案していても、人間がManualへ切り替えたらAutomationは停止する。
Human AuthorityをSoftwareだけでなくPhysical Controlにも保持する。
理想的には、重要なSafety ControlはSoftware UIだけに依存しない。
Physical Control Surfaceや設備側Safety Mechanismも残す。
18 Safety Boundary
FEELCYCLE AIはPhysical Equipmentを制御する以上、安全設計を最優先にする。
特に、
過度な音量。
危険なLighting State。
予期しない急変。
Device暴走。
Network異常。
Software Failure。
などを考慮する。
AIの出力を直接Hardwareへ無制限に流さない。
```text
AI Suggestion
↓
Policy
↓
Runtime Validation
↓
Safety Constraint
↓
Physical Adapter
↓
Hardware
とする。
Safety Constraintを最後の境界として置く。
19 Physical ConfigurationはVersion化する
Studio Configurationも変化する。
Speaker。
Mixer。
Lighting Fixture。
Sensor。
Network。
Edge Device。
Firmware。
だからConfiguration Versionを記憶する。
Session Memoryには、
Program Version。
AI Model Version。
Studio Configuration Version。
を対応させる。
すると後から、
Program v12
AI Model v4.3
Studio Configuration v8
という実行条件を復元できる。
これはPhysical Realityの再現性に重要である。
20 SimulationからPhysical Realityへ
Program BuilderではSimulationを行った。
しかしSimulationはRealityではない。
次の段階は、
Simulation
↓
Staging Hardware
↓
Controlled Test
↓
Production Studio
である。
いきなりProduction Sessionへ新しいPhysical Control AlgorithmをDeployしない。
Softwareと同様に、
Develop
↓
Test
↓
Verify
↓
Deploy
をHardware Integrationでも維持する。
21 Digital TwinではなくPhysical Verification
Studioの状態をSoftware上でModel化することは有用である。
しかしSoftware Modelが一致しているからPhysical Realityも一致しているとは限らない。
最終的にはDevice Response、Sensor、Human Verificationによって確認する。
Model
≠
Reality
という本書の最初からの原則をPhysical Runtimeでも保持する。
22 Studio Integration
Audio Systemだけ正常でもFEELCYCLEは成立しない。
Lightingだけでも成立しない。
Sensorだけでも成立しない。
最終的には、
Audio。
Lighting。
Sensor。
Network。
Edge。
Rust Runtime。
Instructor Console。
Human Operation。
を同じStudioへ統合する。
Studio
Python Intelligence
↕
Rust Runtime
↓
┌─────────┼─────────┐
↓ ↓ ↓
Audio Lighting Sensor
↓ ↓ ↑
音 光 空間
└─────────┼─────────┘
↓
Member / Instructor
↓
Reality
そしてRealityから再びDataが戻る。
23 Physical RuntimeのMemory
Physical Realityも記憶する。
Command。
Device Response。
Health State。
Fallback。
Manual Override。
Latency。
Configuration Version。
これらをSession IDへ接続する。
これによって、
「AIは正しかったがHardwareが実行しなかった」
「Programは正しかったがNetworkにDelayがあった」
という原因分解が可能になる。
Learningの精度が上がる。
24 Physical Runtimeと会社
Physical Runtime DataはCompany Dashboardへ集約できる。
しかしCompany側にRaw Sensorや詳細なRealtime Controlを必要以上に見せない。
Studioごとの、
Runtime Availability。
Device Failure。
Fallback Rate。
Configuration。
Maintenance Need。
などにAggregationする。
Companyの目的はStudioを遠隔から細かく支配することではない。
Network全体のResilienceを理解することである。
25 Physical Intelligence
ここまで進むと、FEELCYCLE AIは単なるSoftware AIではなくなる。
Musicを解析する。
Runtimeを実行する。
人間へ意味を返す。
Memoryから学ぶ。
そしてPhysical Spaceへ作用する。
しかし、これを「AIがStudioを支配する」と理解してはいけない。
正確には、
AI
+
Runtime
+
Hardware
+
Human
+
Reality
が一つのSystemになる。
HumanをSystemから外さない。
26 FEELCYCLE Physical Runtimeの最小条件
第Ⅴ部で完成させるPhysical Runtime v0.1には、少なくとも次の条件が必要になる。
AudioへCommandを送れる。
LightingへSemantic Stateを送れる。
SensorからObservationを受け取れる。
Device Healthを取得できる。
EdgeでLocal Runtimeを動かせる。
Cloud Failure時にも継続できる。
Device Failure時にFallbackできる。
HumanがManual Overrideできる。
Physical Execution ResultをAuditできる。
Session Memoryへ戻せる。
この一周が成立すれば、SoftwareとPhysical Realityの境界は接続されたと言える。
27 CodeからRealityへ
ここまで本書は長い距離を移動してきた。
最初は二冊の言語化だった。
そこからDataへ変換した。
Pythonによって理解した。
Rustによって時間の中で実行した。
TypeScriptとSwiftで人間へ接続した。
SQLとAWSでMemoryにした。
そしてここから、
Data
↓
Code
↓
Signal
↓
Hardware
↓
Physical Reality
へ進む。
同時に、
Physical Reality
↓
Sensor
↓
Data
↓
Memory
↓
Learning
という逆方向を成立させる。
28 Physical Realityは最後ではない
Hardwareへ出たから実装が完了するわけではない。
Physical RealityはVerificationの入口である。
Softwareが考えたことが、Realityではどうなったのか。
予定したTimingは成立したか。
Lightingは意図した空間を生成したか。
Sensorは何を観測したか。
Instructorはどう判断したか。
Memberはどう経験したか。
Realityが答えを返す。
したがって、
Implementation
↓
Reality
↓
Verification
である。
29 第Ⅴ部の役割
第Ⅴ部では、このPhysical Translationを具体化する。
まずAudio Systemを実装する。
次にLighting Systemを実装する。
Microphone、Sensor、Edge Deviceを接続する。
Network、Controller、Protocolを統合する。
そしてStudio Integrationを行う。
最後に、
FEELCYCLE Physical Runtime v0.1
として、
Code
⇄
Physical Reality
の双方向循環を完成させる。
30 Realityへ出る
FEELCYCLE AIは、ここから画面の中だけには存在しない。
Speakerから音が出る。
光が変化する。
Sensorが空間を観測する。
Edge Runtimeが時間を保持する。
人間が判断する。
身体が動く。
45分がRealityになる。
AIの価値は、モデルの精度だけでは決まらない。
現実へ出たときに、
人間のExperienceを壊さず。
安全性を損なわず。
創造性を奪わず。
必要な瞬間だけ支援し。
そしてRealityから再び学べるか。
によって決まる。
第Ⅴ部では、その最終境界へ進む。
SoftwareをRealityへ。
Codeを音へ。
Stateを光へ。
Dataを空間へ。
そして再びRealityをDataへ。
FEELCYCLE AIを、実際の45分が生まれるStudioへ実装する。
第6章 Physical Runtime
――音響・照明・センサー・機材を動かす
第1節 AIから物理空間へ
ここまでFEELCYCLE AIは、Softwareの内部では一つのSystemとして動き始めている。
Python IntelligenceがMusicや45分を理解する。
Rust Runtimeが時間を保持し、Eventを処理する。
TypeScriptとSwiftが人間とのInterfaceを形成する。
SQLとAWSが、一回の45分をMemoryとして次へ接続する。
しかし、FEELCYCLEのRealityはSoftwareの中には存在しない。
最終的に存在するのはStudioである。
Speakerから音が出る。
Lightingが空間を変える。
Instructorの声が届く。
Memberの身体が動く。
複数の人間が一つの時間を共有する。
そして45分がRealityとして成立する。
したがってFEELCYCLE AIを完成させるには、
Digital State
↓
Physical State
へのTranslationが必要になる。
本章では、この変換を担当する実行系をPhysical Runtimeと呼ぶ。
Physical RuntimeとはHardwareそのものではない。
AI、Software、Network、Controller、Device、Sensor、人間を、Physical Realityの中で安全に接続するExecution Layerである。
基本構造は、
Python Intelligence
↓
Intent
↓
Rust Runtime
↓
Semantic Command
↓
Physical Runtime
↓
Device Protocol
↓
Hardware
↓
Physical Reality
となる。
しかし、これは半分でしかない。
Physical RealityからSoftwareへ戻る経路も必要である。
Physical Reality
↓
Sensor / Device
↓
Observation
↓
Physical Runtime
↓
Rust Runtime
↓
Python Intelligence
したがって全体は、
AI
↓
Runtime
↓
Physical Reality
↓
Observation
↓
AI
↺
という循環になる。
この双方向性が重要である。
AIがCommandを出しただけではRealityが変わったとは言えない。
Hardwareが実際に応答したか。
音が出ているか。
Lighting ControllerがStateを受け取ったか。
Sensorが何を観測しているか。
それを再びSystemへ返さなければならない。
つまり、
Command
≠
Reality
である。
1 Physical Runtimeの責任
Physical Runtimeには、少なくとも五つの責任がある。
第一に、Semantic CommandをHardware Commandへ翻訳する。
第二に、複数Deviceを同じ時間上で同期する。
第三に、Physical Deviceの状態を観測する。
第四に、Failure時に安全な状態へ縮退する。
第五に、実行結果をRuntimeとMemoryへ返す。
この五つを一つにすると、
Translate
Synchronize
Observe
Protect
Verify
となる。
Physical Runtimeは、単なるDevice Driverの集合ではない。
Reality Execution Systemである。
2 Semantic Command
FEELCYCLE AIでは、AIにHardware固有の値を直接生成させない。
たとえばLightingを考える。
AIが、
「DMX Channel 17を183に変更し、Channel 42を221にする」
と直接出力するArchitectureは避ける。
AIやProgram Builderが扱うのは、
Dark
Focus
Build
Peak
Release
のようなSemantic Stateである。
Rust側では、
#[derive(
Debug,
Clone,
serde::Serialize,
serde::Deserialize,
)]
enum LightingIntent {
Dark,
Focus,
Build,
Peak,
Release,
}
と表現できる。
これをPhysical Adapterへ渡す。
struct LightingCommand {
intent: LightingIntent,
target_time_seconds: f64,
}
Physical Adapterが、そのStudioの設備に応じて具体的なHardware Commandへ変換する。
つまり、
Meaning
↓
Adapter
↓
Protocol
↓
Device
である。
これによってIntelligenceとHardwareを分離できる。
3 Hardware Abstraction
StudioによってEquipmentが異なる可能性がある。
Lighting Controller A。
Lighting Controller B。
異なるAudio Interface。
異なるSensor Gateway。
それでもRust Runtimeそのものを書き換え続ける必要はない。
共通Interfaceを作る。
#[async_trait::async_trait]
trait LightingAdapter:
Send + Sync
{
async fn apply(
&self,
command: LightingCommand,
) -> Result<
DeviceExecutionResult,
PhysicalError,
>;
async fn health(
&self,
) -> DeviceHealth;
}
Audioにも同じ考え方を使う。
#[async_trait::async_trait]
trait AudioAdapter:
Send + Sync
{
async fn play(
&self,
command: AudioCommand,
) -> Result<
DeviceExecutionResult,
PhysicalError,
>;
async fn stop(
&self,
) -> Result<
DeviceExecutionResult,
PhysicalError,
>;
async fn health(
&self,
) -> DeviceHealth;
}
Physical Runtimeが共通Interfaceを見る。
Vendor固有ImplementationはAdapterの裏側へ隠す。
4 Physical Command
Hardwareへ送るCommandにはIdentityを持たせる。
#[derive(
Debug,
Clone,
serde::Serialize,
)]
struct PhysicalCommand {
command_id:
uuid::Uuid,
session_id:
uuid::Uuid,
device_id:
uuid::Uuid,
command_type:
String,
target_time_seconds:
f64,
payload:
serde_json::Value,
}
なぜcommand_idが必要なのか。
同じCommandを重複実行しないため。
Auditするため。
Device Responseと対応させるため。
Latencyを測るため。
である。
Physical RealityでもIdentityが必要になる。
5 Commandと結果を分離する
Commandを送信したらResultを受け取る。
#[derive(
Debug,
Clone,
serde::Serialize,
)]
struct DeviceExecutionResult {
command_id:
uuid::Uuid,
accepted:
bool,
applied:
bool,
applied_at_seconds:
Option<f64>,
message:
Option<String>,
}
ここで、
accepted
と、
applied
を分ける。
ControllerがCommandを受け取った。
しかしFixtureが実際に変化したかは別である。
したがって、
Sent
↓
Accepted
↓
Applied
↓
Observed
という段階を持つ。
Physical Verificationを強くするならSensor Observationまで接続する。
6 Desired StateとObserved State
Physical Runtimeでは二種類のStateを持つ。
Desired State。
Observed State。
である。
#[derive(Debug, Clone)]
struct PhysicalState {
desired_lighting:
Option<LightingIntent>,
observed_lighting:
Option<String>,
audio_active:
Option<bool>,
sensor_health:
DeviceHealth,
}
例えば、
Desired Lighting
=
Peak
Observed Device State
=
Unavailable
という状態があり得る。
Software上のStateだけをRealityとみなさない。
これは本書全体で繰り返してきた、
Reality
≠
Representation
という境界のPhysical版である。
7 Edge Runtime
Physical Executionの中心はStudio側に置く。
AWSへCommandを送り、Cloudから返ってきた答えでLightingを制御するArchitectureにはしない。
Studio内のEdge DeviceでRust Runtimeを動かす。
Studio Edge
│
├── Rust Runtime
├── Physical Adapters
├── Local Program
├── Local State
├── Safety Policy
├── Local Event Buffer
└── Cloud Synchronizer
これによってCloudが失われても45分を継続できる。
Cloud Connected
→ Normal
Cloud Disconnected
→ Local Runtime Continues
Physical Realityの時間はCloud Availabilityに従属させない。
8 Edge Deviceの候補
実装機材は導入規模によって変わる。
概念上は、
産業用小型PC。
Intel / AMD系Mini PC。
ARM系Edge Computer。
Studio Rack内Computer。
などを利用できる。
重要なのは製品名より要件である。
必要なのは、
Rust Runtimeを安定稼働できる。
有線Networkを利用できる。
必要なUSB / Audio / Control Interfaceへ接続できる。
Local Storageを持つ。
自動起動できる。
Watchdogを持てる。
遠隔Monitoring可能。
という条件である。
Physical RuntimeではConsumer DeviceをそのままSafety-Critical Coreにするのではなく、運用継続性を含めて選択する。
9 Real-TimeとSoft Real-Time
FEELCYCLE Runtimeは、工場RobotのEmergency ControlのようなHard Real-Time Systemとは目的が異なる。
しかしMusicとLightingの同期では、人間が違和感を感じない程度の時間精度が必要になる。
したがって、
Soft Real-Time
として設計する。
目標時刻を明示する。
struct ScheduledPhysicalCommand {
target_time_seconds:
f64,
dispatch_time_seconds:
f64,
command:
PhysicalCommand,
}
Device Latencyを予測してDispatch Timeを調整する。
Target Physical Time
-
Estimated Device Latency
=
Dispatch Time
である。
10 Latency Profile
DeviceごとにLatency Profileを持つ。
#[derive(
Debug,
Clone,
)]
struct DeviceLatencyProfile {
device_id:
uuid::Uuid,
expected_ms:
f64,
p95_ms:
f64,
maximum_ms:
f64,
}
たとえばLighting Controllerが平均12msで反応し、Audio Commandが平均4msなら、同じPhysical Momentを狙ってDispatch Timeを変える。
Software上で同時送信することと、Physical Realityで同時になることは同じではない。
11 End-to-End Latency
Physical Runtimeで測定すべきLatencyは一つではない。
AI / Program Decision
↓
Runtime Processing
↓
Command Dispatch
↓
Network
↓
Controller
↓
Device
↓
Physical Output
全体のDelayを見る。
概念的には、
End-to-End Latency
Runtime Processing
+
Network
+
Controller
+
Device Response
である。
この値をSession Memoryへ戻せば、StudioごとのTiming Differenceを学習できる。
12 Clock
複数Deviceを同期するにはClockも重要になる。
Runtime側にSession Clockがある。
Device側にもInternal Clockがある場合がある。
Network上の複数Computerを使うならClock Synchronizationが必要になる。
概念上、
Master Session Clock
↓
Edge Runtime
↓
Timestamped Command
↓
Device
とする。
重要なのは、
「Commandを受け取った瞬間に実行」
だけに依存しないことである。
ProtocolやDeviceがTimestamp Executionを支援するなら利用できる。
支援しないDeviceではEdge側のDispatch Precisionを高める。
13 Physical Event Engine
Software EventをPhysical Commandへ変換する。
async fn handle_physical_event(
event: RuntimeEvent,
lighting:
&dyn LightingAdapter,
audio:
&dyn AudioAdapter,
) -> Result<(), PhysicalError> {
match event.event_type {
EventType::LightingCue => {
let command =
translate_lighting_event(
event
)?;
lighting
.apply(command)
.await?;
Ok(())
}
EventType::MusicSectionChange => {
let command =
translate_audio_event(
event
)?;
audio
.play(command)
.await?;
Ok(())
}
_ => Ok(()),
}
}
Runtime EventとDevice Protocolの間にTranslation Functionを置く。
14 AIを直接Hardwareへ接続しない
Python IntelligenceからDeviceへ直接Commandを送らせない。
基本経路は、
Python Intelligence
↓
Prediction / Suggestion
↓
Human / Policy
↓
Rust Runtime
↓
Safety Validation
↓
Physical Runtime
↓
Device
とする。
Programにあらかじめ定義されたAutomationであっても、
Rust Runtime
↓
Safety
↓
Physical Adapter
を通す。
AI Outputの自由度とPhysical Hardwareの自由度を同一にしない。
15 Safety Envelope
Physical Commandには許容範囲を設定する。
LightingのTransition速度。
Audio Level。
Device Operation。
などである。
概念的に、
struct SafetyEnvelope {
max_audio_level:
f64,
max_lighting_change_rate:
f64,
allowed_devices:
std::collections::HashSet<
uuid::Uuid
>,
}
とする。
Validationする。
fn validate_physical_command(
command:
&PhysicalCommand,
safety:
&SafetyEnvelope,
) -> Result<(), PhysicalError> {
if !safety
.allowed_devices
.contains(
&command.device_id
)
{
return Err(
PhysicalError::
DeviceNotAllowed
);
}
Ok(())
}
実Studioでは音量・照明・設備の安全基準を専門家と設備仕様に基づいて具体化する。
16 Manual Authority
AutomationがPhysical Realityへ入るほど、人間のOverride経路を明確にする。
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
)]
enum PhysicalControlMode {
Automatic,
Assisted,
Manual,
Safe,
}
Manualへ切り替えた場合、
AI Execution
=
OFF
Automatic Physical Commands
=
OFF
Human Control
=
ON
とする。
AIやRuntimeはObservationを継続してもよい。
しかしExecution Authorityは人間へ移る。
17 Physical Safe State
異常時に「何もしない」ことが安全とは限らない。
Lighting ControllerがFailureしたとき、最後の極端なSceneのまま固定するよりSafe Static Sceneへ移した方がよい場合がある。
Audioも安全なFallback Operationを持つ。
したがってDeviceごとにSafe Stateを定義する。
#[async_trait::async_trait]
trait SafeDevice {
async fn enter_safe_state(
&self,
) -> Result<
DeviceExecutionResult,
PhysicalError,
>;
}
Emergency時にはPhysical Runtimeが全AdapterへSafe Stateを要求する。
18 Health Monitoring
Physical RuntimeはCommandだけでなくHealthを監視する。
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
)]
enum DeviceHealth {
Healthy,
Degraded,
Unavailable,
Unknown,
}
DeviceごとのHealthをまとめる。
struct PhysicalHealth {
audio:
DeviceHealth,
lighting:
DeviceHealth,
sensor:
DeviceHealth,
network:
DeviceHealth,
}
UnknownをHealthyとして扱わない。
Physical Realityでも同じ原則を守る。
19 Heartbeat
Network DeviceではHeartbeatを使える。
struct DeviceHeartbeat {
last_seen:
std::time::Instant,
timeout:
std::time::Duration,
}
impl DeviceHeartbeat {
fn healthy(
&self,
) -> bool {
self.last_seen
.elapsed()
<= self.timeout
}
}
一定時間応答がなければHealthをUnknownまたはUnavailableへ移す。
20 Sensor Gateway
Physical RuntimeにはInput側もある。
Sensor Gatewayは複数SensorからObservationを受け取る。
#[derive(
Debug,
Clone,
)]
struct SensorObservation {
sensor_id:
uuid::Uuid,
session_id:
uuid::Uuid,
observed_at_seconds:
f64,
feature_type:
String,
value:
f64,
confidence:
Option<f64>,
}
ここでもRaw SignalとMeaningful Featureを分ける。
Microphone Raw AudioをそのままRust Runtimeへ大量送信するのではなく、Edge ProcessingしたFeatureを渡す構造を基本にする。
21 Physical Realityを観測する
Sensor ObservationをRuntime Eventへ変換する。
fn observation_to_event(
observation:
SensorObservation,
) -> RuntimeEvent {
RuntimeEvent::new(
observation
.session_id
.to_string(),
EventType::SensorUpdate,
observation
.observed_at_seconds,
EventPriority::Normal,
EventPayload::Sensor {
sensor_id:
observation
.sensor_id
.to_string(),
value:
observation
.value,
},
)
}
これによって、
Physical
↓
Sensor
↓
Runtime
の逆方向が成立する。
22 Physical Execution Record
CommandとResultをMemoryへ残す。
#[derive(
Debug,
serde::Serialize,
)]
struct PhysicalExecutionRecord {
command_id:
uuid::Uuid,
session_id:
uuid::Uuid,
device_id:
uuid::Uuid,
target_seconds:
f64,
applied_seconds:
Option<f64>,
result:
String,
}
SQL側では例えば、
CREATE TABLE physical_execution_events (
execution_id UUID PRIMARY KEY,
command_id UUID NOT NULL,
session_id UUID NOT NULL,
device_id UUID NOT NULL,
target_seconds
DOUBLE PRECISION,
applied_seconds
DOUBLE PRECISION,
result TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL
DEFAULT NOW(),
FOREIGN KEY (
session_id
)
REFERENCES sessions(
session_id
)
);
とできる。
これでSoftware EventとPhysical Executionを区別して記憶できる。
23 Planned・Commanded・Observed
ここでMemoryは三段階になる。
Planned
↓
Commanded
↓
Observed
Programでは、
Lighting Peakを120秒に予定。
Physical Runtimeでは、
119.987秒にCommand Dispatch。
Deviceでは、
120.011秒にApplied。
Sensorでは、
120.020秒に状態変化をObserved。
というように追跡できる。
これによってPhysical Synchronizationを検証できる。
24 Device Configuration
Device ControlにはConfigurationが必要である。
#[derive(
Debug,
serde::Deserialize,
)]
struct DeviceConfig {
device_id:
uuid::Uuid,
device_type:
String,
protocol:
String,
address:
String,
enabled:
bool,
}
ConfigurationはCodeへHardcodeしない。
Studio Configuration VersionとしてMemoryへ保持する。
Session開始時に正しいConfigurationを読み込む。
25 Configuration Validation
Session開始前にDevice Configurationを検証する。
fn validate_device_config(
config:
&DeviceConfig,
) -> Result<(), PhysicalError> {
if !config.enabled {
return Err(
PhysicalError::
DeviceDisabled
);
}
if config.address
.trim()
.is_empty()
{
return Err(
PhysicalError::
InvalidConfiguration
);
}
Ok(())
}
Session開始後に初めてConfiguration Errorを発見するのでは遅い。
Preparation Stageで検出する。
26 Preflight Check
Session開始前にPhysical Runtimeを確認する。
Runtime
Audio
Lighting
Sensor
Network
Manual Control
Safe State
を検証する。
struct PreflightReport {
runtime_ready:
bool,
audio_ready:
bool,
lighting_ready:
bool,
sensor_ready:
bool,
network_ready:
bool,
}
Critical ComponentがUnavailableなら開始判断へ返す。
SensorのようなOptional ComponentならDegraded Startを許容できる。
27 Physical Runtimeの優先順位
FEELCYCLE Physical Runtimeでは、優先順位を明確にする。
Safety
>
Human Authority
>
Audio Continuity
>
Program Timing
>
Lighting Automation
>
Sensor Enhancement
>
AI Optimization
AI Optimizationが失われても45分は成立する。
Lighting Automationが失われてもFallbackできる。
しかしSafetyやHuman AuthorityをAI Optimizationのために犠牲にしない。
このPriorityは設計全体を貫く。
28 AIから物理空間へ、という意味
ここで本節のタイトルに戻る。
「AIから物理空間へ」とは、AIが直接Studioを動かすという意味ではない。
AIが理解する。
Runtimeが判断可能なStateへ変換する。
HumanとPolicyがAuthorityを与える。
Physical RuntimeがHardwareの言語へTranslationする。
DeviceがRealityを変える。
RealityがObservationを返す。
という複数の境界を通過することである。
AI
↓
Meaning
↓
Authority
↓
Runtime
↓
Safety
↓
Protocol
↓
Hardware
↓
Reality
↓
Observation
↓
AI
一段も飛ばさない。
この分離が安全性、交換可能性、検証可能性を生む。
29 Physical Runtime v0.1の起点
本節で、Physical Runtimeの基本Architectureは成立した。
Semantic Command。
Adapter。
Edge Runtime。
Command Identity。
Desired / Observed State。
Latency。
Safety Envelope。
Manual Authority。
Health Monitoring。
Sensor Gateway。
Physical Execution Memory。
ここから各Systemを具体化する。
最初はAudioである。
FEELCYCLEにおいてMusicは単なるBackground Soundではない。
45分の時間構造を形成する主要な基準であり、身体運動、Lighting、Instructor、Member Experienceを接続する軸でもある。
したがって次節では、
Audio System
を実装する。
Music Fileがどこから再生されるのか。
Playback Engineをどう構成するのか。
Mixer、DSP、Audio Interface、Amplifier、Speakerをどう接続するのか。
Rust Runtimeとどこで同期するのか。
障害時にどうFallbackするのか。
そしてAIがMusicを理解した結果を、音として安全にStudioへ出すにはどうすればよいのか。
Codeが最初にPhysical Realityへ変わる場所として、音響系を構築する。
第2節 Audio System
FEELCYCLEのPhysical Runtimeにおいて、Audio Systemは単なる「音を再生する装置」ではない。
Musicは45分の時間そのものを形成する。
身体運動がMusicへ接続する。
InstructorのTimingがMusicへ接続する。
LightingがMusicへ接続する。
Memberの注意と身体感覚もMusicによって変化する。
したがってAudio Systemは、
Playback System
であると同時に、
Physical Time Reference
でもある。
Python IntelligenceがMusicを解析し、Rust Runtimeが45分のTimelineを保持していても、実際のStudioで音が遅延したり、停止したり、意図しない音量へ変化すれば、全体の同期は崩れる。
本節では、
Music Data
↓
Playback Engine
↓
Audio Interface
↓
Mixer / DSP
↓
Amplifier
↓
Speaker
↓
Studio
というPhysical Audio Chainを構築し、Rust Runtimeから安全に制御できるFEELCYCLE Audio Runtime v0.1を実装する。
1 Audio Systemの全体構造
最初に役割を分ける。
Python Intelligence
↓
Music Analysis
↓
Program Timeline
↓
Rust Runtime
↓
Audio Adapter
↓
Playback Engine
↓
Audio Interface
↓
Mixer / DSP
↓
Amplifier
↓
Speaker
↓
Studio
逆方向には、
Audio Device
↓
Playback State
↓
Device Health
↓
Rust Runtime
↓
Memory
が存在する。
つまりAudio Systemも双方向である。
Commandだけではなく、
現在再生しているTrack。
現在Position。
Device Health。
Playback Error。
Latency。
をRuntimeへ返す。
2 Audio AssetとPlaybackを分離する
Music Metadataと実際のAudio Assetを同じものとして扱わない。
SQLには、
Track ID。
Title。
Artist。
Duration。
Analysis。
を持つ。
実際のPlayback Assetは、権利処理された配信・再生基盤や適切なAsset Managementの下で扱う。
Rust Runtimeが知るべきなのは、
track_id
asset_reference
start_position
target_start_time
である。
Audio Fileそのものの保存場所や権利条件をRuntimeへ埋め込まない。
#[derive(
Debug,
Clone,
serde::Serialize,
serde::Deserialize,
)]
struct AudioAssetReference {
track_id: uuid::Uuid,
asset_reference: String,
duration_seconds: f64,
}
これによって、
Music Identity
と、
Physical Playback Asset
を分離できる。
3 Audio Command
RuntimeからAudio Systemへ送るCommandを定義する。
#[derive(
Debug,
Clone,
serde::Serialize,
)]
enum AudioAction {
Prepare,
Play,
Pause,
Stop,
Seek,
}
#[derive(
Debug,
Clone,
serde::Serialize,
)]
struct AudioCommand {
command_id: uuid::Uuid,
session_id: uuid::Uuid,
track_id: uuid::Uuid,
action: AudioAction,
target_position_seconds:
Option<f64>,
target_session_seconds:
f64,
}
ここで重要なのは、
「今すぐPlay」
だけではなく、
「Session Clock上の何秒で開始するか」
を持つことである。
これによってLightingやMovementとの同期基準を作れる。
4 PrepareとPlayを分ける
Track開始時刻になってからFileを読み込み始めてはいけない。
先にPrepareする。
Upcoming Track
↓
Prepare
↓
Decode / Buffer
↓
Ready
↓
Target Time
↓
Play
Audio AdapterにはPrepareを持たせる。
#[async_trait::async_trait]
trait AudioAdapter:
Send + Sync
{
async fn prepare(
&self,
asset:
&AudioAssetReference,
) -> Result<
AudioPrepareResult,
AudioError,
>;
async fn execute(
&self,
command:
&AudioCommand,
) -> Result<
AudioExecutionResult,
AudioError,
>;
async fn state(
&self,
) -> Result<
AudioPlaybackState,
AudioError,
>;
async fn health(
&self,
) -> DeviceHealth;
}
Resultを定義する。
#[derive(Debug)]
struct AudioPrepareResult {
track_id: uuid::Uuid,
ready: bool,
}
#[derive(Debug)]
struct AudioExecutionResult {
command_id: uuid::Uuid,
accepted: bool,
applied: bool,
applied_at_seconds:
Option<f64>,
message:
Option<String>,
}
Prepareに失敗すれば、Track開始前にFallback判断ができる。
5 Playback State
CommandとActual Playbackを分離する。
#[derive(
Debug,
Clone,
)]
enum PlaybackStatus {
Idle,
Prepared,
Playing,
Paused,
Stopped,
Failed,
}
#[derive(
Debug,
Clone,
)]
struct AudioPlaybackState {
track_id:
Option<uuid::Uuid>,
status:
PlaybackStatus,
position_seconds:
f64,
updated_at_session_seconds:
f64,
}
Runtimeは定期的にPlayback Stateを確認する。
Program上ではTrack Aが再生中でも、
Actual Playback State
がFailedなら、Realityは異なる。
6 Playback Positionを検証する
Session ClockとPlayback Positionを比較する。
概念的には、
Expected Position
=
Session Time
-
Track Start Time
である。
Rustでは、
fn expected_position(
session_seconds: f64,
track_start_seconds: f64,
) -> f64 {
(
session_seconds
- track_start_seconds
)
.max(0.0)
}
Differenceを計算する。
fn playback_drift_ms(
expected_seconds: f64,
actual_seconds: f64,
) -> f64 {
(
actual_seconds
- expected_seconds
)
* 1000.0
}
これによってAudio Driftを観測できる。
ただし、常に細かな補正を行えばよいわけではない。
補正そのものが音の不自然さを生む可能性がある。
許容範囲を設定する。
7 Audio Drift Policy
#[derive(Debug)]
struct AudioSyncPolicy {
warning_drift_ms:
f64,
critical_drift_ms:
f64,
}
判定する。
#[derive(Debug)]
enum AudioSyncState {
Synchronized,
Warning,
Critical,
}
fn classify_drift(
drift_ms: f64,
policy:
&AudioSyncPolicy,
) -> AudioSyncState {
let value =
drift_ms.abs();
if value
>= policy
.critical_drift_ms
{
AudioSyncState::Critical
} else if value
>= policy
.warning_drift_ms
{
AudioSyncState::Warning
} else {
AudioSyncState::Synchronized
}
}
具体的なThresholdは、実Studioでの聴覚評価、Device特性、Program要件に基づいて決定する。
8 Audio Interface
Playback EngineからStudio設備へ音を出すにはAudio Interfaceが必要になる。
概念構造は、
Playback Computer
↓
Digital Audio
↓
Audio Interface
↓
Balanced Audio / Network Audio
↓
Mixer / DSP
となる。
Audio Interface選定では、
必要Channel数。
Driverの安定性。
低Latency。
Sample Rate。
Output Format。
Redundancy。
運用実績。
を重視する。
製品名よりも、
Studio Runtimeとして安定運用できること
を要件の中心にする。
9 Mixer
FEELCYCLEのStudio AudioにはMusicだけではなく、Instructor側の音声も存在する可能性がある。
したがってMixerでは、
Music。
Instructor Microphone。
必要なSystem Audio。
を分離する。
Music Playback ─────┐
│
Instructor Mic ─────┼→ Mixer → DSP → Speakers
│
System Audio ───────┘
AIがMixer全体を自由に操作する設計にはしない。
特にInstructor VoiceやMaster Outputは、Physical SafetyとOperational Controlを持つ。
10 Signal Model
SemanticなAudio Stateを定義できる。
#[derive(
Debug,
Clone,
)]
struct AudioMixIntent {
music_active:
bool,
instructor_voice_active:
bool,
scene:
AudioScene,
}
#[derive(
Debug,
Clone,
)]
enum AudioScene {
Normal,
Transition,
Recovery,
Safe,
}
このSemantic StateをMixer Adapterが実設備のRoutingやPresetへ変換する。
AIが個別Gain値を直接生成する構造より安全である。
11 DSP
DSPは音響処理を担当する。
たとえば、
Routing。
EQ。
Dynamics。
Delay Compensation。
Limiter。
などである。
ここで重要なのは、AIがPhysical Safety Limiterを上書きできないようにすることである。
AI / Runtime
↓
Mix Intent
↓
DSP Scene
↓
Safety Processing
↓
Physical Output
Safety LayerはAutomationより下位に置く。
つまりAIがどのようなAudio Intentを生成しても、安全上設定された限界を越えられない。
12 音量のAuthority
音量はFEELCYCLEのExperienceに大きく影響する。
しかし、音量最大化をAI Optimization Objectiveにしない。
また本書のコードだけで具体的な安全音圧値を固定しない。
Studioの物理特性、設備仕様、関連する安全基準、専門的な測定を基に定める必要があるためである。
Architectureとしては、
Program Intent
↓
Runtime
↓
Allowed Range
↓
DSP / Limiter
↓
Output
とする。
最大許容値はConfigurationとして管理する。
#[derive(Debug)]
struct AudioSafetyConfig {
maximum_output_level:
f64,
allow_runtime_gain_change:
bool,
}
実際の単位・値は設備設計時に定義する。
13 Speaker System
Speaker SystemはPhysical Outputの最終段である。
ここでは、
Coverage。
Placement。
Frequency Response。
Headroom。
Reliability。
Room Acoustics。
を考える。
AIが高度でも、Physical Acoustic Designが悪ければExperienceは改善されない。
Audio Intelligence
≠
Acoustic Engineering
である。
Softwareは、物理音響設計を代替しない。
むしろ適切に設計されたPhysical Systemを再現性高く運用する。
14 StudioごとのAudio Configuration
Studioによって、
Speaker。
Amplifier。
DSP。
Mixer。
Audio Interface。
が異なる場合がある。
そこでAudio ConfigurationをVersion化する。
{
"configuration_version": 4,
"audio_interface": {
"device_id": "audio-interface-01"
},
"mixer": {
"device_id": "mixer-01",
"scene": "feelcycle-default"
},
"dsp": {
"device_id": "dsp-01",
"preset": "studio-a-v4"
}
}
Sessionには、
Studio Configuration Version
を紐付ける。
これによって後から、
「同じProgramなのにStudio AだけExperienceが違った」
原因を物理設備側まで追跡できる。
15 Audio Device Identity
DatabaseにもDeviceを記録する。
CREATE TABLE audio_devices (
audio_device_id UUID PRIMARY KEY
DEFAULT gen_random_uuid(),
studio_id UUID NOT NULL,
device_type TEXT NOT NULL,
device_name TEXT NOT NULL,
hardware_reference TEXT,
firmware_version TEXT,
active BOOLEAN NOT NULL
DEFAULT TRUE,
installed_at TIMESTAMPTZ,
FOREIGN KEY (
studio_id
)
REFERENCES studios(
studio_id
)
);
これによりPhysical Memoryが成立する。
16 Health Monitoring
Audio DeviceのHealthを定期的に確認する。
#[derive(
Debug,
Clone,
)]
struct AudioHealth {
playback_engine:
DeviceHealth,
audio_interface:
DeviceHealth,
mixer:
DeviceHealth,
dsp:
DeviceHealth,
output_path:
DeviceHealth,
}
全体を判定する。
fn overall_audio_health(
health:
&AudioHealth,
) -> DeviceHealth {
let states = [
health.playback_engine,
health.audio_interface,
health.mixer,
health.dsp,
health.output_path,
];
if states
.contains(
&DeviceHealth::Unavailable
)
{
DeviceHealth::Unavailable
} else if states
.contains(
&DeviceHealth::Degraded
)
{
DeviceHealth::Degraded
} else if states
.contains(
&DeviceHealth::Unknown
)
{
DeviceHealth::Unknown
} else {
DeviceHealth::Healthy
}
}
17 Preflight Check
Session開始前にAudio Systemを確認する。
#[derive(Debug)]
struct AudioPreflightReport {
playback_ready:
bool,
output_ready:
bool,
mixer_ready:
bool,
dsp_ready:
bool,
fallback_ready:
bool,
}
判定する。
impl AudioPreflightReport {
fn session_ready(
&self,
) -> bool {
self.playback_ready
&& self.output_ready
&& self.mixer_ready
&& self.dsp_ready
}
}
重要なのは、Session開始後に初めて音が出ないことへ気づくのを防ぐことである。
18 Preload
次のTrackを先読みする。
struct PreparedTrack {
track_id:
uuid::Uuid,
ready:
bool,
prepared_at:
std::time::Instant,
}
Program Timelineから次のTrackを取得し、余裕を持ってPrepareする。
Current Track
↓
Next Track Lookup
↓
Preload
↓
Ready
↓
Scheduled Transition
19 Track Transition
Track TransitionをRuntime Eventとして扱う。
#[derive(
Debug,
Clone,
)]
struct TrackTransition {
from_track:
uuid::Uuid,
to_track:
uuid::Uuid,
target_session_seconds:
f64,
}
Transition時には、
次TrackがReadyか。
Audio DeviceはHealthyか。
Runtime Clockは正常か。
を確認する。
fn can_transition(
next_ready: bool,
health:
DeviceHealth,
) -> bool {
next_ready
&& health
== DeviceHealth::Healthy
}
20 Fallback Playback
Audioは45分の主要基盤であるため、Fallbackが重要になる。
通常Playback EngineがFailureした場合、
Secondary Playback。
Manual Playback。
Preloaded Local Fallback。
などの設計が考えられる。
概念的には、
Primary Playback
↓ failure
Secondary Playback
↓ failure
Manual Fallback
とする。
実装規模に応じて段階を決める。
重要なのは、
Audio Failure
↓
Immediate Session Collapse
だけを唯一の状態にしないことである。
21 Fallback State
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
)]
enum AudioRuntimeMode {
Primary,
Secondary,
Manual,
SafeStop,
}
Fallback Managerを作る。
fn next_audio_mode(
current:
AudioRuntimeMode,
) -> AudioRuntimeMode {
match current {
AudioRuntimeMode::Primary =>
AudioRuntimeMode::Secondary,
AudioRuntimeMode::Secondary =>
AudioRuntimeMode::Manual,
AudioRuntimeMode::Manual =>
AudioRuntimeMode::SafeStop,
AudioRuntimeMode::SafeStop =>
AudioRuntimeMode::SafeStop,
}
}
Productionでは人間判断や設備構成を含むState Machineにする。
22 Manual Control
Audio Automationを切り離せる必要がある。
Manual Modeへ移れば、
Rust Runtimeからの自動Track Change。
自動Scene Change。
AI由来のAudio Suggestion Execution。
を停止する。
struct AudioAuthority {
automatic_execution:
bool,
human_control:
bool,
}
Manualへ移す。
fn enter_manual_mode(
authority:
&mut AudioAuthority,
) {
authority
.automatic_execution =
false;
authority
.human_control =
true;
}
ただしSafety LimiterなどはManual Modeでも残す。
Human Authority
≠
Safety Bypass
である。
23 Instructor Microphone
Instructor MicrophoneはMusic Playbackとは別系統として扱う。
FEELCYCLE AIがInstructorの声そのものを常時記録する必要はない。
Physical Audioでは、
Mic Input
↓
Mixer / DSP
↓
Speaker
として動く。
AIが必要とするのが、
Voice Activity。
Level。
Signal Health。
などのFeatureだけなら、EdgeでFeature抽出してRaw Voiceを破棄する設計を優先できる。
Microphone
↓
Edge Audio Analysis
↓
Feature
↓
Raw Audio Discard
PrivacyとOperational Utilityを両立する。
24 Microphone Feature
たとえば、
#[derive(
Debug,
Clone,
)]
struct VoiceFeature {
active:
bool,
level:
Option<f64>,
confidence:
f64,
}
程度のFeatureで十分な用途もある。
Speech Contentを保存しなくても、
「現在Voice Activityがある」
ことは観測できる。
Need Meaning
≠
Need Recording
である。
25 Audio Sensor
Studio Audioを検証するためのMeasurement Microphoneを別に用意することもできる。
これはInstructor Microphoneとは役割が異なる。
Instructor Mic
=
Human Voice Input
Measurement Mic
=
Studio Audio Observation
両者を混同しない。
Measurement側では、
音響Level。
Frequency Feature。
Output Presence。
などをEdgeで抽出できる。
26 Output Verification
Playback EngineがPlayingでも、Speakerから実際に音が出ているとは限らない。
したがってより完全なPhysical Verificationでは、
Playback State
↓
Audio Interface
↓
Mixer / DSP
↓
Speaker
↓
Measurement
まで確認する。
Software ObservationとPhysical Observationを分離する。
struct AudioVerification {
playback_reported:
bool,
physical_output_detected:
bool,
}
これによって、
Software Playing
+
Physical Silence
というFailureを検出できる可能性が高まる。
27 Audio EventをMemoryへ戻す
Audio Systemで起きたEventを記録する。
CREATE TABLE audio_runtime_events (
audio_event_id UUID PRIMARY KEY
DEFAULT gen_random_uuid(),
session_id UUID NOT NULL,
track_id UUID,
event_type TEXT NOT NULL,
target_seconds DOUBLE PRECISION,
actual_seconds DOUBLE PRECISION,
runtime_mode TEXT,
result TEXT NOT NULL,
metadata JSONB NOT NULL
DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL
DEFAULT NOW(),
FOREIGN KEY (
session_id
)
REFERENCES sessions(
session_id
)
);
これによってAudioのPhysical Memoryが成立する。
28 Audio DriftをMemoryへ保存する
CREATE TABLE audio_sync_measurements (
measurement_id UUID PRIMARY KEY
DEFAULT gen_random_uuid(),
session_id UUID NOT NULL,
track_id UUID,
session_seconds
DOUBLE PRECISION NOT NULL,
expected_position_seconds
DOUBLE PRECISION NOT NULL,
actual_position_seconds
DOUBLE PRECISION NOT NULL,
drift_ms
DOUBLE PRECISION NOT NULL,
created_at TIMESTAMPTZ NOT NULL
DEFAULT NOW(),
FOREIGN KEY (
session_id
)
REFERENCES sessions(
session_id
)
);
すべてのSampleを永久保存する必要はない。
必要なSamplingやSummaryへ圧縮する。
29 Session Audio Summary
Session終了後にSummaryへ変換する。
CREATE TABLE audio_session_summaries (
session_id UUID PRIMARY KEY,
availability
DOUBLE PRECISION,
average_drift_ms
DOUBLE PRECISION,
p95_drift_ms
DOUBLE PRECISION,
fallback_count
INTEGER NOT NULL
DEFAULT 0,
failure_count
INTEGER NOT NULL
DEFAULT 0,
generated_at TIMESTAMPTZ NOT NULL
DEFAULT NOW(),
FOREIGN KEY (
session_id
)
REFERENCES sessions(
session_id
)
);
Company DashboardはRaw Audio Eventではなく、このSummaryを中心に利用する。
30 Audio Runtime Loop
Audio Runtimeの中心を簡略化すると、
async fn audio_runtime_loop(
adapter:
&dyn AudioAdapter,
commands:
&mut tokio::sync::mpsc::Receiver<
AudioCommand
>,
) {
while let Some(command) =
commands.recv().await
{
let health =
adapter.health().await;
if health
== DeviceHealth::Unavailable
{
continue;
}
let result =
adapter
.execute(
&command
)
.await;
match result {
Ok(result) => {
record_audio_result(
result
).await;
}
Err(error) => {
handle_audio_failure(
error
).await;
}
}
}
}
となる。
実際にはPriority、Timing、Fallback、Safety、Auditを統合する。
31 Audio CommandをRuntimeへ接続する
Music Transition EventからAudio Commandを生成する。
fn to_audio_command(
session_id:
uuid::Uuid,
track_id:
uuid::Uuid,
target_seconds:
f64,
) -> AudioCommand {
AudioCommand {
command_id:
uuid::Uuid::new_v4(),
session_id,
track_id,
action:
AudioAction::Play,
target_position_seconds:
Some(0.0),
target_session_seconds:
target_seconds,
}
}
これでProgram TimelineからPhysical Audioへつながる。
32 Python Intelligenceとの境界
Python IntelligenceはMusic Structureを解析する。
しかしPlayback Engineを直接操作しない。
Pythonが返すのは、
Section。
Energy。
Transition Candidate。
Prediction。
Suggestion。
である。
その情報をProgramやRuntimeが解釈し、Audio Commandへ変える。
Python
↓
Music Understanding
↓
Program / Suggestion
↓
Human / Runtime
↓
Audio Command
知性とPhysical Authorityを分離する。
33 TypeScript Interfaceとの接続
Instructor ConsoleではAudioの詳細Device情報を大量に表示しない。
必要なのは、
Playing。
Fallback。
Manual。
Failure。
などである。
Studio Monitorではさらに詳しく、
Playback Engine。
Interface。
Mixer。
DSP。
Output。
を表示できる。
同じAudio RealityをObserver Positionによって異なるRepresentationへする。
34 Swiftとの接続
Member AppがStudio Audioを制御することはない。
Instructor MobileもPrimary Audio Controlにはしない。
Mobileから見せるとしても、
Session Ready。
Audio System Ready。
程度でよい。
Physical Control AuthorityをPersonal Mobile Deviceへ分散させすぎない。
35 Audio SystemのSafety Boundary
Physical Audioでは、Software Errorが実空間へ直接影響する。
したがって、
Program。
AI。
Runtime。
Adapter。
Mixer。
DSP。
Physical Safety。
を一つのLayerにまとめない。
AI
↓
Runtime
↓
Audio Adapter
↓
Mixer / DSP
↓
Independent Safety Constraint
↓
Speaker
複数の防衛境界を持つ。
36 Audio v0.1のPreflight Flow
Session開始前には、
Playback Engine
↓ check
Audio Asset
↓ check
Audio Interface
↓ check
Mixer
↓ check
DSP
↓ check
Speaker Path
↓ check
Fallback
↓ check
Ready
を確認する。
結果をStudio Readinessへ返す。
37 Session Start
Session開始時、
最初のTrackをPrepare。
Session Clock開始。
Target TimeにPlay。
Playback Stateを確認。
Physical Outputを必要に応じて確認。
Timing Differenceを記録する。
Session Start
↓
Audio Ready
↓
Play
↓
Verify
↓
Continue
38 Session End
Session終了時には、
Playback停止。
Runtime State更新。
Audio Summary生成。
Memory同期。
Fallback History記録。
を行う。
45 Minutes
↓
Audio Stop
↓
Verification
↓
Summary
↓
Memory
一つのAudio Realityが次のLearningへ変わる。
39 Audio System v0.1の完成条件
FEELCYCLE Audio System v0.1は、最低限次を満たす。
Music AssetをTrack Identityと分離できる。
次Trackを事前Prepareできる。
Session Clockに基づいて再生できる。
Actual Playback Positionを取得できる。
Audio Driftを測定できる。
Audio Interface、Mixer、DSP、OutputのHealthを観測できる。
Primary Failure時にFallbackへ移れる。
HumanがManual Controlを引き取れる。
Safety ConstraintをAutomationから独立させられる。
Audio EventをSession Memoryへ戻せる。
この一周が成立すれば、Pythonで解析されたMusicはPhysical Realityの「音」へ変換されたことになる。
40 Musicを時間へ戻す
ここでAudio Systemの意味をもう一度整理する。
FEELCYCLEにおいてMusicは、単に流れるContentではない。
45分の構造を支える時間軸である。
ProgramはMusicへ身体運動を接続する。
Rust RuntimeはMusicへEventを接続する。
LightingはMusicへ空間変化を接続する。
InstructorはMusicを読みながらRealityを生成する。
MemberはMusicを身体として経験する。
だからAudio Systemが安定することは、単に「音が途切れない」以上の意味を持つ。
Music
↓
Time
↓
Body
↓
Space
↓
Experience
へつながる。
Python IntelligenceはMusicを理解した。
Rust Runtimeはその時間を保持した。
Audio Systemによって、その時間がStudioに鳴り始める。
しかし、FEELCYCLEのPhysical Realityは音だけでは完成しない。
同じMusicでも、空間が完全な暗闇なのか、Focusなのか、Buildなのか、PeakなのかによってExperienceは変わる。
次節では、時間を空間へ展開する。
Lighting Systemを実装する。
Semantic Lighting StateをSceneへ変換し、ControllerとFixtureへ安全に送る。
Musicと同期する。
Failure時にはSafe Sceneへ戻る。
Human Overrideを保持する。
そしてRust RuntimeのStateを、実際のStudioの「光」へ変換する。
第3節 Lighting System
Audio Systemによって、FEELCYCLE AIの時間はStudioの「音」へ変換された。
次に、その時間を空間へ展開する。
Lightingである。
FEELCYCLEにおけるLightingは、単なる装飾ではない。
暗闇をつくる。
身体への注意を変える。
InstructorとMemberのRelationを変える。
MusicのTransitionを空間として可視化する。
集中を深める。
開放する。
45分の時間構造を、光と影によってPhysical Spaceへ翻訳する。
したがってLighting Systemの役割は、
「AIが照明を操作すること」
ではない。
Program、Music、Runtimeが持つ意味を、
安全で再現可能なPhysical Lighting State
へTranslationすることである。
基本構造は、
Program / AI
↓
Lighting Intent
↓
Rust Runtime
↓
Lighting Adapter
↓
Scene
↓
Protocol
↓
Controller
↓
Fixture
↓
Physical Space
となる。
そしてAudioと同じように逆方向も必要である。
Controller / Fixture
↓
Device State
↓
Lighting Adapter
↓
Rust Runtime
↓
Studio Monitor
↓
Memory
つまりLighting Systemも、
Command
⇄
Observation
を持つPhysical Runtimeとして設計する。
1 LightingをMeaningから設計する
Lighting Systemで最も重要なのは、AIやProgram CreatorへHardware Channelを直接操作させないことである。
Program Builderでは、
Dark。
Focus。
Build。
Peak。
Release。
というSemantic Lighting Stateを扱ってきた。
この思想をPhysical Runtimeでも維持する。
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
serde::Serialize,
serde::Deserialize,
)]
enum LightingIntent {
Dark,
Focus,
Build,
Peak,
Release,
Safe,
}
Programには、
120.0 sec
→ Build
138.5 sec
→ Peak
と記述する。
それをRust RuntimeがLighting Adapterへ渡す。
AIは、
「Channel 12を値210へ」
とは言わない。
Meaningを出す。
Hardware Layerが具体値へ翻訳する。
これによって、
Creative Meaning
≠
Hardware Implementation
を維持できる。
2 Sceneを第一級Entityにする
Semantic Intentを、StudioごとのLighting Sceneへ変換する。
#[derive(
Debug,
Clone,
serde::Deserialize,
)]
struct LightingScene {
scene_id: String,
intent:
LightingIntent,
transition_ms:
u64,
parameters:
serde_json::Value,
}
たとえばStudio AのPeakとStudio BのPeakは、Fixture構成が違っても同じ意味を持てる。
Studio Aでは、
Peak
↓
Fixture A
Fixture B
Fixture C
Studio Bでは、
Peak
↓
Fixture X
Fixture Y
Fixture Z
へTranslationする。
Runtimeは違いを知らなくてよい。
これがHardware Abstractionの価値である。
3 Scene Configuration
Sceneの具体値はConfigurationとして保持する。
概念例は、
{
"scene_id": "peak_v3",
"intent": "Peak",
"transition_ms": 300,
"fixtures": [
{
"fixture_id": "front_01",
"intensity": 0.75
},
{
"fixture_id": "side_01",
"intensity": 0.60
}
]
}
である。
ここで具体的な光量・演出値は実Studioで設計・検証する。
重要なのはCodeへHardcodeしないことである。
Lighting SceneもVersion化する。
4 Lighting Scene Version
SQLでは例えば、
CREATE TABLE lighting_scenes (
scene_id UUID PRIMARY KEY
DEFAULT gen_random_uuid(),
studio_id UUID NOT NULL,
scene_name TEXT NOT NULL,
semantic_intent TEXT NOT NULL,
version_number INTEGER NOT NULL,
scene_definition JSONB NOT NULL,
active BOOLEAN NOT NULL
DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL
DEFAULT NOW(),
FOREIGN KEY (
studio_id
)
REFERENCES studios(
studio_id
),
UNIQUE (
studio_id,
scene_name,
version_number
)
);
とする。
これによって過去Sessionで、
Program Version。
Studio Configuration Version。
Lighting Scene Version。
を対応させられる。
5 ProgramとSceneを分離する
Program BuilderのLightingIntent::Peakを、そのまま特定Scene IDへ永久固定する必要はない。
Translation Layerを置く。
Program
Peak
↓
Studio Configuration
↓
peak_v3
↓
Physical Scene
これにより設備更新後もProgramそのものを書き換えずに済む。
同じProgramが複数Studioで実行可能になる。
6 Lighting Command
Physical Commandを定義する。
#[derive(
Debug,
Clone,
serde::Serialize,
)]
struct LightingCommand {
command_id:
uuid::Uuid,
session_id:
uuid::Uuid,
intent:
LightingIntent,
scene_id:
String,
target_session_seconds:
f64,
transition_ms:
u64,
}
ここでもtarget_session_secondsを持つ。
AudioとLightingを同じSession Clockへ接続するためである。
7 Lighting Adapter
共通Interfaceを実装する。
#[async_trait::async_trait]
trait LightingAdapter:
Send + Sync
{
async fn prepare_scene(
&self,
scene:
&LightingScene,
) -> Result<
(),
LightingError,
>;
async fn apply(
&self,
command:
&LightingCommand,
) -> Result<
LightingExecutionResult,
LightingError,
>;
async fn state(
&self,
) -> Result<
LightingObservedState,
LightingError,
>;
async fn health(
&self,
) -> DeviceHealth;
async fn safe_scene(
&self,
) -> Result<
LightingExecutionResult,
LightingError,
>;
}
これによってDMX、Art-Net、sACN、Vendor APIなどをAdapterの後ろへ隠せる。
8 Lighting Protocol
Studio設備では複数のLighting Control Protocolが利用され得る。
代表的には、
DMX512。
Art-Net。
sACN。
専用Controller API。
などである。
FEELCYCLE RuntimeはProtocolを一つへ固定しない。
Rust Runtime
↓
Lighting Adapter
├── DMX Adapter
├── Art-Net Adapter
├── sACN Adapter
└── Vendor Adapter
とする。
Hardware交換時にRuntime Coreを書き換えない。
9 DMX Mapping
DMX系設備なら、FixtureとChannel Mappingが必要になる。
#[derive(
Debug,
Clone,
serde::Deserialize,
)]
struct DmxFixtureMapping {
fixture_id:
String,
universe:
u16,
start_channel:
u16,
channel_count:
u16,
}
しかしProgram CreatorやAIはこの値を意識しない。
Physical Adapterだけが利用する。
10 Semantic SceneからDevice Valuesへ
Scene Translationを実装する。
fn resolve_scene(
intent:
LightingIntent,
scenes:
&[LightingScene],
) -> Option<
LightingScene
> {
scenes
.iter()
.find(
|scene|
scene.intent
== intent
)
.cloned()
}
さらにScene DefinitionをProtocol Packetへ変換する。
概念的には、
LightingIntent::Peak
↓
LightingScene
↓
Fixture Values
↓
Protocol Packet
となる。
意味と物理値の間に明確なTranslation Boundaryを置く。
11 Lightingの時間
Lightingは単にStateを切り替えるだけではない。
TransitionそのものがExperienceを形成する。
DarkからFocus。
FocusからBuild。
BuildからPeak。
PeakからRelease。
同じ二つのStateでも、
瞬時に変わるのか。
1秒かけるのか。
数秒かけるのか。
によってExperienceは異なる。
したがってLighting Commandは、
Target State
だけでなく、
Transition Duration
も持つ。
struct LightingTransition {
from:
LightingIntent,
to:
LightingIntent,
duration_ms:
u64,
}
12 Musicとの同期
Audio SystemとLighting Systemは同じSession Clockへ接続する。
たとえば、
Music Peak
= 138.500 sec
Lighting Peak
= 138.500 sec
を目標にする。
しかしDevice Latencyは異なる。
Audio Response = 4ms。
Lighting Controller Response = 18ms。
と仮定するなら、
Audio Dispatch
≈ 138.496
Lighting Dispatch
≈ 138.482
のように先行送信する発想になる。
一般化すると、
Dispatch Time
=
Target Physical Time
-
Estimated Device Latency
である。
13 Lighting Latency Profile
#[derive(
Debug,
Clone,
)]
struct LightingLatencyProfile {
controller_id:
uuid::Uuid,
expected_ms:
f64,
p95_ms:
f64,
maximum_ms:
f64,
}
Sessionごとに測定結果をMemoryへ戻せば、Studio固有の補正値を更新できる。
ただしリアルタイム自動補正を過度に行い、Lightingが不安定になるのは避ける。
Stable Timingを優先する。
14 Lighting Scheduler
Lighting EventをDispatchする。
async fn schedule_lighting(
command:
LightingCommand,
latency:
&LightingLatencyProfile,
session_clock:
&SessionClock,
adapter:
&dyn LightingAdapter,
) -> Result<
LightingExecutionResult,
LightingError,
> {
let dispatch_seconds =
command
.target_session_seconds
-
latency.expected_ms
/ 1000.0;
session_clock
.wait_until(
dispatch_seconds
)
.await;
adapter
.apply(
&command
)
.await
}
これは概念実装である。
実際にはCancellation、Priority、Clock Drift、Safe Stateなどを追加する。
15 Lighting Execution Result
#[derive(
Debug,
Clone,
serde::Serialize,
)]
struct LightingExecutionResult {
command_id:
uuid::Uuid,
accepted:
bool,
applied:
bool,
applied_at_seconds:
Option<f64>,
controller_state:
Option<String>,
message:
Option<String>,
}
Commandを出した時刻ではなく、可能ならApplied Stateまで取得する。
16 DesiredとObserved
Lighting Stateも二重化する。
#[derive(
Debug,
Clone,
)]
struct LightingRuntimeState {
desired:
LightingIntent,
commanded_scene:
Option<String>,
observed_scene:
Option<String>,
health:
DeviceHealth,
}
例えば、
Desired
=
Peak
Commanded
=
peak_v3
Observed
=
build_v2
なら、Physical RealityはまだPeakへ移行していない。
このDifferenceを明示する。
17 Fixture State
ControllerからFixture個別Stateを取得できる設備なら利用する。
#[derive(
Debug,
Clone,
)]
struct FixtureState {
fixture_id:
String,
health:
DeviceHealth,
reported_state:
Option<
serde_json::Value
>,
}
しかしすべてのFixtureが双方向Telemetryを返すとは限らない。
その場合、
Controller Accepted
と、
Physical Verified
を混同しない。
18 Physical Verification
より高度なVerificationでは、照度SensorやCameraを利用する可能性もある。
しかしCameraはPrivacy Impactが大きい。
照明確認だけが目的なら、映像を保存するより、
光量Sensor。
Controller Telemetry。
限定的なEdge Feature。
など、よりPrivacy Costの低い方法を優先する。
Need Lighting Verification
≠
Need Continuous Video Recording
である。
19 暗闇を安全に扱う
FEELCYCLEの重要な空間要素として暗闇がある。
しかしPhysical Runtimeで「暗闇」を単なるintensity = 0として扱うだけでは不十分である。
実Studioには、
避難。
設備安全。
運用。
法令。
非常時照明。
などAutomationとは独立したSafety Layerが必要になる。
したがって、
FEELCYCLE Lighting Runtime
が制御する演出照明と、
施設安全のための照明
を分離する。
Experience Lighting
↓
AI / Runtime Control
Safety / Emergency Lighting
↓
Independent Safety System
AIが後者を無効化できない構造にする。
20 Safety Envelope
Lightingにも許容範囲を置く。
#[derive(
Debug,
Clone,
)]
struct LightingSafetyConfig {
allowed_scene_ids:
std::collections::HashSet<
String
>,
minimum_transition_ms:
u64,
allow_dynamic_effects:
bool,
}
Commandを検証する。
fn validate_lighting_command(
command:
&LightingCommand,
safety:
&LightingSafetyConfig,
) -> Result<
(),
LightingError,
> {
if !safety
.allowed_scene_ids
.contains(
&command.scene_id
)
{
return Err(
LightingError::
SceneNotAllowed
);
}
if command.transition_ms
< safety.minimum_transition_ms
{
return Err(
LightingError::
UnsafeTransition
);
}
Ok(())
}
実際の安全要件は照明設備、演出内容、専門家の検証に基づいて具体化する。
21 Dynamic Lightingと注意
高速な点滅や急激な光変化は、人によって安全上の問題を生じ得る。
したがってAIに自由なEffect Generationを許可する設計にはしない。
利用可能なSceneやEffectを事前検証済みのAllowlistへ限定する。
AI
↓
Semantic Intent
↓
Approved Scene Library
↓
Safety Validation
↓
Physical Output
AIは安全範囲の外へ新しいHardware Patternを直接生成しない。
22 Scene Library
CREATE TABLE approved_lighting_scenes (
scene_id UUID PRIMARY KEY,
studio_id UUID NOT NULL,
scene_name TEXT NOT NULL,
semantic_intent TEXT NOT NULL,
safety_status TEXT NOT NULL,
approved_at TIMESTAMPTZ,
approved_by UUID,
active BOOLEAN NOT NULL
DEFAULT FALSE
);
Production Runtimeでは、
safety_status = 'approved'
かつ、
active = TRUE
のSceneだけを実行対象にする。
23 AIとLighting
Python Intelligenceができるのは、
Music Energyを解析する。
Sectionを認識する。
Collective Stateを推定する。
Lighting Candidateを生成する。
ことである。
例えば、
Music Energy rising
+
Transition approaching
+
Program Context
↓
Suggestion:
Build → Peak
とする。
しかし直接Fixture Valueにはしない。
SuggestionがProgram PolicyやHuman Approvalを必要とする場合は、Instructor Consoleへ送る。
Python
↓
Lighting Suggestion
↓
Instructor
↓
Accept / Modify / Ignore
↓
Rust Runtime
↓
Approved Scene
↓
Physical Lighting
とする。
24 Program-defined Lighting
一方、Program Creatorがあらかじめ設計し、承認済みProgram Versionに含まれるLighting CueはAutomationとして実行できる。
ただしそれでも、
Rust Runtime。
Safety Validation。
Lighting Adapter。
を通す。
Published Program
↓
Scheduled Lighting Cue
↓
Runtime
↓
Safety
↓
Adapter
↓
Scene
Program Published
≠
Safety Bypass
である。
25 Manual Override
Lighting Automationは人間が切り離せる。
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
)]
enum LightingControlMode {
Automatic,
Assisted,
Manual,
Safe,
}
Manualへ移行する。
fn enter_lighting_manual(
mode:
&mut LightingControlMode,
) {
*mode =
LightingControlMode::Manual;
}
Manual ModeではRuntimeからのAutomation Commandを停止する。
ただしSafety Systemは維持する。
26 Safe Scene
Lighting Controller FailureやRuntime Errorが発生した場合に、可能なら事前定義したSafe Sceneへ移行する。
async fn enter_safe_lighting(
adapter:
&dyn LightingAdapter,
) -> Result<
LightingExecutionResult,
LightingError,
> {
adapter
.safe_scene()
.await
}
Safe Sceneは派手な演出ではない。
人間が状況を理解し、安全に運用を継続または停止できる状態である。
27 Fallback
Lighting Failureが起きても、Audioまで止める必要がない場合がある。
Lighting Failure
↓
Fallback Scene
↓
Audio Continues
↓
Instructor Continues
つまりSubsystem FailureをSession全体のFailureへ直結させない。
LightingはDegraded Modeへ移る。
28 Lighting Runtime Mode
#[derive(
Debug,
Clone,
Copy,
)]
enum LightingRuntimeMode {
Normal,
Fallback,
Manual,
Safe,
Unavailable,
}
Studio MonitorではこのStateを表示する。
Instructor Consoleではより簡潔に、
通常。
代替照明。
手動。
安全状態。
程度へTranslationする。
29 Device Health
#[derive(
Debug,
Clone,
)]
struct LightingHealth {
edge_adapter:
DeviceHealth,
controller:
DeviceHealth,
network:
DeviceHealth,
fixtures:
DeviceHealth,
}
全体Healthを計算する。
fn overall_lighting_health(
health:
&LightingHealth,
) -> DeviceHealth {
let states = [
health.edge_adapter,
health.controller,
health.network,
health.fixtures,
];
if states
.contains(
&DeviceHealth::Unavailable
)
{
DeviceHealth::Unavailable
} else if states
.contains(
&DeviceHealth::Degraded
)
{
DeviceHealth::Degraded
} else if states
.contains(
&DeviceHealth::Unknown
)
{
DeviceHealth::Unknown
} else {
DeviceHealth::Healthy
}
}
30 Preflight
Session開始前にはLightingを確認する。
#[derive(Debug)]
struct LightingPreflight {
controller_ready:
bool,
scene_library_ready:
bool,
network_ready:
bool,
safe_scene_ready:
bool,
manual_control_ready:
bool,
}
Critical要素が利用不能なら、開始前にOperatorへ返す。
31 Preflightの意味
確認するのは、
Controllerへ接続できるか。
Programで利用するSceneが存在するか。
Sceneが承認済みか。
Safe Sceneが利用できるか。
Manual Controlが使えるか。
Network Pathが正常か。
である。
Lighting Systemが「動くか」だけではなく、
安全に失敗できるか
まで確認する。
32 Lighting Event Memory
実行結果をDatabaseへ戻す。
CREATE TABLE lighting_runtime_events (
lighting_event_id UUID PRIMARY KEY
DEFAULT gen_random_uuid(),
session_id UUID NOT NULL,
command_id UUID NOT NULL,
scene_id TEXT NOT NULL,
semantic_intent TEXT NOT NULL,
target_seconds
DOUBLE PRECISION,
dispatched_seconds
DOUBLE PRECISION,
applied_seconds
DOUBLE PRECISION,
runtime_mode TEXT NOT NULL,
result TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL
DEFAULT NOW(),
FOREIGN KEY (
session_id
)
REFERENCES sessions(
session_id
)
);
これによってPhysical LightingのTimelineを再構成できる。
33 Lighting Timing Difference
Session終了後に、
SELECT
semantic_intent,
target_seconds,
applied_seconds,
(
applied_seconds
- target_seconds
) * 1000
AS difference_ms
FROM lighting_runtime_events
WHERE session_id = $1
AND applied_seconds
IS NOT NULL
ORDER BY
target_seconds;
とすれば、Physical Timing Differenceを検証できる。
34 Lighting Session Summary
CREATE TABLE lighting_session_summaries (
session_id UUID PRIMARY KEY,
availability
DOUBLE PRECISION,
average_timing_difference_ms
DOUBLE PRECISION,
p95_timing_difference_ms
DOUBLE PRECISION,
fallback_count
INTEGER NOT NULL
DEFAULT 0,
manual_override_count
INTEGER NOT NULL
DEFAULT 0,
failure_count
INTEGER NOT NULL
DEFAULT 0,
generated_at TIMESTAMPTZ NOT NULL
DEFAULT NOW(),
FOREIGN KEY (
session_id
)
REFERENCES sessions(
session_id
)
);
Company DashboardではこのSummaryを使える。
35 AudioとLightingを比較する
同じSession IDとTarget Timeによって、AudioとLightingを比較できる。
Target Transition
138.500 sec
Audio Applied
138.504 sec
Lighting Applied
138.518 sec
であれば、Physical Differenceを測定できる。
しかし、常に0msにすることが目的ではない。
人間が知覚するExperienceとHardware特性を踏まえ、必要十分な同期を目指す。
36 Synchronization Memory
CREATE TABLE physical_sync_measurements (
measurement_id UUID PRIMARY KEY
DEFAULT gen_random_uuid(),
session_id UUID NOT NULL,
reference_type TEXT NOT NULL,
reference_seconds
DOUBLE PRECISION NOT NULL,
audio_seconds
DOUBLE PRECISION,
lighting_seconds
DOUBLE PRECISION,
difference_ms
DOUBLE PRECISION,
created_at TIMESTAMPTZ NOT NULL
DEFAULT NOW()
);
こうしたDataからStudioごとのLatency Characteristicを学習できる。
37 LightingとInstructor
Lighting Systemが高度化してもInstructorをLighting Operatorにしてはいけない。
Instructor Consoleでは必要な場合のみ、
Current Scene。
Next Lighting Transition。
AI Suggestion。
Manual State。
を表示する。
複雑なFixtureやUniverse情報はStudio Monitor側に置く。
InstructorのAttentionはPhysical Realityへ残す。
38 LightingとMember
Member AppへRealtime Lighting Dataを流す必要は基本的にない。
MemberはLightingをDataとして見るのではなくExperienceとして受け取る。
Technologyを意識させないこと自体がUI Designになる。
39 LightingとProgram Creator
Program BuilderではLighting TimelineをMusic、Movementと同じ時間軸上で設計する。
Music
──────Build────────Peak────Release
Movement
────Build──────────Peak────Recovery
Lighting
Dark──Focus──Build──Peak────Release
Program CreatorはHardware ChannelではなくRelationを見る。
これがLighting IntelligenceのHuman Interfaceである。
40 Lighting System v0.1の完成条件
FEELCYCLE Lighting System v0.1は、最低限次を満たす。
Semantic Lighting Intentを定義できる。
Studio固有SceneへTranslationできる。
SceneをVersion管理できる。
承認済みSceneだけをProduction実行できる。
Rust RuntimeからTarget Time付きCommandを送れる。
Device Latencyを考慮できる。
Controller Stateを観測できる。
Desired StateとObserved Stateを分離できる。
Human Manual Overrideを保持できる。
Failure時にFallbackまたはSafe Sceneへ移行できる。
施設Safety LightingをAI制御から独立させられる。
Lighting EventをSession Memoryへ戻せる。
AudioとのPhysical Synchronizationを検証できる。
ここまででFEELCYCLE AIは、
Musicを「音」へ。
Program Stateを「光」へ。
変換できるようになった。
音と光が同じSession Clockへ接続され、45分の時間構造がPhysical Spaceへ展開される。
しかし、ここまでのSystemはまだRealityへ作用する能力の方が強い。
次に必要なのは、Realityを見る能力である。
Studioでは何が起きているのか。
Audio Systemは実際に音を出しているのか。
空間の状態はどう変化しているのか。
Deviceは正常か。
人間を監視することなく、Physical Runtimeに必要なObservationをどう取得するのか。
次節では、
Microphone・Sensor・Edge Device
を実装する。
Physical Realityを無差別に記録するのではなく、必要なFeatureだけをEdgeで抽出し、RealityからAIへの安全な帰路を構築する。
第4節 Microphone・Sensor・Edge Device
Audio Systemによって音がPhysical Realityへ出力され、Lighting Systemによって光が空間へ展開された。
次に必要なのは、Physical RealityからFEELCYCLE AIへ戻る経路である。
Studioでは、SoftwareがCommandを送るだけでは十分ではない。
実際に音は出ているのか。
Lighting Controllerは正常なのか。
Networkは安定しているのか。
Physical Deviceは応答しているのか。
Studioの環境状態にはどのような変化が生じているのか。
こうしたRealityを観測しなければ、AIは自分が生成したCommandの結果を知ることができない。
そこで本節では、
Microphone。
Sensor。
Edge Device。
をPhysical Runtimeへ接続する。
ただし、最初に境界を置く。
FEELCYCLE AIのSensor Systemは、人間を無差別に監視するSystemではない。
目的は、
Physical Runtimeに必要なRealityを、必要最小限のDataによって観測すること
である。
したがって基本構造は、
Physical Reality
↓
Sensor
↓
Raw Signal
↓
Edge Processing
↓
Feature
↓
Rust Runtime
↓
Python Intelligence / Memory
となる。
重要なのは、
Raw Signal
≠
Meaning
である。
Raw Audioを保存することと、Studioの音響状態を理解することは同じではない。
Camera映像を記録することと、空間状態を理解することも同じではない。
可能な限りEdgeで必要なFeatureへ変換し、不要なRaw Dataは残さない。
1 Observation Layer
FEELCYCLE Physical RuntimeにObservation Layerを追加する。
Physical Studio
│
├── Audio Output
├── Lighting Output
├── Instructor Voice
├── Device State
├── Network State
└── Environmental State
↓
Sensors
↓
Edge Device
↓
Feature Extraction
↓
Observation
↓
Rust Runtime
↓
Python Intelligence
↓
Memory
ここでSensorはRealityを完全に記述するものではない。
Realityの一部分を観測する。
複数のObservationを統合しながら、AIが推定する。
したがって、
Observation
↓
Interpretation
↓
Estimate
を分離する。
2 Microphoneの役割を分ける
FEELCYCLE Studioには、少なくとも二種類のMicrophoneの役割が考えられる。
Instructor Microphone。
Measurement Microphone。
である。
Instructor Microphone
=
声をPhysical Audio Systemへ届ける
Measurement Microphone
=
Studioの音響Realityを観測する
二つを同じData Pipelineへ入れない。
Instructor MicrophoneはAudio Inputである。
Measurement MicrophoneはSensorである。
目的が違う。
3 Instructor Microphone
Instructor Microphoneの主要経路は、
Instructor
↓
Microphone
↓
Mixer
↓
DSP
↓
Speaker
↓
Studio
である。
AIが必要とする場合でも、必ずしも音声内容そのものを記録する必要はない。
必要なのが、
Voice Activity。
Signal Level。
Microphone Health。
程度なら、EdgeでFeatureだけを抽出する。
#[derive(
Debug,
Clone,
serde::Serialize,
)]
struct VoiceActivityFeature {
active: bool,
signal_level:
Option<f64>,
confidence:
f64,
observed_at_seconds:
f64,
}
これだけでも、
現在Instructor Voiceが存在するか。
Signalが途切れていないか。
を観測できる。
Speech Recordingをしなくても成立する。
4 Measurement Microphone
Studio AudioをPhysical Realityとして確認したい場合には、Measurement Microphoneを利用できる。
目的は、
Playback EngineがPlayingと言っている。
しかしStudioでは本当に音が出ているのか。
を確認することである。
Playback Engine
↓
Audio Chain
↓
Speaker
↓
Studio
↓
Measurement Microphone
↓
Feature Extraction
↓
Output Presence
例えばFeatureを、
#[derive(
Debug,
Clone,
)]
struct AudioEnvironmentFeature {
output_detected:
bool,
relative_level:
Option<f64>,
spectral_summary:
Option<Vec<f64>>,
confidence:
f64,
}
とする。
ここでもRaw RecordingをDefault Memoryにしない。
5 Raw Audioを保存しない設計
音響状態の検証が目的なら、
Raw Audio
↓
Edge Memory
↓
Feature Extraction
↓
Feature
↓
Raw Audio Discard
とできる。
つまり、
Need Audio Feature
≠
Need Audio Archive
である。
これはPrivacyだけでなくStorage、Security、Governanceの負荷も下げる。
Raw Audioが必要になる特別なTestingやCalibrationでは、別の明示的なModeとPolicyを使う。
6 Sensor Type
StudioにはMicrophone以外にも複数Sensorを配置できる。
ただしv0.1では、目的ごとに限定する。
#[derive(
Debug,
Clone,
Copy,
serde::Serialize,
serde::Deserialize,
)]
enum SensorType {
AudioMeasurement,
Environmental,
DeviceTelemetry,
LightingMeasurement,
NetworkTelemetry,
}
将来のSensorを追加できるが、何でも収集するArchitectureにはしない。
7 Environmental Sensor
Physical Environmentの安定性を見る場合、
温度。
湿度。
機材Rackの環境。
などを設備保守目的で扱える。
#[derive(
Debug,
Clone,
)]
struct EnvironmentObservation {
temperature_c:
Option<f64>,
humidity_ratio:
Option<f64>,
observed_at:
chrono::DateTime<
chrono::Utc
>,
}
ただしMemberの身体状態をEnvironmental Sensor Dataから勝手に推定するような利用へ拡大しない。
Sensor DataのPurposeを守る。
8 Lighting Measurement
Lighting ControllerがScene Appliedと返しても、Physical Outputが完全に一致しているとは限らない。
必要なら簡易的な光Sensorを使える。
#[derive(
Debug,
Clone,
)]
struct LightingObservation {
relative_light_level:
f64,
sensor_id:
uuid::Uuid,
observed_at_seconds:
f64,
confidence:
f64,
}
ただし、この値をそのまま、
LightingIntent::Peak
と断定しない。
Observed LevelはMeasurement。
Scene IdentityはInterpretationである。
9 Device Telemetry
多くの場合、Physical Runtimeで最も有用なSensorは専用の人体Sensorではなく、Device自身が返すTelemetryである。
Audio Interface。
Mixer。
DSP。
Lighting Controller。
Edge Computer。
Network Switch。
などの状態を取得する。
#[derive(
Debug,
Clone,
)]
struct DeviceTelemetry {
device_id:
uuid::Uuid,
online:
bool,
latency_ms:
Option<f64>,
error_code:
Option<String>,
observed_at:
chrono::DateTime<
chrono::Utc
>,
}
これによって、人間を観測せずにSystem Healthの多くを理解できる。
10 Network Telemetry
Physical Deviceの多くがNetworkへ接続されるなら、Network自身を観測する。
#[derive(
Debug,
Clone,
)]
struct NetworkObservation {
target:
String,
latency_ms:
Option<f64>,
packet_loss_ratio:
Option<f64>,
reachable:
bool,
observed_at:
chrono::DateTime<
chrono::Utc
>,
}
Network FailureをLighting FailureやAudio Failureと誤認しないために重要である。
11 Sensor Observationの共通型
異なるSensorをRuntimeへ接続するため、共通Envelopeを作る。
#[derive(
Debug,
Clone,
serde::Serialize,
)]
struct SensorObservation {
observation_id:
uuid::Uuid,
session_id:
Option<uuid::Uuid>,
sensor_id:
uuid::Uuid,
sensor_type:
SensorType,
observed_at_seconds:
Option<f64>,
evidence_type:
EvidenceType,
quality:
SensorQuality,
payload:
serde_json::Value,
}
Evidence Typeを定義する。
#[derive(
Debug,
Clone,
Copy,
serde::Serialize,
)]
enum EvidenceType {
Observed,
Estimated,
Derived,
}
Sensor Dataは原則Observedである。
Sensorを組み合わせてAIが生成したCollective StateなどはEstimatedになる。
この区別を失わない。
12 Sensor Quality
すべてのObservationへQualityを付ける。
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
serde::Serialize,
)]
enum SensorQuality {
Good,
Partial,
Poor,
Unavailable,
}
例えばMicrophone Featureが、
value = 0
なのか、
Sensor unavailable
なのかを区別する。
0
≠
No Data
である。
13 Sensor Health
#[derive(
Debug,
Clone,
)]
struct SensorHealth {
sensor_id:
uuid::Uuid,
device_health:
DeviceHealth,
last_observation:
Option<
std::time::Instant
>,
sample_rate_hz:
Option<f64>,
}
一定時間Observationが来なければ、UnknownまたはUnavailableへ移す。
14 Edge Deviceとは何か
ここでEdge Deviceの役割を明確にする。
Edge Deviceは単なるStudio PCではない。
CloudとPhysical Realityの境界に置かれるLocal Execution Nodeである。
最低限、
Rust Runtime。
Audio Adapter。
Lighting Adapter。
Sensor Gateway。
Local Memory。
Health Monitoring。
Cloud Synchronization。
を動かす。
FEELCYCLE Edge
│
├── Runtime Core
├── Audio
├── Lighting
├── Sensor
├── Local Database / Buffer
├── Health
├── Security
└── Cloud Sync
これがStudio単位のPhysical Computer Coreになる。
15 Edge Hardwareの要件
具体的な製品名より、Requirementを先に定める。
必要なのは、
安定したCPU。
十分なMemory。
SSD。
複数のNetwork Interface。
必要なUSB / Audio Interface。
自動再起動。
Watchdog。
長時間連続稼働。
適切な冷却。
遠隔保守可能性。
である。
必要に応じてGPUやNPUを追加できる。
しかし、v0.1のRealtime Runtime自体に巨大GPUは必須ではない。
重いAI InferenceはCloudまたは別Computeへ分離できる。
16 Edgeで何を処理するか
Edgeへ何でも詰め込む必要はない。
Edgeで処理すべきものは、
低Latencyが必要。
Cloud Failure時にも必要。
Privacy上Local Processingが望ましい。
というものを優先する。
Edge
=
Low Latency
+
Local Continuity
+
Privacy-sensitive Feature Extraction
具体的には、
Runtime Clock。
Audio / Lighting Control。
Sensor Feature Extraction。
Device Health。
Local Event Buffer。
Fallback。
などである。
17 Cloudで何を処理するか
一方Cloudへ置くのは、
長期Memory。
Cross-Studio Analytics。
Model Training。
Company Dashboard。
Global Program Distribution。
などである。
Edge
=
Current Reality
Cloud
=
Shared Long-Term Memory
と整理できる。
18 EdgeとCloudの通信
EdgeからCloudへは、直接Database Connectionを持たせるよりAPI / Queue Layerを通す。
Edge
↓
Authenticated Connection
↓
Ingestion API
↓
Queue
↓
Cloud Memory
CloudからEdgeへは、
Program Configuration。
Approved Model。
Studio Configuration。
などを配信する。
しかしCloudから任意のPhysical Commandを直接Pushして即時実行するArchitectureには慎重である。
19 Command Authority
CloudがPhysical Runtimeへ何かを送る場合でも、
Cloud Request
↓
Edge Validation
↓
Authority Check
↓
Safety Policy
↓
Local Runtime
↓
Device
とする。
Edgeが最後のAuthority Boundaryになる。
Cloud
≠
Unrestricted Remote Control
である。
20 Edge Service Architecture
Rust側のProcessを分割する。
feelcycle-edge
│
├── runtime-core
├── audio-service
├── lighting-service
├── sensor-service
├── health-service
├── persistence-service
└── cloud-sync-service
すべてを一つの巨大なFunctionへ書かない。
ProcessまたはModule Boundaryを持たせる。
21 Sensor Gateway
Sensor Gatewayは複数Sensor Inputを受け取る。
#[async_trait::async_trait]
trait SensorAdapter:
Send + Sync
{
async fn read(
&self,
) -> Result<
SensorObservation,
SensorError,
>;
async fn health(
&self,
) -> DeviceHealth;
}
Microphone Feature Adapter。
Environment Adapter。
Network Adapter。
などがこれを実装する。
22 Sensor Polling
一定周期でSensorを読むものなら、
async fn sensor_loop(
adapter:
&dyn SensorAdapter,
tx:
tokio::sync::mpsc::Sender<
SensorObservation
>,
interval:
std::time::Duration,
) {
let mut timer =
tokio::time::interval(
interval
);
loop {
timer.tick().await;
match adapter.read().await {
Ok(observation) => {
let _ =
tx.send(
observation
)
.await;
}
Err(error) => {
record_sensor_error(
error
)
.await;
}
}
}
}
とできる。
必要以上のSampling Rateにしない。
Purposeに応じたFrequencyを選ぶ。
23 Streaming Sensor
Microphone FeatureのようにContinuous Streamが必要なら、Audio Processing ThreadからFeatureだけを送る。
Audio Stream
↓
Windowing
↓
Feature Extraction
↓
Feature Queue
↓
Sensor Gateway
Raw SamplesをRuntime Event Queueへ流し続けるのではない。
Feature Levelまで圧縮する。
24 Feature Window
例えば一定時間WindowでFeatureを生成する。
#[derive(Debug)]
struct FeatureWindow {
started_at_seconds:
f64,
ended_at_seconds:
f64,
sample_count:
usize,
}
これによって、
「この100ms / 500ms / 1秒間で何が観測されたか」
として扱える。
具体的Windowは用途ごとに設定する。
25 Edge AI
将来的にはEdge上で軽量Machine Learning Modelを動かせる。
例えば、
Audio Feature Classification。
Device Anomaly Detection。
Sensor Quality Estimation。
などである。
しかしEdge AIのOutputは、
Observed
ではなく、
Estimated
として扱う。
#[derive(
Debug,
Clone,
)]
struct EdgeEstimate {
estimate_type:
String,
value:
serde_json::Value,
confidence:
f64,
model_version:
String,
}
Model Versionも残す。
26 Edge Model Distribution
Cloudで検証済みModelをEdgeへ配布する。
Training
↓
Evaluation
↓
Approved Model
↓
Signed Artifact
↓
Edge Download
↓
Verification
↓
Activate
Model Fileを取得しただけで即Activateしない。
ChecksumやSignatureを検証する。
27 Model Rollback
新しいEdge Modelに問題があれば前Versionへ戻せるようにする。
#[derive(
Debug,
Clone,
)]
struct EdgeModelState {
active_version:
String,
previous_version:
Option<String>,
}
AI ModelもHardware Configurationと同様にVersioned Runtime Componentである。
28 Edge Configuration
Edge Device自身のConfigurationを持つ。
#[derive(
Debug,
Clone,
serde::Deserialize,
)]
struct EdgeConfig {
studio_id:
uuid::Uuid,
device_id:
uuid::Uuid,
environment:
String,
cloud_endpoint:
String,
local_data_path:
String,
sensor_enabled:
bool,
}
SecretはConfiguration Fileへ平文保存しない。
Credential StoreやOS-level Secret Mechanismを使う。
29 Boot Sequence
Edge Deviceが起動したら、いきなりHardware Controlを開始しない。
Boot
↓
Configuration Load
↓
Identity Verify
↓
Local Memory Check
↓
Adapter Initialize
↓
Device Health Check
↓
Safe State
↓
Cloud Connect
↓
Ready
という順序にする。
30 Boot State
#[derive(
Debug,
Clone,
Copy,
)]
enum EdgeBootState {
Starting,
LoadingConfig,
InitializingDevices,
Verifying,
Ready,
Degraded,
Failed,
}
Studio Monitorから確認できるようにする。
31 Watchdog
Edge Runtimeが停止した場合、自動的に検出できる仕組みを持つ。
Software WatchdogやOS / Hardware Watchdogを利用できる。
概念的には、
Runtime Heartbeat
↓
Watchdog
├── Healthy → Continue
└── Missing → Restart / Safe State
とする。
ただしRestart Loopに陥らないよう制御する。
32 Local Persistence
Cloudが切れてもObservationや重要Eventを失わないため、EdgeへLocal Persistenceを持つ。
v0.1ではSQLiteやLocal Append-only Logなどを利用できる。
例えばSQLiteなら、
CREATE TABLE local_events (
event_id TEXT PRIMARY KEY,
session_id TEXT,
event_type TEXT NOT NULL,
payload TEXT NOT NULL,
synced INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL
);
Cloud Sync後にsynced = 1へする。
33 Append-only Log
Physical RuntimeではAppend-only Event Logも有効である。
Event 001
Event 002
Event 003
...
Current Stateだけでなく、
何が起きたか
を保持する。
Edge Failure後にもSessionを再構成しやすい。
34 Cloud Reconciliation
Cloud復旧後、
Local Event ID。
Cloud Event ID。
を比較する。
未同期だけ送る。
async fn sync_pending_events(
events:
Vec<LocalEvent>,
) {
for event in events {
if cloud_has_event(
event.event_id
)
.await
{
mark_synced(
event.event_id
)
.await;
continue;
}
upload_event(
&event
)
.await;
}
}
Event IDによって重複Memoryを防ぐ。
35 Edge Security
Edge DeviceはPhysical Studio内にあるため、Cloudとは別のSecurity Riskを持つ。
機材へのPhysical Access。
USB Device。
Network接続。
Local Storage。
Remote Maintenance。
を考える。
最低限、
OS Update。
Firewall。
Disk Encryption。
Service Account。
Secure Bootが可能なら利用。
Unused Portの無効化。
Remote Accessの制限。
を行う。
36 Device Identity
Edge DeviceもIdentityを持つ。
CREATE TABLE edge_devices (
edge_device_id UUID PRIMARY KEY,
studio_id UUID NOT NULL,
device_name TEXT NOT NULL,
hardware_reference TEXT,
software_version TEXT,
status TEXT NOT NULL,
installed_at TIMESTAMPTZ,
last_seen_at TIMESTAMPTZ,
FOREIGN KEY (
studio_id
)
REFERENCES studios(
studio_id
)
);
Cloudは、
「Studio Aを名乗っている何か」
ではなく、
認証されたEdge Device
として扱う。
37 Certificate-based Identity
EdgeとCloud間では、Device Certificateなどを用いたMachine Identityを利用できる。
概念構造は、
Edge Private Key
↓
Certificate
↓
Mutual Authentication
↓
Cloud
とする。
固定API Keyを全Studioで共有する設計は避ける。
一台がCompromiseされても全Studioへ広がらないようにする。
38 ObservationをRuntimeへ送る
Sensor ObservationをRust Runtimeへ流す。
async fn observation_router(
mut rx:
tokio::sync::mpsc::Receiver<
SensorObservation
>,
runtime_tx:
tokio::sync::mpsc::Sender<
RuntimeEvent
>,
) {
while let Some(
observation
) = rx.recv().await
{
if let Some(event) =
observation_to_runtime_event(
observation
)
{
let _ =
runtime_tx
.send(event)
.await;
}
}
}
すべてのObservationをRuntime Eventへ変換する必要はない。
意味のあるState Changeだけを流す。
39 Noiseを抑える
SensorはNoiseを持つ。
一回だけNetwork Latencyが上がった。
一瞬Measurement MicのFeatureが欠落した。
それだけでRuntime Stateを頻繁に切り替えるとSystemが不安定になる。
そこでDebounceやHysteresisを使う。
概念的には、
One abnormal sample
↓
Observe
Repeated abnormal samples
↓
Degraded State
とする。
40 Simple Threshold State
struct FailureCounter {
consecutive_failures:
u32,
threshold:
u32,
}
impl FailureCounter {
fn report_failure(
&mut self,
) -> bool {
self.consecutive_failures
+= 1;
self.consecutive_failures
>= self.threshold
}
fn report_success(
&mut self,
) {
self.consecutive_failures =
0;
}
}
これによって一時的NoiseでPhysical Runtime全体がFallbackへ入るのを減らす。
41 Sensor Fusion
複数Observationを統合できる。
例えばAudio Output確認では、
Playback Engine State。
Mixer State。
Measurement Microphone。
を一緒に見る。
Playback says Playing
+
Mixer says Healthy
+
Measurement says Output Present
↓
High Confidence Audio Output
一方、
Playback says Playing
+
Measurement says Silence
↓
Possible Physical Failure
となる。
Single SensorだけでRealityを決めない。
42 Observation Confidence
統合結果にはConfidenceを持たせる。
#[derive(
Debug,
Clone,
)]
struct RealityEstimate {
estimate_type:
String,
confidence:
f64,
evidence_ids:
Vec<uuid::Uuid>,
}
Evidence IDから元Observationへ遡れる。
43 Collective Stateとの境界
将来的にStudio全体のCollective StateをAIが推定する場合も、
Microphone。
Wearable Aggregate。
Program Context。
Instructor Observation。
など複数Sourceを使う。
しかし、
Collective State
Sensor Fact
ではない。
AI Estimateである。
そのためMemoryにはEstimatedとして保存する。
44 Raw Human RecordingをDefaultにしない
MicrophoneやCameraを使えば大量のHuman Dataを収集できる。
しかしFEELCYCLE AIの価値はData量に比例しない。
必要なのは、
音が存在する。
Deviceが正常。
Lightingが反応した。
Networkが遅延している。
といった必要なPhysical Featureである場合が多い。
したがって、
More Recording
≠
Better Intelligence
とする。
45 CameraをDefault Sensorにしない
身体運動解析にはCameraが使える可能性がある。
しかしPrivacy ImpactはMicrophone以上に大きい。
v0.1ではCameraを必須Architectureから外す。
将来利用する場合も、
明確なPurpose。
Consent。
Edge Processing。
Data Retention。
No Raw Recording Option。
などを先に設計する。
46 Sensor Privacy Boundary
Physical Sensorについて、
Operational Sensor
↓
System Health
Optional Human Sensor
↓
Explicit Consent
を分離する。
Network Switch TelemetryにMember Consentは通常必要ない。
Wearable DataやHuman Recordingは別である。
Data Categoryを同一に扱わない。
47 Sensor Memory
Cloudへ保存するのは意味のあるObservationやSummaryに限定する。
CREATE TABLE sensor_observations (
observation_id UUID PRIMARY KEY,
session_id UUID,
sensor_id UUID NOT NULL,
sensor_type TEXT NOT NULL,
evidence_type TEXT NOT NULL,
quality TEXT NOT NULL,
observed_at_seconds
DOUBLE PRECISION,
payload JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL
DEFAULT NOW(),
FOREIGN KEY (
session_id
)
REFERENCES sessions(
session_id
)
);
高頻度Raw SampleはObject Storageまたは短期Local Storageへ分離するか、保存しない。
48 Sensor Summary
Session終了後にはSummaryへ圧縮する。
CREATE TABLE sensor_session_summaries (
sensor_summary_id UUID PRIMARY KEY
DEFAULT gen_random_uuid(),
session_id UUID NOT NULL,
sensor_type TEXT NOT NULL,
availability
DOUBLE PRECISION,
observation_count
INTEGER NOT NULL,
quality_summary TEXT,
summary JSONB NOT NULL
DEFAULT '{}'::jsonb,
generated_at TIMESTAMPTZ NOT NULL
DEFAULT NOW(),
FOREIGN KEY (
session_id
)
REFERENCES sessions(
session_id
)
);
Company Dashboardでは原則Summaryを利用する。
49 Edge Health Summary
Edge Device自身もSessionごとに評価する。
CREATE TABLE edge_session_summaries (
session_id UUID PRIMARY KEY,
edge_device_id UUID NOT NULL,
runtime_availability
DOUBLE PRECISION,
restart_count INTEGER NOT NULL
DEFAULT 0,
local_buffer_peak
INTEGER NOT NULL
DEFAULT 0,
cloud_disconnect_count
INTEGER NOT NULL
DEFAULT 0,
generated_at TIMESTAMPTZ NOT NULL
DEFAULT NOW(),
FOREIGN KEY (
session_id
)
REFERENCES sessions(
session_id
)
);
これによってEdge RuntimeのOperational Qualityも学習できる。
50 Preflight
Session開始前にSensorとEdgeも確認する。
#[derive(Debug)]
struct SensorEdgePreflight {
edge_runtime_ready:
bool,
local_storage_ready:
bool,
audio_measurement_ready:
bool,
network_monitor_ready:
bool,
cloud_sync_ready:
bool,
}
Cloud Syncだけ失われているならSessionは開始可能かもしれない。
Edge Runtimeそのものが利用不能ならCriticalである。
Componentごとの重要度を分ける。
51 Priority
Physical RealityにおけるSensorのPriorityを整理する。
Safety
>
Human Authority
>
Edge Runtime
>
Audio
>
Lighting
>
Operational Sensor
>
Optional Sensor
>
AI Optimization
Sensor Enhancementが失われてもSessionは継続する。
Sensor Failure
≠
Session Failure
である。
52 Fallback
Measurement Microphoneが失われた。
その場合、
Output Verification機能は失われる。
しかしAudio Playback自体は継続できる。
Measurement Failure
↓
Verification Degraded
↓
Audio Continues
Network Telemetryが失われた場合も同様である。
SensorのFailureによって不要にPhysical Outputを止めない。
53 Edge Failure
一方、Edge DeviceそのものがFailureした場合は影響が大きい。
そこで、
Primary Edge。
Manual Physical Control。
Safe State。
などのFallbackを設計する。
規模によってはSecondary Edgeも検討できる。
しかしまずv0.1では、
Edge Failureを検出する。
Automationを安全停止する。
Manualへ移行できる。
ことをCompletion Conditionとする。
54 Manual Physical Operation
Edgeが停止しても、
Audio Mixer。
Lighting Console。
設備Safety。
などのPhysical Control Pathが完全に失われないArchitectureが望ましい。
AI / Edge Automation
↓ failure
Physical Manual Control
↓
Human Operation
Digital AutomationがPhysical Realityの唯一の入口にならない。
55 Edge Update
Edge Softwareの更新も慎重に行う。
Build
↓
Test
↓
Staging
↓
Signed Release
↓
Edge Download
↓
Verify
↓
Install
↓
Health Check
↓
Activate
Session中に無条件でUpdateしない。
Maintenance Windowを利用する。
56 Rollback
#[derive(
Debug,
Clone,
)]
struct EdgeSoftwareVersion {
current:
String,
previous:
Option<String>,
}
Update後のPreflightに失敗したらRollbackする。
Software DeploymentもPhysical Safetyへ影響するからである。
57 Observability
Edge Runtime自身のMetricsを収集する。
CPU。
Memory。
Disk。
Queue Depth。
Device Connection。
Sensor Health。
Cloud Sync Delay。
などである。
しかしMetricsを高頻度でCloudへ送りすぎてNetwork負荷を増やさない。
適切にAggregationする。
58 Edge Diagnostic Event
#[derive(
Debug,
serde::Serialize,
)]
struct EdgeDiagnosticEvent {
edge_device_id:
uuid::Uuid,
category:
String,
code:
String,
occurred_at:
chrono::DateTime<
chrono::Utc
>,
}
Diagnostic LogへRaw AudioやPersonal Dataを不用意に混ぜない。
Observability
≠
Personal Data Collection
である。
59 Studio Monitorとの接続
TypeScript Studio Monitorには、
Edge。
Microphone。
Sensor。
Network。
のHealthを表示する。
しかしRaw Dataを大量表示しない。
Edge
Healthy
Audio Measurement
Healthy
Network
Degraded
Optional Sensor
Unavailable
という意味レベルで表示する。
詳細はDrill Downする。
60 Instructor Consoleとの接続
Instructor Consoleにはさらに少なく表示する。
通常時は何も表示しない。
必要な場合のみ、
「一部Sensorを利用できません。Sessionは継続できます」
と表示する。
Technology FailureによってInstructorのAttentionを不必要に奪わない。
61 Company Dashboardとの接続
Company側には、
Edge Availability。
Sensor Availability。
Network Failure傾向。
Configuration Version。
などをAggregationする。
Raw Audio Featureや個別ObservationをCompany Dashboardの中心には置かない。
Company Observer PositionではStructureを見る。
62 Python Intelligenceとの接続
PythonはSensor Featureを受け取る。
例えば、
def build_runtime_context(
observations: list[dict],
) -> dict:
return {
"audio_output_present":
latest_feature(
observations,
"audio_output"
),
"network_health":
latest_feature(
observations,
"network"
),
"lighting_observed":
latest_feature(
observations,
"lighting"
),
}
ここからAIがReality Estimateを生成する。
しかしSensor Missing時にはUnknownを返す。
推測で埋めない。
63 AIはMissing Dataを知る
def confidence_from_quality(
quality: str,
) -> float:
return {
"good": 1.0,
"partial": 0.6,
"poor": 0.3,
"unavailable": 0.0,
}.get(
quality,
0.0,
)
これによってAI自身が、
何を知っていて。
何を知らないか。
を扱える。
64 Physical Observation Loop
ここまでを一つにまとめる。
Physical Reality
↓
Microphone / Sensor / Telemetry
↓
Edge Device
↓
Feature Extraction
↓
Quality / Evidence
↓
Rust Runtime
↓
Python Intelligence
↓
Estimate / Suggestion
↓
Human / Policy
↓
Physical Runtime
↓
Physical Reality
↺
これでPhysical Runtimeは初めて閉循環になる。
65 Microphone・Sensor・Edge Device v0.1の完成条件
v0.1では、最低限次を満たす。
Instructor MicrophoneとMeasurement Microphoneの役割を分離できる。
Raw Audioを保存せずFeature抽出できる。
複数Sensorを共通Observation Modelへ変換できる。
Sensor Qualityを保持できる。
ObservedとEstimatedを区別できる。
Device Telemetryを取得できる。
Network Telemetryを取得できる。
Edge上でRust Runtimeを継続実行できる。
Cloud断時にLocal Bufferへ保存できる。
Cloud復旧後に同期できる。
Edge DeviceをMachine Identityとして認証できる。
Sensor Failure時にSessionを継続できる。
Edge Failure時にManual / Safe Stateへ移行できる。
ObservationをSession Memoryへ戻せる。
ここまで成立すれば、FEELCYCLE AIは単にPhysical Spaceへ作用するSystemではなくなる。
Realityから返答を受け取れるSystemになる。
66 見るために記録しすぎない
Physical AIでは、「見えるDataを増やすこと」が進化だと考えやすい。
しかしFEELCYCLE AIでは逆の方向を取る。
Raw Audioをすべて保存しなくてもよい。
全員をCameraで追跡しなくてもよい。
すべての身体をWearableで測定しなくてもよい。
必要なObservationを、必要な瞬間に、必要な粒度で取得する。
それでも、
Audioが出たか。
Lightingが反応したか。
Deviceが健康か。
Networkが安定しているか。
Physical CommandがRealityになったか。
を理解できる。
これはSensorを増やす設計ではなく、
Observationを最小化しながらRealityを理解する設計
である。
67 Physical Realityが返事をする
第6章第1節では、AIからPhysical Spaceへ進んだ。
第2節では音を出した。
第3節では光を出した。
本節では、RealityからAIへ戻る道を作った。
これによって、
AI
↓
音・光
↓
Studio
↓
Sensor
↓
AI
という循環が成立する。
しかしStudioには、まだ複数のDeviceを接続するCommunication Layerが必要である。
Audio。
Lighting。
Sensor。
Edge。
Cloud。
Instructor Console。
これらが別々のProtocolで無秩序につながれば、System全体は脆弱になる。
次節では、
Network・Controller・Protocol
を実装する。
Studio内部のNetworkをどう分離するのか。
Audio、Lighting、Sensorをどう接続するのか。
どのProtocolをどのLayerで使うのか。
Command、Telemetry、Realtime Eventをどう分けるのか。
そしてNetwork Failure時にも45分を継続できるPhysical Communication Architectureを構築する。
第5節 Network・Controller・Protocol
ここまでPhysical Runtimeには、実際に音を出すAudio System、空間を変えるLighting System、Realityを観測するMicrophone・Sensor、そしてStudio内でそれらを処理するEdge Deviceが実装された。
しかし、これらが存在するだけでは一つのSystemにはならない。
Rust Runtime。
Audio Playback Engine。
Mixer。
DSP。
Lighting Controller。
Sensor Gateway。
Edge Device。
Instructor Console。
Studio Monitor。
Cloud。
これらの間では、絶えずDataとCommandが移動している。
したがってPhysical Runtimeには、
何を接続するのか。
どこへ接続するのか。
どのProtocolを使うのか。
どの通信を優先するのか。
Networkが切れたとき何を残すのか。
を定義するCommunication Architectureが必要になる。
本節では、
Network。
Controller。
Protocol。
を一つのLayerとして実装する。
目的は、すべてのDeviceを一つの巨大Networkへつなぐことではない。
異なる性質を持つ通信を分離しながら、45分に必要な情報だけを確実に通すことである。
基本構造は、
Intelligence
↓
Runtime
↓
Command
↓
Network
↓
Controller
↓
Protocol
↓
Device
↓
Physical Reality
である。
逆方向には、
Physical Device
↓
Telemetry
↓
Protocol
↓
Network
↓
Edge Runtime
↓
Observation
↓
Memory / Intelligence
が存在する。
つまりNetworkは単なる配線ではない。
Physical RealityとSoftware Realityを接続する神経系である。
1 通信を一種類にしない
FEELCYCLE Studioには、性質の異なる通信が存在する。
Audio Stream。
Lighting Command。
Sensor Observation。
Device Telemetry。
Human Interface。
Cloud Synchronization。
これらを同じPriorityで扱うべきではない。
まずCommunication Classを定義する。
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
)]
enum CommunicationClass {
Safety,
RuntimeControl,
RealtimeTelemetry,
HumanInterface,
MemorySync,
BackgroundAnalytics,
}
Priorityは、
Safety
>
Runtime Control
>
Realtime Telemetry
>
Human Interface
>
Memory Sync
>
Background Analytics
とする。
Cloud AnalyticsのUploadが増えたことでLighting Commandが遅れるArchitectureにはしない。
2 Studio Networkを分離する
一つのFlat Networkへすべてを置くと、Failure Domainが大きくなる。
概念的には、
Studio Network
│
├── Control Network
│ ├── Edge Runtime
│ ├── Lighting Controller
│ ├── Audio Controller
│ └── Sensor Gateway
│
├── Audio Network
│ ├── Playback
│ ├── DSP
│ └── Network Audio
│
├── Operations Network
│ ├── Instructor Console
│ └── Studio Monitor
│
└── Cloud Uplink
└── AWS
と分ける。
実際にはVLANなどを使って論理分離できる。
重要なのは、
Member向けWi-Fi。
社内業務Network。
Physical Control Network。
を無秩序に同じBroadcast Domainへ置かないことである。
3 Network Zone
Network ZoneをDomainとして定義する。
#[derive(
Debug,
Clone,
Copy,
)]
enum NetworkZone {
PhysicalControl,
Audio,
Operations,
Cloud,
}
各DeviceがどのZoneに属するかConfigurationへ持たせる。
#[derive(
Debug,
Clone,
serde::Deserialize,
)]
struct NetworkDeviceConfig {
device_id:
uuid::Uuid,
zone:
NetworkZone,
address:
String,
protocol:
String,
}
これによって、Physical RuntimeがNetwork Structureを明示的に理解できる。
4 有線を中心にする
Physical Controlの中心をWi-Fiだけへ依存させない。
Lighting。
Audio。
Edge Runtime。
主要Controller。
など、固定設備間の通信では有線Networkを基本にする。
Wirelessは、
Mobile。
補助Sensor。
一部Wearable。
などに利用する。
Fixed Critical Device
→ Wired
Personal / Mobile
→ Wireless when appropriate
とする。
Wireless Failure
≠
Core Physical Failure
へ近づける。
5 Controllerとは何か
RuntimeとPhysical Deviceの間にはControllerが存在する。
Lightingでは、
Lighting Console。
DMX / Art-Net Node。
Fixture Controller。
Audioでは、
Playback Engine。
Mixer。
DSP。
Audio Interface。
がControllerとして働く。
したがって、
Runtime
↓
Controller
↓
Physical Device
という一段を明示する。
AIが直接FixtureやSpeakerへ命令を送るのではない。
ControllerがDevice固有の責任を持つ。
6 Controller Identity
ControllerにもIdentityを持たせる。
#[derive(
Debug,
Clone,
)]
struct ControllerIdentity {
controller_id:
uuid::Uuid,
controller_type:
ControllerType,
studio_id:
uuid::Uuid,
}
#[derive(
Debug,
Clone,
)]
enum ControllerType {
Audio,
Lighting,
Sensor,
Network,
}
Databaseにも保存する。
CREATE TABLE physical_controllers (
controller_id UUID PRIMARY KEY,
studio_id UUID NOT NULL,
controller_type TEXT NOT NULL,
name TEXT NOT NULL,
protocol TEXT NOT NULL,
hardware_reference TEXT,
firmware_version TEXT,
active BOOLEAN NOT NULL
DEFAULT TRUE,
FOREIGN KEY (
studio_id
)
REFERENCES studios(
studio_id
)
);
これでSession時のPhysical Configurationを追跡できる。
7 Protocol Adapter
FEELCYCLE Runtimeは、各Protocolを直接Coreへ埋め込まない。
共通Adapterを定義する。
#[async_trait::async_trait]
trait ProtocolAdapter:
Send + Sync
{
async fn send(
&self,
command:
ProtocolCommand,
) -> Result<
ProtocolResult,
ProtocolError,
>;
async fn health(
&self,
) -> DeviceHealth;
}
Commandを定義する。
#[derive(
Debug,
Clone,
)]
struct ProtocolCommand {
command_id:
uuid::Uuid,
target_id:
uuid::Uuid,
payload:
Vec<u8>,
target_time_seconds:
Option<f64>,
}
これによってProtocol固有実装を交換できる。
8 Lighting Protocol
Lightingでは、
DMX512。
Art-Net。
sACN。
Vendor API。
などが候補になる。
概念構造は、
Lighting Intent
↓
Scene
↓
Lighting Adapter
↓
Protocol Adapter
├── DMX
├── Art-Net
└── sACN
↓
Controller
↓
Fixture
となる。
ProgramやAIはProtocolを知らない。
9 Audio Protocol
Audio側では用途によって、
Local Audio Driver。
MIDI。
OSC。
Network Audio。
Vendor Control API。
などが存在し得る。
ここでも、
Playback Command
と、
Device Protocol
を分離する。
Play Track
↓
Audio Adapter
↓
Playback Protocol
↓
Audio Engine
DSP Scene変更なら、
Audio Scene
↓
DSP Adapter
↓
Control Protocol
↓
DSP
となる。
一つのAudio Adapterの中でさらにSubsystemを分けてもよい。
10 OSC
OSCのようなMessage-oriented Protocolは、Semantic Controlとの相性がよい。
概念的なMessageは、
/feelcycle/lighting/scene peak
/feelcycle/audio/track/play track-123
/feelcycle/runtime/mode manual
のように設計できる。
ただし文字列だけを自由に送り合うのではなく、Message Schemaを固定する。
11 Protocol Version
Network MessageにもVersionを持たせる。
#[derive(
Debug,
Clone,
serde::Serialize,
serde::Deserialize,
)]
struct MessageEnvelope<T> {
schema_version:
u32,
message_id:
uuid::Uuid,
session_id:
Option<uuid::Uuid>,
sent_at:
chrono::DateTime<
chrono::Utc
>,
payload:
T,
}
これによってSoftware Update時に旧Messageと新Messageを区別できる。
Network ProtocolもVersioned Systemである。
12 CommandとTelemetryを分離する
同じChannelで無秩序に双方向Messageを流さない。
概念的には、
Command Channel
Runtime → Device
Telemetry Channel
Device → Runtime
Event Channel
Runtime ↔ Interfaces
Memory Channel
Edge → Cloud
と分ける。
これによって通信の意味を明確にできる。
13 CommandにはAcknowledgementを返す
Command送信を成功とみなさない。
#[derive(
Debug,
Clone,
)]
struct CommandAcknowledgement {
command_id:
uuid::Uuid,
accepted:
bool,
controller_received_at:
chrono::DateTime<
chrono::Utc
>,
message:
Option<String>,
}
ここからさらにApplied Resultへ進む。
Sent
↓
Acknowledged
↓
Applied
↓
Observed
の段階を保持する。
14 Timeout
Controllerが返事をしない場合に無限に待たない。
async fn send_with_timeout(
adapter:
&dyn ProtocolAdapter,
command:
ProtocolCommand,
timeout:
std::time::Duration,
) -> Result<
ProtocolResult,
ProtocolError,
> {
match tokio::time::timeout(
timeout,
adapter.send(command),
)
.await
{
Ok(result) =>
result,
Err(_) =>
Err(
ProtocolError::Timeout
),
}
}
Timeout後のActionはCommand Classによって変える。
15 Retry
すべてのCommandを同じようにRetryしてはいけない。
たとえば、
Telemetry Request
はRetryしてよい。
しかし、
Scene Advance
を無条件に再送すると二重実行の可能性がある。
そこでCommandにIdempotencyを持たせる。
#[derive(
Debug,
Clone,
Copy,
)]
enum RetryPolicy {
Never,
Idempotent,
Bounded(u8),
}
Commandの意味に応じて設定する。
16 Command Identity
重複実行を避けるためcommand_idをController側でも記憶できると強い。
command_id = X
First delivery
→ Execute
Second delivery
→ Already executed
→ Return previous result
これによってNetwork RetryとPhysical Duplicationを分離できる。
17 Network Time
AudioとLightingを同期するにはNetwork上のClockも重要である。
複数Edge / Controllerが独立Clockを持つ場合、
時刻同期。
Clock Drift。
を監視する。
#[derive(
Debug,
Clone,
)]
struct ClockHealth {
offset_ms:
f64,
drift_ms_per_minute:
f64,
synchronized:
bool,
}
Session ClockをPhysical Runtimeの基準として保持し、必要なControllerへTimestamp付きCommandを送る。
18 Clock Drift Alert
fn clock_state(
offset_ms: f64,
warning_ms: f64,
) -> DeviceHealth {
if offset_ms.abs()
<= warning_ms
{
DeviceHealth::Healthy
} else {
DeviceHealth::Degraded
}
}
Thresholdは実設備要件に応じて決める。
Network上で「同じ時刻」の意味を確認できることが重要である。
19 Quality of Service
可能なNetwork EquipmentではTraffic Priorityを設定できる。
考え方として、
Physical Control
High Priority
Audio Transport
High Priority
Telemetry
Medium Priority
Cloud Sync
Low Priority
とする。
AWSへのBackup UploadによってPhysical Control Packetが詰まることを避ける。
20 Bandwidth Budget
Studio NetworkでもBandwidthを無限とみなさない。
特に、
Raw Audio Upload。
Video。
High-frequency Sensor。
Cloud Backup。
は大量Trafficになり得る。
そのため、
Raw Sensor
↓
Edge Processing
↓
Feature
↓
Small Network Payload
を優先する。
これはPrivacyだけでなくNetwork Resilienceにも効く。
21 Network Health
EdgeからNetwork状態を監視する。
#[derive(
Debug,
Clone,
)]
struct NetworkHealth {
control_network:
DeviceHealth,
audio_network:
DeviceHealth,
operations_network:
DeviceHealth,
cloud_uplink:
DeviceHealth,
}
Cloud Uplinkだけが失われても、Control NetworkがHealthyならSessionを継続する。
22 Network Failureを分解する
「Network Down」という一つの状態にしない。
例えば、
Cloud Uplink Down
→ Session continues
→ Memory buffered locally
Operations Network Down
→ Studio Monitor unavailable
→ Runtime continues
Lighting Network Down
→ Lighting fallback
Audio Network Down
→ Audio fallback / manual
と影響範囲を分ける。
これがNetwork Segmentationの大きな価値である。
23 Failure Domain
一つの障害がSystem全体へ波及しないようにする。
Cloud Failure
≠
Audio Failure
Lighting Failure
≠
Runtime Failure
Member Wi-Fi Failure
≠
Studio Control Failure
をArchitectureで実現する。
24 Controller Failure
Controllerが落ちた場合はAdapterがHealthをUnavailableへする。
async fn controller_health_loop(
adapter:
&dyn ProtocolAdapter,
) {
loop {
let health =
adapter.health().await;
publish_controller_health(
health
)
.await;
tokio::time::sleep(
std::time::Duration::
from_secs(1)
)
.await;
}
}
実際のPoll IntervalはDevice特性に合わせる。
25 Controller Fallback
Lighting ControllerがFailureしたら、
Secondary Controller。
Static Safe Scene。
Manual Console。
などへ移る。
Audio Controllerも同様である。
Primary Controller
↓ failure
Secondary / Local
↓ failure
Manual
↓
Safe State
Physical Layerでは「代替経路」の存在が重要になる。
26 Human Control Pathを独立させる
AI / Edge Runtimeが停止したときにも、人間が設備を操作できる経路を残す。
Automation Path
Edge → Controller → Device
Manual Path
Human Console → Controller → Device
二つを可能な範囲で独立させる。
Automation Failure
≠
Loss of Human Control
である。
27 Network Security
Physical Control NetworkはInternetへ無制限に開かない。
最低限、
Firewall。
Network Segmentation。
Device Authentication。
Encrypted Management Channel。
Remote Access制限。
を持つ。
ControllerにDefault Passwordを残さない。
不要なServiceを無効化する。
Firmwareを管理する。
Physical RuntimeもCybersecurityの対象である。
28 Remote Access
保守のためRemote Accessが必要でも、常時無制限Accessにしない。
概念構造は、
Authorized Operator
↓
Authentication
↓
Controlled Remote Access
↓
Audit
↓
Edge / Controller
とする。
誰がいつどのStudioへ接続したかをAuditできるようにする。
29 CloudからのCommand
CloudからStudioへ直接Realtime Physical Commandを送る設計は最小化する。
Cloudは、
Program配布。
Configuration配布。
Model配布。
Operation Request。
を行える。
しかし実行前にEdgeでValidationする。
Cloud Request
↓
Authenticated
↓
Edge
↓
Current Session Check
↓
Permission / Policy
↓
Safety Validation
↓
Apply or Reject
Cloud側がPhysical Realityの最終Authorityにはならない。
30 Configuration Distribution
Studio ConfigurationをCloudから配布する場合もVersionを持つ。
#[derive(
Debug,
Clone,
serde::Deserialize,
)]
struct StudioNetworkConfiguration {
configuration_version:
u64,
studio_id:
uuid::Uuid,
devices:
Vec<
NetworkDeviceConfig
>,
}
Edge側では現在Versionと比較する。
31 Configuration Activation
取得したConfigurationを即座に本番適用しない。
Download
↓
Signature / Integrity Check
↓
Schema Validation
↓
Device Validation
↓
Staging
↓
Activation
Session中のNetwork Configuration変更は原則避ける。
32 Configuration Rollback
struct ConfigurationState {
active_version:
u64,
previous_version:
Option<u64>,
}
Activation後にPreflightが失敗すれば前Versionへ戻す。
Physical InfrastructureにもRollbackが必要である。
33 Protocol Translation
一つのSemantic Commandを、Studioごとに異なるProtocolへ翻訳できる。
enum PhysicalIntent {
Lighting(
LightingIntent
),
Audio(
AudioAction
),
}
Translation Layerを置く。
fn route_intent(
intent:
PhysicalIntent,
) -> ControllerRoute {
match intent {
PhysicalIntent::Lighting(_) =>
ControllerRoute::Lighting,
PhysicalIntent::Audio(_) =>
ControllerRoute::Audio,
}
}
ここからStudio Configurationに従ってAdapterを選択する。
34 Protocol Registry
struct ProtocolRegistry {
adapters:
std::collections::HashMap<
uuid::Uuid,
std::sync::Arc<
dyn ProtocolAdapter
>,
>,
}
Controller IDから正しいAdapterを取得する。
impl ProtocolRegistry {
fn adapter(
&self,
controller_id:
&uuid::Uuid,
) -> Option<
std::sync::Arc<
dyn ProtocolAdapter
>
> {
self.adapters
.get(controller_id)
.cloned()
}
}
これによりRuntime CoreからProtocol固有実装を分離できる。
35 Protocol Error
#[derive(
Debug,
thiserror::Error,
)]
enum ProtocolError {
#[error(
"timeout"
)]
Timeout,
#[error(
"connection lost"
)]
ConnectionLost,
#[error(
"invalid response"
)]
InvalidResponse,
#[error(
"unsupported command"
)]
UnsupportedCommand,
}
Error Typeを明示することで、Fallback判断を分けられる。
36 Event Bus
Studio内部で複数Serviceを接続する場合、Internal Event Busを利用できる。
Runtime Core
↓
Event Bus
├── Audio Service
├── Lighting Service
├── Sensor Service
├── Interface Gateway
└── Memory Service
ただしv0.1では過剰なDistributed Systemにしない。
一台のEdge Device内なら、Tokio ChannelなどのIn-process Communicationで十分な場合がある。
37 In-process Message
#[derive(
Debug,
Clone,
)]
enum EdgeMessage {
Runtime(
RuntimeEvent
),
Audio(
AudioCommand
),
Lighting(
LightingCommand
),
Sensor(
SensorObservation
),
Health(
DeviceHealthEvent
),
}
ChannelでService間を接続する。
let (
tx,
mut rx
) =
tokio::sync::mpsc::
channel::<EdgeMessage>(
1024
);
必要になるまでExternal Brokerを増やさない。
38 Backpressure
Messageが処理能力を超えて増えた場合を考える。
特にSensor Eventが大量に来た場合、重要なControl Commandを押し流してはいけない。
そこでQueueを分ける。
Critical Queue
→ Safety / Control
Realtime Queue
→ Audio / Lighting / Telemetry
Background Queue
→ Cloud / Analytics
とする。
39 Priority Channel
概念的には、
struct EdgeChannels {
critical:
tokio::sync::mpsc::
Sender<EdgeMessage>,
realtime:
tokio::sync::mpsc::
Sender<EdgeMessage>,
background:
tokio::sync::mpsc::
Sender<EdgeMessage>,
}
のように分けられる。
一つの巨大Queueにしない。
40 Sensor Flood
Sensorが異常になって毎ミリ秒大量Eventを送る場合、Runtimeを保護する。
Rate Limitを設ける。
struct SensorRateLimit {
max_events_per_second:
u32,
}
Raw Eventを全部処理しない。
最新StateやWindow Summaryへ圧縮する。
41 StateとEventを分ける
Network上で、
State。
Event。
を区別する。
Stateは、
「現在LightingはPeak」
である。
Eventは、
「120秒でPeakへ変化した」
である。
#[derive(Debug, Clone)]
struct StateMessage {
resource_id:
String,
version:
u64,
value:
serde_json::Value,
}
#[derive(Debug, Clone)]
struct EventMessage {
event_id:
uuid::Uuid,
event_type:
String,
occurred_at:
chrono::DateTime<
chrono::Utc
>,
payload:
serde_json::Value,
}
現在状態の同期とHistorical Memoryを混同しない。
42 Authoritative State
Physical RuntimeのAuthoritative StateはEdge Runtimeへ置く。
TypeScript Studio MonitorやCloud DashboardはRepresentationを受け取る。
Edge Authoritative State
↓
State Update
↓
Web / Cloud Representation
Webから古いStateを送り返してRuntimeを上書きしない。
Action Requestとして送る。
43 Sequence Number
Realtime State MessageにはSequence Numberを持たせる。
#[derive(
Debug,
Clone,
serde::Serialize,
)]
struct RuntimeStateMessage {
session_id:
uuid::Uuid,
sequence:
u64,
state:
serde_json::Value,
}
Frontendは古いMessageを無視できる。
Network遅延によってStateが逆順になるのを防ぐ。
44 Studio Monitor通信
Studio MonitorとはWebSocketなどでRealtime Stateを共有できる。
Edge
↓
Operations Gateway
↓
WebSocket
↓
Studio Monitor
ただしStudio Monitorが切れてもRuntimeは継続する。
Interface Connection
≠
Execution Connection
である。
45 Instructor Console通信
Instructor Consoleではさらに小さなMessageだけを送る。
Current Program。
Current Section。
System Mode。
AI Suggestion。
重要Alert。
である。
Device Telemetryの全量を送らない。
Machine ComplexityをHuman Meaningへ圧縮する。
46 Cloud Synchronization
Cloudへ送るDataはBackground Priorityにする。
Runtime Events
↓
Local Buffer
↓
Cloud Sync
Network Congestion時にはCloud Syncを遅らせてもよい。
Physical Controlを優先する。
47 Offline State
Cloudが切断されたら、
Physical Control Network
Healthy
Cloud Uplink
Unavailable
というStateになる。
EdgeはLocal Operationを続ける。
Studio Monitorには、
「Cloud同期停止・Session継続中」
と表示する。
Failureの意味を正しく伝える。
48 Network Reconnect
Cloud復旧時には、一気に大量UploadしてControl Networkを圧迫しない。
Rate Limitを設けて徐々にSyncする。
struct SyncPolicy {
max_events_per_batch:
usize,
pause_between_batches:
std::time::Duration,
}
Current Realityを過去DataのUploadより優先する。
49 Controller Preflight
Session開始前にはControllerを検証する。
#[derive(Debug)]
struct ControllerPreflight {
audio_controller:
bool,
lighting_controller:
bool,
sensor_gateway:
bool,
manual_control:
bool,
clock_sync:
bool,
}
必要ControllerがReadyか確認する。
50 Network Preflight
さらに、
Control Network。
Audio Network。
Operations Network。
Cloud Uplink。
を確認する。
#[derive(Debug)]
struct NetworkPreflight {
control_ready:
bool,
audio_ready:
bool,
operations_ready:
bool,
cloud_ready:
bool,
}
cloud_ready = falseでもSession開始可能な設計にする。
51 Preflight判定
impl NetworkPreflight {
fn physical_runtime_ready(
&self,
) -> bool {
self.control_ready
&& self.audio_ready
}
}
CloudやOperations Interfaceは別評価にする。
CoreとOptionalを分離する。
52 Protocol Audit
Physical CommandをAuditする。
CREATE TABLE protocol_command_events (
protocol_event_id UUID PRIMARY KEY
DEFAULT gen_random_uuid(),
session_id UUID,
command_id UUID NOT NULL,
controller_id UUID NOT NULL,
protocol TEXT NOT NULL,
command_type TEXT NOT NULL,
result TEXT NOT NULL,
latency_ms DOUBLE PRECISION,
occurred_at TIMESTAMPTZ NOT NULL
DEFAULT NOW()
);
ただしRaw Packetをすべて永久保存する必要はない。
意味のあるCommand Resultを残す。
53 Network Event Memory
CREATE TABLE network_runtime_events (
network_event_id UUID PRIMARY KEY
DEFAULT gen_random_uuid(),
session_id UUID,
zone TEXT NOT NULL,
event_type TEXT NOT NULL,
latency_ms DOUBLE PRECISION,
packet_loss_ratio
DOUBLE PRECISION,
result TEXT,
occurred_at TIMESTAMPTZ NOT NULL
DEFAULT NOW()
);
Session終了後にSummaryへ圧縮する。
54 Network Session Summary
CREATE TABLE network_session_summaries (
session_id UUID PRIMARY KEY,
control_availability
DOUBLE PRECISION,
audio_network_availability
DOUBLE PRECISION,
cloud_availability
DOUBLE PRECISION,
max_control_latency_ms
DOUBLE PRECISION,
reconnect_count INTEGER NOT NULL
DEFAULT 0,
generated_at TIMESTAMPTZ NOT NULL
DEFAULT NOW(),
FOREIGN KEY (
session_id
)
REFERENCES sessions(
session_id
)
);
Company DashboardではこのようなSummaryを使う。
55 Network Learning
複数Sessionを分析すると、
特定Studioで毎晩Latencyが増える。
特定Controller FirmwareでDisconnectが多い。
Cloud Sync後にNetwork Loadが上がる。
などのPatternが分かる。
Python IntelligenceはPhysical Networkについても学習できる。
ただしAIがNetwork Routingを無制限に自動変更するのではない。
まずInsightとしてOperationへ返す。
56 Self-healingの境界
Network異常を検出したら自動RestartできるDeviceもある。
しかし何でも自動再起動すればよいわけではない。
Observe
↓
Classify
↓
Approved Recovery Action
↓
Execute
↓
Verify
とする。
許可されたRecoveryだけをAutomationする。
57 Recovery Policy
#[derive(
Debug,
Clone,
)]
enum RecoveryAction {
Reconnect,
RestartAdapter,
SwitchFallback,
RequireHuman,
}
Network Eventに応じてPolicyで選ぶ。
fn recovery_for(
error:
&ProtocolError,
) -> RecoveryAction {
match error {
ProtocolError::Timeout =>
RecoveryAction::Reconnect,
ProtocolError::ConnectionLost =>
RecoveryAction::
SwitchFallback,
ProtocolError::InvalidResponse =>
RecoveryAction::
RequireHuman,
ProtocolError::UnsupportedCommand =>
RecoveryAction::
RequireHuman,
}
}
58 人間へのEscalation
Automationで解決できない場合はStudio Operatorへ返す。
Alertには、
何が壊れたか。
Sessionは継続可能か。
現在のFallback。
必要なAction。
を表示する。
単なるError Codeだけを人間へ渡さない。
59 Network・Controller・Protocolの統合
ここまでをまとめる。
Studio Network
Python Intelligence
↓
Rust Runtime
↓
Semantic Intent
↓
Safety / Policy
↓
Controller Routing
↓
Protocol Adapter
↓
┌────────┼─────────┐
↓ ↓ ↓
Audio Lighting Sensor
↓ ↓ ↑
Sound Light Observation
└────────┼─────────┘
↓
Reality
↓
Device Telemetry
↓
Edge Runtime
↓
Local Memory / Cloud
通信系はRealityの外部ではない。
Physical Runtimeの成立条件である。
60 Protocolを目的化しない
DMX。
Art-Net。
sACN。
OSC。
MIDI。
WebSocket。
HTTP。
これらは目的ではない。
FEELCYCLEが必要とするMeaningをDeviceへ届けるためのTranslation Methodである。
したがって、
Best Protocol
を一つ決めるのではなく、
適切なLayerに適切なProtocol
を置く。
Music StreamingとLighting Cueに同じProtocolを強制する必要はない。
61 Minimum Complete Communication
FEELCYCLE AIに必要な最小Communicationは、
RuntimeからAudioへCommandが届く。
RuntimeからLightingへCommandが届く。
SensorからObservationが戻る。
Device Healthが戻る。
Human InterfaceへCurrent Stateが届く。
CloudへMemoryが同期される。
Cloud断でもLocal Realityが継続する。
ということである。
それ以上のComplexityは必要になってから追加する。
62 Network・Controller・Protocol v0.1の完成条件
v0.1では最低限、次を満たす。
Physical Control Networkを他Networkから分離できる。
有線を主要Physical Controlの中心にできる。
ControllerへIdentityを持たせられる。
Protocol AdapterでHardware固有通信を分離できる。
CommandとTelemetryを分離できる。
Message SchemaをVersion管理できる。
Command IDによって重複を抑制できる。
AcknowledgementとApplied Resultを区別できる。
Clock Syncを観測できる。
Critical TrafficをBackground Syncより優先できる。
Cloud Failure時にもPhysical Controlを継続できる。
Controller Failure時にFallbackできる。
Human Manual Control Pathを残せる。
Network EventをSession Memoryへ戻せる。
これによってAudio、Lighting、Sensor、Edgeは、個別の機器ではなく、一つのCommunication Architectureの上で動くようになる。
63 Studioは一つのNetworked Physical Systemになる
ここまでPhysical Runtimeには、
音。
光。
Sensor。
Edge。
Network。
Controller。
Protocol。
が揃った。
それぞれは異なるTechnologyである。
しかしFEELCYCLEの45分では、その違いを人間が意識し続ける必要はない。
Instructorが見るのは、
今の45分。
Memberが経験するのは、
音・身体・暗闇・他者・空間。
Studio Operatorが見るのは、
Systemが正常か。
である。
Machine内部では複雑に分離する。
Human Experienceでは一つへ統合する。
Machine Side
Audio
Lighting
Sensor
Network
Controller
Protocol
↓
Physical Runtime
↓
Human Side
One Studio
One Session
One 45 Minutes
これがPhysical RuntimeのArchitectureである。
64 次はStudio全体を統合する
ここまで各Physical Componentを個別に実装してきた。
しかし、本番環境では、
AudioだけをDeployする。
LightingだけをDeployする。
SensorだけをDeployする。
のではない。
一つのStudioへ全部を入れる。
ProgramをLoadする。
Edgeを起動する。
DeviceをPreflightする。
Instructor Consoleを接続する。
Memberが入る。
Sessionを開始する。
45分を実行する。
終了後にMemoryへ戻す。
次節では、このEnd-to-End Integrationを実装する。
Studio Integration。
SoftwareとHardwareを一つのStudioへ統合し、
Program
↓
Preflight
↓
Session
↓
Physical Reality
↓
Verification
↓
Memory
を一周させる。
ここで初めて、FEELCYCLE AIは「機材が動くSystem」から「45分が実際に成立するSystem」へ進む。
第6節 Studio Integration
ここまで第6章では、Physical Runtimeを構成する主要な要素を個別に実装してきた。
Audio System。
Lighting System。
Microphone・Sensor・Edge Device。
Network・Controller・Protocol。
しかし、実際のFEELCYCLEでは、これらが別々に動いても45分は成立しない。
一つのStudio。
一つのProgram。
一人のInstructor。
複数のMember。
一つのSession Clock。
その中で、音、光、身体、空間、AI、Hardware、人間が同時に動く必要がある。
本節では、ここまで構築したすべてのPhysical Componentを一つのStudioへ統合する。
Studio Integrationである。
Studio Integrationの目的は、機材を接続することではない。
Programという設計を、45分のPhysical Realityとして最初から最後まで安全に成立させ、その結果をMemoryへ戻すことである。
最小構造は、
Program
↓
Studio Configuration
↓
Preflight
↓
Session Start
↓
Physical Runtime
↓
Human + AI + Hardware
↓
Session End
↓
Verification
↓
Memory
となる。
ここまで一周して初めて、一つのStudioがFEELCYCLE AIの実行環境になる。
1 Studioを一つのExecution Unitとして定義する
StudioはLocationではない。
一つのPhysical Runtime Unitである。
#[derive(
Debug,
Clone,
)]
struct StudioRuntimeIdentity {
studio_id:
uuid::Uuid,
edge_device_id:
uuid::Uuid,
configuration_version:
u64,
}
Studioごとに、
Edge Device。
Audio Configuration。
Lighting Configuration。
Sensor Configuration。
Network Configuration。
Fallback。
Manual Control。
を持つ。
概念的には、
Studio
│
├── Edge Runtime
├── Audio System
├── Lighting System
├── Sensor System
├── Network
├── Instructor Console
├── Manual Control
└── Safety System
となる。
これを一つのRuntimeとして扱う。
2 Studio Configuration
Studio Integrationの中心にConfigurationを置く。
#[derive(
Debug,
Clone,
serde::Deserialize,
)]
struct StudioConfiguration {
studio_id:
uuid::Uuid,
version:
u64,
audio:
AudioStudioConfig,
lighting:
LightingStudioConfig,
sensors:
SensorStudioConfig,
network:
NetworkStudioConfig,
safety:
StudioSafetyConfig,
}
このConfigurationによって、同じProgramを異なるStudioへTranslationできる。
Programは、
Peak。
Build。
Track A。
Movement B。
という意味を持つ。
Studio Configurationが、それを具体的なDeviceへ変換する。
3 ConfigurationをVersion化する
Studio設備は変化する。
Speakerを交換する。
Lighting Controllerを更新する。
Firmwareを更新する。
Sensorを追加する。
Network構成を変更する。
したがってConfigurationを上書きしない。
CREATE TABLE studio_runtime_configurations (
configuration_id UUID PRIMARY KEY
DEFAULT gen_random_uuid(),
studio_id UUID NOT NULL,
version_number INTEGER NOT NULL,
configuration JSONB NOT NULL,
status TEXT NOT NULL
DEFAULT 'draft',
created_at TIMESTAMPTZ NOT NULL
DEFAULT NOW(),
activated_at TIMESTAMPTZ,
FOREIGN KEY (
studio_id
)
REFERENCES studios(
studio_id
),
UNIQUE (
studio_id,
version_number
)
);
Sessionには、実際に使用したConfiguration Versionを記録する。
これによって、
Program Version。
AI Model Version。
Studio Configuration Version。
を一組として残せる。
4 Session Execution Context
Session開始前に、実行条件を一つのContextへ固定する。
#[derive(
Debug,
Clone,
)]
struct SessionExecutionContext {
session_id:
uuid::Uuid,
program_version_id:
uuid::Uuid,
studio_id:
uuid::Uuid,
instructor_id:
uuid::Uuid,
studio_configuration_version:
u64,
ai_model_version:
Option<String>,
}
これが一回の45分のExecution Identityになる。
途中でCloud側のCurrent Program Versionが変わっても、このSessionには影響させない。
Running RealityをCurrent Configurationで上書きしない。
5 Studio Boot
Session以前にStudio Runtimeそのものを正常に起動する必要がある。
Boot Sequenceは、
Edge Boot
↓
Configuration Load
↓
Device Initialization
↓
Network Check
↓
Safe State
↓
Cloud Sync
↓
Idle Ready
とする。
RustではState Machineとして扱える。
#[derive(
Debug,
Clone,
Copy,
)]
enum StudioBootState {
Starting,
Loading,
Initializing,
Verifying,
Ready,
Degraded,
Failed,
}
ReadyになるまではAutomatic Session Startを許可しない。
6 Idle State
StudioはSessionを実行していない時間にもRuntimeとして存在する。
#[derive(
Debug,
Clone,
Copy,
)]
enum StudioOperationalState {
Offline,
Booting,
Idle,
Preparing,
Ready,
Running,
Degraded,
Manual,
Safe,
Closing,
}
このStateをStudio Monitorへ返す。
「Sessionがない」
と、
「Studio Runtimeが停止している」
を分離する。
7 Session Preparation
Session開始予定が近づいたらPreparationへ入る。
Scheduled Session
↓
Program Download / Verify
↓
Studio Configuration Verify
↓
Asset Prepare
↓
Preflight
↓
Ready
まずProgram Versionを取得する。
struct PreparedProgram {
program_version_id:
uuid::Uuid,
duration_seconds:
f64,
tracks:
Vec<PreparedTrack>,
lighting:
Vec<LightingCommand>,
movements:
Vec<MovementBlock>,
}
Session開始前に必要なDataをLocalへ準備する。
Cloud ConnectionがSession開始直前に失われても実行できるようにする。
8 Asset Validation
Audio Asset。
Lighting Scene。
Configuration。
すべてが存在するか確認する。
#[derive(Debug)]
struct AssetValidation {
audio_assets_ready:
bool,
lighting_scenes_ready:
bool,
program_valid:
bool,
}
impl AssetValidation {
fn ready(
&self,
) -> bool {
self.audio_assets_ready
&& self.lighting_scenes_ready
&& self.program_valid
}
}
必要なAssetがない状態でSessionを開始しない。
9 Unified Preflight
ここまで各Subsystemで作ったPreflightを一つへ統合する。
#[derive(Debug)]
struct StudioPreflight {
edge:
EdgePreflight,
audio:
AudioPreflightReport,
lighting:
LightingPreflight,
sensor:
SensorEdgePreflight,
network:
NetworkPreflight,
controller:
ControllerPreflight,
assets:
AssetValidation,
}
これがStudio Integrationの重要な境界になる。
10 CriticalとOptionalを分離する
すべてが100%正常でなければ開始できない設計にはしない。
ComponentをCritical / Optionalに分類する。
たとえば概念上、
Critical
────────────
Edge Runtime
Audio Core
Control Network
Manual Control
Safety
Degradable
────────────
Lighting Automation
Measurement Sensor
Cloud Connection
AI Intelligence
Company Monitoring
とする。
具体的な分類は実設備と安全要件に合わせて確定する。
11 Preflight Decision
#[derive(
Debug,
Clone,
Copy,
)]
enum PreflightDecision {
Ready,
ReadyDegraded,
RequireHumanCheck,
CannotStart,
}
判定する。
fn evaluate_preflight(
report:
&StudioPreflight,
) -> PreflightDecision {
if !report
.edge
.runtime_ready
|| !report
.audio
.playback_ready
|| !report
.network
.control_ready
{
return
PreflightDecision::
CannotStart;
}
if !report
.lighting
.controller_ready
|| !report
.sensor
.audio_measurement_ready
|| !report
.network
.cloud_ready
{
return
PreflightDecision::
ReadyDegraded;
}
PreflightDecision::Ready
}
AIが自動的に開始判断するのではなく、必要に応じてStudio OperatorやInstructorへ判断を返す。
12 PreflightをHuman Meaningへ変換する
Studio MonitorではTechnical Detailを表示できる。
Instructor Consoleでは圧縮する。
たとえば、
Studio Ready
Lighting sensor unavailable.
Session can continue.
程度でよい。
人間が判断するために必要な意味だけを返す。
13 Session Ready State
Preflight完了後、
struct SessionReadyState {
session_id:
uuid::Uuid,
decision:
PreflightDecision,
prepared_at:
chrono::DateTime<
chrono::Utc
>,
}
を作る。
このStateが成立して初めてSession Startを許可する。
14 Session Start Authority
Session Startは重要なState Transitionである。
Automatic Scheduleだけで勝手に開始するのではなく、運用設計に応じてHuman Startを要求できる。
Scheduled
↓
Prepared
↓
Human Ready
↓
Start
InstructorまたはOperatorからStart Intentを受け取る。
struct StartSessionIntent {
session_id:
uuid::Uuid,
actor_id:
uuid::Uuid,
requested_at:
chrono::DateTime<
chrono::Utc
>,
}
Backend / EdgeでAuthorityを確認する。
15 Session Start Transaction
Local Runtimeでは、
Session Clock。
Program State。
Audio。
Lighting。
Memory。
を一貫して開始する。
概念的には、
Validate
↓
Create Runtime State
↓
Start Session Clock
↓
Start Audio
↓
Apply Initial Lighting
↓
Record session_start
↓
Running
となる。
16 Studio Runtime State
統合Stateを定義する。
#[derive(
Debug,
Clone,
)]
struct StudioRuntimeState {
operational_state:
StudioOperationalState,
session_id:
Option<uuid::Uuid>,
session_seconds:
f64,
program_state:
ProgramRuntimeState,
audio_state:
AudioPlaybackState,
lighting_state:
LightingRuntimeState,
physical_health:
PhysicalHealth,
control_mode:
PhysicalControlMode,
cloud_connected:
bool,
}
これがStudio側のAuthoritative Runtime Stateになる。
17 One Clock
Studio Integrationで特に重要なのは、一つのSession Clockを共有することである。
Audio。
Lighting。
Program。
Runtime Event。
Sensor Timestamp。
すべてをこのClockへ対応させる。
Session Clock
│
┌─────────────┼─────────────┐
↓ ↓ ↓
Audio Lighting Program
↓ ↓ ↓
Physical Physical Movement
│ │ │
└─────────────┼─────────────┘
↓
Reality
各Subsystemが独立した「現在時刻」を持って勝手に動かない。
18 Runtime Orchestrator
Subsystemを統合するOrchestratorを作る。
struct StudioOrchestrator {
audio:
std::sync::Arc<
dyn AudioAdapter
>,
lighting:
std::sync::Arc<
dyn LightingAdapter
>,
runtime:
RuntimeEngine,
sensors:
SensorGateway,
memory:
LocalMemory,
safety:
SafetyManager,
}
Orchestratorは全処理を一つのThreadで直列化するものではない。
Subsystemを一つのState Machineとして調整する。
19 Main Loop
概念的なMain Loopは、
async fn run_session(
orchestrator:
&mut StudioOrchestrator,
) -> Result<
(),
StudioRuntimeError,
> {
loop {
let event =
orchestrator
.runtime
.next_event()
.await?;
orchestrator
.handle_event(
event
)
.await?;
if orchestrator
.runtime
.session_finished()
{
break;
}
}
Ok(())
}
となる。
実際にはAudio、Lighting、Sensorを並列で動かし、Eventによって同期する。
20 Event Routing
Runtime Eventを適切なSubsystemへ送る。
async fn route_event(
event:
RuntimeEvent,
audio:
&dyn AudioAdapter,
lighting:
&dyn LightingAdapter,
) -> Result<
(),
StudioRuntimeError,
> {
match event.event_type {
EventType::TrackStart => {
let command =
audio_command_from(
&event
)?;
audio
.execute(
&command
)
.await?;
}
EventType::LightingCue => {
let command =
lighting_command_from(
&event
)?;
lighting
.apply(
&command
)
.await?;
}
_ => {}
}
Ok(())
}
一つのProgram Timelineから複数Physical Outputが生成される。
21 Human Eventも同じRuntimeへ入れる
Physical Runtimeで起きるEventはProgramだけではない。
InstructorのManual Override。
Studio OperatorのFallback。
Human Approval。
もある。
enum StudioEvent {
Program(
RuntimeEvent
),
Human(
HumanRuntimeEvent
),
Sensor(
SensorObservation
),
Device(
DeviceHealthEvent
),
}
ProgramとHumanとSensorを一つのEvent Architecture上で扱う。
22 AuthorityはEventごとに異なる
Program Eventは自動実行可能。
AI SuggestionはHuman Approvalが必要な場合がある。
Safety Eventは即時Safe Stateへ移行する。
Manual EventはHuman Authorityを優先する。
したがって、
Event
↓
Classify
↓
Authority
↓
Safety
↓
Execute
の順序で処理する。
23 Runtime Mode
Session中のModeを統合する。
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
)]
enum IntegratedRuntimeMode {
Normal,
Assisted,
Degraded,
Manual,
Safe,
Stopping,
Ended,
}
このModeによってAutomationの範囲が変わる。
24 Normal Mode
Normalでは、
Program Timeline。
Approved Automation。
AI Suggestion。
Sensor Observation。
が通常どおり動く。
しかしAI Suggestionは必要なAuthorityを通す。
25 Degraded Mode
一部Subsystemが失われた場合、
AI unavailable
→ Program continues
Sensor unavailable
→ Sensor-dependent function stops
Lighting automation unavailable
→ Safe / Manual lighting
Cloud unavailable
→ Local memory buffers
というようにCapabilitiesを落とす。
Degraded
≠
Failed
である。
26 Capability Model
#[derive(
Debug,
Clone,
)]
struct StudioCapabilities {
audio:
bool,
automated_lighting:
bool,
sensor_observation:
bool,
ai_assistance:
bool,
cloud_sync:
bool,
manual_control:
bool,
}
Runtime Modeだけでなく、何が利用可能かを明示する。
27 Manual Mode
HumanがManualを選択すれば、Automation Authorityを移す。
Automatic Audio Control
→ Depending on operation policy
Automatic Lighting
→ OFF
AI Physical Execution
→ OFF
Human Control
→ ON
Runtimeは観測とMemoryを続けられる。
Manual
≠
System Blind
である。
28 Safe Mode
Critical Failure時はSafe Modeへ移る。
async fn enter_safe_mode(
orchestrator:
&StudioOrchestrator,
) {
let _ =
orchestrator
.lighting
.safe_scene()
.await;
orchestrator
.safety
.disable_automation()
.await;
}
Audioの安全な扱いは設備・運用条件に応じたSafe Policyを適用する。
Safetyを一つのGeneric Actionに固定しない。
29 Failure Isolation
Studio Integrationの大きな目的は、一つのFailureを全体へ広げないことである。
Measurement Sensor Failure
≠
Audio Failure
Cloud Failure
≠
Lighting Failure
Company Dashboard Failure
≠
Studio Runtime Failure
AI Failure
≠
Program Failure
Subsystem Boundaryを守る。
30 Dependency Graph
ただし本当に依存しているものは明確にする。
例えば、
Audio Playback
depends on
Audio Asset
+
Playback Engine
+
Audio Output Path
Lighting Automation
depends on
Runtime
+
Control Network
+
Lighting Controller
Cloud Memory
depends on
Cloud Uplink
but
Session Runtime does not
このDependency Graphを設計時に明示する。
31 Studio Integration Test Environment
Production Studioへいきなり統合しない。
最低でも、
Simulation。
Bench Test。
Empty Studio Test。
Controlled Session。
Production。
の段階を踏む。
Software Simulation
↓
Hardware Bench
↓
Empty Studio
↓
Staff-only Test
↓
Controlled Operation
↓
Production
Physical IntegrationではRealityによる検証が不可欠である。
32 Hardware-in-the-Loop Test
Rust Runtimeに実際のControllerを接続する。
Runtime
↓
Real Controller
↓
Test Fixture / Audio Path
↓
Measurement
↓
Verification
これによってSimulationでは見えないDevice LatencyやProtocol Behaviorを確認する。
33 Empty Studio Test
実StudioでMemberなしの45分を一周させる。
確認するのは、
Audio。
Lighting。
Transition。
Network。
Sensor。
Fallback。
Manual Override。
Memory。
である。
Program全体をEnd-to-Endで流す。
34 Golden Session
v0.1では基準となるTest Program / Sessionを一つ作るとよい。
例えば、
Golden Session v0.1
Duration:
45 minutes
Includes:
Audio transitions
Lighting transitions
Sensor observations
AI suggestion
Manual override
Fallback simulation
Cloud disconnect
Cloud reconnect
これをReleaseごとに実行する。
一つのE2E Referenceになる。
35 Integration Test Event
Test中に意図的にFailureを入れる。
例えば、
10分:Cloud Disconnect。
15分:Measurement Sensor停止。
20分:Lighting Controller一時切断。
30分:Manual Override。
35分:Automation Restore。
というようにする。
Systemが安全にState Transitionできるか確認する。
36 Fault Injection
概念的なTest Eventを定義する。
enum FaultInjection {
CloudDisconnect,
SensorFailure,
LightingDisconnect,
AudioAdapterFailure,
EdgeServiceRestart,
}
ProductionではなくTest Environmentで使う。
Failureを経験していないSystemを、Failureに強いとは評価できない。
37 RestoreもTestする
Failure後に、
正常へ戻る。
ManualからAutomaticへ戻る。
Cloud Syncを再開する。
Local EventをReconcileする。
ことも確認する。
Fail Safeだけでなく、
Recover Safe
が必要である。
38 Human Handoff
AutomationからManualへの移行と、ManualからAutomationへの復帰を明確にする。
Automation
↓
Handoff Request
↓
Human Acknowledgement
↓
Manual
Manual
↓
System Ready
↓
Human Approval
↓
Automation
勝手にAutomationへ復帰しない。
人間がManualで操作している最中にAIが突然Controlを奪わない。
39 Instructor Console Integration
Instructor Consoleへ必要な情報を送る。
Current Track
Current Section
Session Time
Current Mode
Next Major Transition
AI Suggestion
Critical Alert
これ以上のTechnical Detailは極力出さない。
40 Studio Monitor Integration
Studio Monitorでは、
Edge。
Audio。
Lighting。
Sensor。
Network。
Cloud。
Device。
を詳細に表示できる。
さらに、
Current Runtime Mode。
Fallback。
Queue Depth。
Latency。
を確認する。
Operator Observer Positionを維持する。
41 Company Dashboard Integration
Company DashboardへはReal-Time ControlではなくAggregationを送る。
Studio
Normal / Degraded
Runtime Availability
99.x%
Fallback Count
Device Health Summary
Cloud Sync State
会社全体を見るためのRepresentationへ圧縮する。
42 Swift Mobile Integration
Member AppはPhysical Runtimeを直接操作しない。
Instructor AppもPrimary Live Controlにはしない。
Mobile側では、
Session Ready。
Studio Information。
Preparation。
Post-session Review。
を中心にする。
Physical RuntimeのAuthorityをiPhoneへ依存させない。
43 Member ExperienceをTechnologyから守る
Studio Integrationが成功しているとき、Memberは大量のTechnologyを意識しない。
Edge Computer。
Rust。
AWS。
SQS。
Sensor。
Protocol。
AI Model。
これらが存在していても、MemberがExperienceするのは、
音楽。
身体。
暗闇。
光。
Instructor。
他者。
45分。
である。
System Complexity
↓
Invisible Infrastructure
↓
Human Experience
へ変換する。
44 Session終了
45分終了時には、単にAudioを止めるだけではない。
End Sequenceを行う。
Program End
↓
Final Physical State
↓
Audio Stop
↓
Lighting End / Safe Scene
↓
Session Clock Stop
↓
Runtime Close
↓
Local Event Flush
↓
Summary Generation
↓
Memory Sync
Session Endも一つのState Transitionとして扱う。
45 Ending State
async fn close_session(
orchestrator:
&mut StudioOrchestrator,
) -> Result<
(),
StudioRuntimeError,
> {
orchestrator
.runtime
.set_mode(
IntegratedRuntimeMode::
Stopping
);
orchestrator
.runtime
.finish_program()
.await?;
orchestrator
.memory
.record_session_end()
.await?;
orchestrator
.runtime
.set_mode(
IntegratedRuntimeMode::
Ended
);
Ok(())
}
実際には各Physical Subsystemの終了処理を加える。
46 Session Summary
終了後にSubsystem Summaryを統合する。
struct IntegratedSessionSummary {
session_id:
uuid::Uuid,
runtime_availability:
f64,
audio:
AudioSessionSummary,
lighting:
LightingSessionSummary,
network:
NetworkSessionSummary,
sensors:
SensorSessionSummary,
fallback_count:
u32,
manual_override_count:
u32,
}
これがPhysical Session Memoryになる。
47 Reality Verification
予定と実際を比較する。
Program Planned
↓
Runtime Commanded
↓
Physical Applied
↓
Sensor Observed
↓
Human Experienced
複数層を比較する。
一つのLayerだけで成功を判定しない。
48 Physical Completion
例えばLighting Cueについて、
ProgramはPeakを要求した。
RuntimeはCommandを送った。
ControllerはAcceptedした。
Physical Observationが変化を検出した。
ここまで揃えばPhysical Completion Confidenceは高い。
一方、
Command Applied
だけなら、まだPhysical Verificationは限定的である。
49 Difference Record
struct PhysicalDifference {
domain:
String,
planned_seconds:
Option<f64>,
commanded_seconds:
Option<f64>,
applied_seconds:
Option<f64>,
observed_seconds:
Option<f64>,
}
Session終了後にDifferenceをまとめる。
50 Physical MemoryをCloudへ送る
終了後SummaryとEventをCloudへ同期する。
ただしCloudが利用不能ならLocalへ残す。
Session End
↓
Local Memory Complete
↓
Cloud Available?
├── Yes → Sync
└── No → Pending
Session CompletionをCloud Sync Completionへ依存させない。
51 Studio Memory Status
CREATE TABLE studio_memory_status (
session_id UUID PRIMARY KEY,
local_memory_complete
BOOLEAN NOT NULL,
cloud_sync_complete
BOOLEAN NOT NULL,
physical_summary_complete
BOOLEAN NOT NULL,
verified_at TIMESTAMPTZ,
FOREIGN KEY (
session_id
)
REFERENCES sessions(
session_id
)
);
これでMemoryの状態を追跡できる。
52 Post-session Review
Instructor Appでは、
ProgramとのDifference。
AI Suggestion。
Manual Override。
重要なPhysical Event。
を人間が理解できる形へ変換する。
例えば、
Session completed
Lighting fallback:
1
Manual override:
1
Cloud interruption:
8 min
No impact on session execution
のようにする。
Logそのものを読ませない。
53 Operational Review
Studio OperatorはTechnical DetailをReviewできる。
Audio Drift。
Lighting Timing Difference。
Network Reconnect。
Sensor Availability。
Queue Depth。
などである。
これをMaintenanceへ接続する。
54 Learningへの接続
Python IntelligenceはSession Memoryから、
Program。
Actual Runtime。
Physical Difference。
Human Decision。
Reflection。
を読む。
Program
+
Physical Reality
+
Human Reality
↓
Learning Record
これによって次回の、
Timing Compensation。
Program Design。
AI Suggestion。
Maintenance。
を改善できる。
55 Physical LearningとCreative Learningを分ける
重要なのは、すべてを同じOptimizationへしないことである。
例えばLighting Timingが18ms遅い。
これはTechnical Optimization対象になり得る。
しかしInstructorが意図的にProgramからDeviationした。
これはCreative Differenceかもしれない。
Technical Difference
→ Reduce unnecessary error
Creative Difference
→ Understand, preserve, learn
と分ける。
AIがCreative Differenceまで「誤差」として0へ収束させない。
56 Studio ConfigurationへのFeedback
Physical Learningから、
Device Latency Profile。
Fallback Policy。
Network Configuration。
Maintenance Priority。
を更新できる。
しかしCurrent Configurationを直接自動変更するのではなく、
Candidate Configuration
↓
Test
↓
Approve
↓
Activate
とする。
57 ProgramへのFeedback
Physical Runtime側からProgram Builderへ、
特定TransitionでLighting Loadが高い。
特定SceneのDevice Latencyが大きい。
Program Cueが密集しすぎている。
などを返せる。
ProgramはCreative DesignだけでなくPhysical Executabilityも持つ。
58 Maintenanceへの接続
Device Health Historyから予防保守へ接続できる。
例えば、
特定ControllerのDisconnect増加。
Audio InterfaceのError増加。
Network Latencyの徐々な悪化。
Edge Storage使用量増加。
を検出する。
AIはMaintenance Candidateを提示できる。
ただし自動交換ではなく、人間の運用判断へ返す。
59 Studio IntegrationとResilience
統合Systemほど、一箇所のFailureで全体が崩れる危険がある。
したがってIntegrationの目的は「全部を密結合すること」ではない。
意味的には統合する。
実装上は疎結合にする。
One Experience
+
Multiple Independent Failure Domains
が理想である。
60 One Studio Runtime
ここまでをまとめると、一Studioは次の構造になる。
FEELCYCLE Studio
Program Version
↓
Session Runtime
↓
┌────────┴────────┐
↓ ↓
Human Authority AI
↓ ↓
└────────┬────────┘
↓
Rust Edge
↓
┌─────────────────┼─────────────────┐
↓ ↓ ↓
Audio Lighting Sensor
↓ ↓ ↑
音 光 観測
└─────────────────┼─────────────────┘
↓
Instructor + Members
↓
45 Minutes
↓
Reality
↓
Memory
↓
Learning
これがStudio Integrationの完成形である。
61 Studio Integration v0.1のCompletion Criteria
v0.1では、少なくとも次を満たす。
Studio ConfigurationをVersion管理できる。
SessionごとのExecution Contextを固定できる。
ProgramとAssetを事前にLocalへ準備できる。
Audio、Lighting、Sensor、Network、Edgeを一つのPreflightで検証できる。
Critical / Optional Componentを分離できる。
Human Start Authorityを持てる。
一つのSession ClockでPhysical Runtimeを動かせる。
Program Event、Human Event、Sensor Eventを一つのRuntimeへ統合できる。
Subsystem Failure時にDegraded Modeへ移行できる。
Human Manual Overrideを保持できる。
Critical Failure時にSafe Stateへ移行できる。
Cloud Failure時にも45分を継続できる。
Session終了後にPhysical Summaryを生成できる。
Local Memoryを完成させた後Cloudへ同期できる。
Planned / Commanded / Applied / Observedを比較できる。
LearningをProgram、AI、Studio Operationへ戻せる。
ここまで成立すれば、一つのStudioでFEELCYCLE AI v0.1をEnd-to-Endで実行できる。
62 「統合」の意味
Studio Integrationは、すべてを一つのSoftwareへ押し込むことではない。
AudioにはAudioの責任がある。
LightingにはLightingの責任がある。
SensorにはSensorの責任がある。
EdgeにはEdgeの責任がある。
HumanにはHumanのAuthorityがある。
AIにはIntelligenceの役割がある。
差異を保持したまま、一つの45分へ接続する。
それがIntegrationである。
63 Physical Runtimeの完成直前
ここまでで、第6章の主要Physical Componentはすべて接続された。
AIからPhysical Spaceへ。
Audio。
Lighting。
Microphone・Sensor・Edge。
Network・Controller・Protocol。
そしてStudio Integration。
残るのは、このPhysical Runtime全体を一つのv0.1として固定することである。
次節では、
FEELCYCLE Physical Runtime v0.1
を完成させる。
どのHardwareを最低限用意するのか。
どのSoftwareをどこへ配置するのか。
起動からPreflight、45分、Fallback、終了、Memoryまでをどう一周させるのか。
そして、一つのStudioで完成したPhysical Runtimeを、次の第Ⅵ部でPython、Rust、TypeScript、Swift、SQL、AWSと完全に統合するための境界を確定する。
第7節 FEELCYCLE Physical Runtime v0.1
ここまで、第6章ではFEELCYCLE AIをSoftwareの外へ出してきた。
AIから物理空間へ。
Audio System。
Lighting System。
Microphone・Sensor・Edge Device。
Network・Controller・Protocol。
Studio Integration。
Pythonが理解し、Rustが計算していた45分は、ここで初めて、
音。
光。
機材。
Network。
Sensor。
身体。
空間。
へ接続された。
本節では、それらを一つの実行可能なPhysical Runtimeとして固定する。
FEELCYCLE Physical Runtime v0.1である。
v0.1の目的は、AIがStudioのすべてを自動制御することではない。
一つのStudioにおいて、
Programを読み込み。
Session開始前にPhysical Systemを検証し。
45分を一つのClockで動かし。
AudioとLightingを安全に実行し。
Physical RealityをSensorで必要最小限観測し。
Failure時には縮退し。
HumanがいつでもAuthorityを引き取れ。
終了後にRealityをMemoryへ戻せる。
この一周を完成させることである。
最小構造は、
Program
↓
Preflight
↓
Human Start
↓
Rust Runtime
↓
Physical Runtime
↓
Audio・Lighting・Sensor・Network
↓
45 Minutes
↓
Verification
↓
Memory
↓
Learning
となる。
1 Physical Runtimeの最終Architecture
一Studioの全体構造を確定する。
FEELCYCLE Physical Runtime v0.1
AWS Cloud
↕
Memory / Configuration
↕
┌─────────────────┐
│ Edge Device │
│ │
│ Rust Runtime │
│ Session Clock │
│ Safety Manager │
│ Local Memory │
│ Cloud Sync │
└────────┬────────┘
│
┌─────────────────────┼─────────────────────┐
│ │ │
↓ ↓ ↓
Audio System Lighting System Sensor Gateway
↓ ↓ ↑
Playback / Mixer Controller / Fixture Microphone
DSP / Amplifier Telemetry
Speaker Environment
↓ ↓ ↑
└─────────────────────┼─────────────────────┘
↓
Studio
↓
Instructor + Members
↓
45 Minutes
そしてHuman Interfaceとして、
Instructor Console
Studio Monitor
Physical Manual Control
を接続する。
Physical Manual ControlはAutomationとは独立して残す。
2 最小Hardware構成
v0.1に必要なHardwareを役割別に整理する。
第一に、Edge Computer。
第二に、Audio Playback環境。
第三に、Audio Interface。
第四に、Mixer / DSP。
第五に、Amplifier / Speaker System。
第六に、Lighting Controller。
第七に、Lighting Fixture。
第八に、Measurement用Microphoneまたは必要なOperational Sensor。
第九に、有線Network Switch。
第十に、Instructor / Operator用Control Interface。
さらに設備側の独立したSafety Systemを保持する。
概念的には、
Edge Computer
│
├── Ethernet
├── Audio Interface
├── Lighting Controller
└── Sensor Gateway
Audio Interface
↓
Mixer / DSP
↓
Amplifier
↓
Speakers
Lighting Controller
↓
Fixtures
Sensor Gateway
↑
Measurement Microphone
Device Telemetry
Network Telemetry
となる。
具体的な製品選定は、既存Studio設備、必要Channel数、設置条件、安全要件、保守体制によって決定する。
本書のArchitectureは特定Vendorに固定しない。
3 最小Software構成
Edge Deviceには最低限、次を配置する。
feelcycle-edge/
│
├── runtime-core
├── session-clock
├── safety-manager
├── audio-service
├── lighting-service
├── sensor-service
├── network-service
├── local-memory
├── health-service
└── cloud-sync
Rustを中心にする。
Python Intelligenceは重い解析や推論を担当し、Physical Critical Pathから分離する。
TypeScriptはStudio MonitorとInstructor Consoleを担当する。
SwiftはStudioのPrimary Physical Runtimeにはしない。
SQL・AWSはLong-Term Memoryを担当する。
4 責任分離
最終的な役割は、
Python
=
理解・推定・提案
Rust
=
時間・実行・安全・Physical Control
TypeScript
=
Live Human Interface
Swift
=
Personal Mobile Interface
SQL
=
Relational Memory
AWS
=
Shared Memory / Distribution
である。
Physical Runtimeの中心はRust Edgeになる。
5 Authoritative Physical State
Studio内のAuthoritative StateをEdge Runtimeへ置く。
#[derive(
Debug,
Clone,
)]
struct AuthoritativePhysicalState {
session_id:
Option<uuid::Uuid>,
mode:
IntegratedRuntimeMode,
session_seconds:
f64,
audio:
AudioPlaybackState,
lighting:
LightingRuntimeState,
health:
PhysicalHealth,
capabilities:
StudioCapabilities,
cloud_connected:
bool,
}
TypeScriptやCloudは、このStateのRepresentationを受け取る。
Web DashboardをAuthoritative Realityにはしない。
6 Runtime Mode
Physical RuntimeのModeを最終確定する。
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
)]
enum IntegratedRuntimeMode {
Idle,
Preparing,
Ready,
Normal,
Assisted,
Degraded,
Manual,
Safe,
Stopping,
Ended,
}
State Transitionは無制限に行わせない。
概念的には、
Idle
↓
Preparing
↓
Ready
↓
Normal
├→ Assisted
├→ Degraded
├→ Manual
└→ Safe
↓
Stopping
↓
Ended
となる。
7 State Transition
fn can_transition(
from:
IntegratedRuntimeMode,
to:
IntegratedRuntimeMode,
) -> bool {
use IntegratedRuntimeMode::*;
matches!(
(from, to),
(Idle, Preparing)
| (Preparing, Ready)
| (Ready, Normal)
| (Normal, Assisted)
| (Normal, Degraded)
| (Normal, Manual)
| (Normal, Safe)
| (Assisted, Normal)
| (Assisted, Manual)
| (Assisted, Safe)
| (Degraded, Manual)
| (Degraded, Safe)
| (Degraded, Normal)
| (Manual, Normal)
| (Manual, Safe)
| (Normal, Stopping)
| (Assisted, Stopping)
| (Degraded, Stopping)
| (Manual, Stopping)
| (Safe, Stopping)
| (Stopping, Ended)
)
}
Productionではより厳密なGuard Conditionを加える。
8 起動
一日のStudio Runtime起動を考える。
Power On
↓
Edge Boot
↓
Runtime Start
↓
Configuration Load
↓
Device Discovery
↓
Network Check
↓
Safe Physical State
↓
Cloud Connection
↓
Idle
起動直後からLightingやAudioを自由に操作しない。
最初はSafe Stateへ置く。
9 Configuration Load
async fn initialize_studio(
config:
StudioConfiguration,
) -> Result<
StudioRuntime,
StudioRuntimeError,
> {
validate_configuration(
&config
)?;
let runtime =
StudioRuntime::new(
config
)
.await?;
runtime
.enter_initial_safe_state()
.await?;
Ok(runtime)
}
Configurationが不正ならReadyへ進まない。
10 Session Preparation
予定されたSessionを取得する。
Program Versionを取得する。
Audio AssetをLocalに準備する。
Lighting Sceneを確認する。
Studio Configurationを固定する。
必要なAI Model Versionを確認する。
Session
+
Program Version
+
Studio Configuration
+
Approved Assets
+
Approved Model
=
Execution Context
このContextをSession開始前に固定する。
11 Execution Manifest
v0.1では一つのManifestへまとめるとよい。
#[derive(
Debug,
Clone,
serde::Serialize,
serde::Deserialize,
)]
struct SessionExecutionManifest {
session_id:
uuid::Uuid,
program_version_id:
uuid::Uuid,
studio_id:
uuid::Uuid,
studio_configuration_version:
u64,
instructor_id:
uuid::Uuid,
ai_model_version:
Option<String>,
created_at:
chrono::DateTime<
chrono::Utc
>,
}
これがその45分の実行条件の最小証明になる。
12 Manifestを保存する
CREATE TABLE session_execution_manifests (
session_id UUID PRIMARY KEY,
program_version_id UUID NOT NULL,
studio_id UUID NOT NULL,
studio_configuration_version
INTEGER NOT NULL,
instructor_id UUID NOT NULL,
ai_model_version TEXT,
manifest JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL
DEFAULT NOW(),
FOREIGN KEY (
session_id
)
REFERENCES sessions(
session_id
)
);
後からRealityを再構成できる。
13 Unified Preflight
Session開始前に全Physical Systemを一回で検査する。
Program
Asset
Edge
Audio
Lighting
Sensor
Control Network
Manual Control
Safety
Local Storage
Cloud
である。
CloudはOptional。
SafetyやAudio CoreはCritical。
このDifferenceを保持する。
14 Preflight Result
#[derive(
Debug,
Clone,
)]
struct PhysicalRuntimePreflight {
program_ready:
bool,
edge_ready:
bool,
audio_ready:
bool,
lighting_ready:
bool,
sensor_ready:
bool,
control_network_ready:
bool,
manual_control_ready:
bool,
safety_ready:
bool,
local_memory_ready:
bool,
cloud_ready:
bool,
}
15 開始可否
fn start_decision(
p:
&PhysicalRuntimePreflight,
) -> PreflightDecision {
if !p.program_ready
|| !p.edge_ready
|| !p.audio_ready
|| !p.control_network_ready
|| !p.manual_control_ready
|| !p.safety_ready
|| !p.local_memory_ready
{
return
PreflightDecision::
CannotStart;
}
if !p.lighting_ready
|| !p.sensor_ready
|| !p.cloud_ready
{
return
PreflightDecision::
ReadyDegraded;
}
PreflightDecision::Ready
}
ただし実運用のCritical分類は安全検証によって確定する。
16 Human Start
Physical RuntimeがReadyでも、Human Start Authorityを残す。
InstructorまたはOperatorが、
「このStudio、このProgram、この状態で開始する」
と決定する。
Machine Ready
+
Human Ready
=
Session Start
である。
17 Session Clock
Startと同時に一つのSession Clockを開始する。
struct SessionClock {
started_at:
std::time::Instant,
}
impl SessionClock {
fn seconds(
&self,
) -> f64 {
self.started_at
.elapsed()
.as_secs_f64()
}
}
Audio。
Lighting。
Runtime Event。
Sensor。
すべてをこのClockへ対応させる。
18 Physical Timeline
Programから実行予定を生成する。
#[derive(
Debug,
Clone,
)]
enum PhysicalTimelineEvent {
Audio(
AudioCommand
),
Lighting(
LightingCommand
),
Program(
RuntimeEvent
),
}
時間順にSchedulerへ入れる。
19 Execution Scheduler
async fn execute_timeline(
clock:
&SessionClock,
mut events:
Vec<
ScheduledPhysicalEvent
>,
tx:
tokio::sync::mpsc::Sender<
PhysicalTimelineEvent
>,
) {
events.sort_by(
|a, b|
a.target_seconds
.partial_cmp(
&b.target_seconds
)
.unwrap()
);
for event in events {
wait_until(
clock,
event.dispatch_seconds,
)
.await;
let _ =
tx.send(
event.payload
)
.await;
}
}
Device Latencyを考慮したDispatch Timeを利用する。
20 Audio + Lighting
同じTransitionを一つのLogical Eventとして扱える。
Logical Transition
138.500 sec
↓
Audio target
138.500
↓
Lighting target
138.500
↓
Different dispatch times
↓
One Physical Moment
ここがPhysical Runtimeの中心になる。
21 Sensor Loop
Physical Outputと並行してSensorを動かす。
tokio::select! {
event =
runtime_events.recv() =>
{
handle_runtime_event(
event
).await;
}
observation =
sensor_events.recv() =>
{
handle_observation(
observation
).await;
}
health =
health_events.recv() =>
{
handle_health(
health
).await;
}
}
Physical Realityを観測しながら実行する。
22 AI Connection
Python IntelligenceはPhysical RuntimeのCritical Loopへ直接置かない。
AIからは、
Prediction。
Suggestion。
Estimate。
が届く。
#[derive(
Debug,
Clone,
)]
struct AiRuntimeSuggestion {
suggestion_id:
uuid::Uuid,
session_id:
uuid::Uuid,
action:
serde_json::Value,
confidence:
f64,
requires_human_approval:
bool,
}
RuntimeがAuthority Policyを確認する。
23 AI実行境界
AI Suggestion
↓
Valid?
↓
Current?
↓
Approved Action Type?
↓
Human Approval if required
↓
Safety Validation
↓
Runtime
↓
Physical Device
期限切れSuggestionを後から実行しない。
24 Human Override
InstructorまたはOperatorはAutomationをOverrideできる。
Override Eventを第一級Eventとして扱う。
#[derive(
Debug,
Clone,
)]
struct ManualOverrideEvent {
override_id:
uuid::Uuid,
session_id:
uuid::Uuid,
actor_id:
uuid::Uuid,
target:
String,
reason:
Option<String>,
occurred_at_seconds:
f64,
}
これをMemoryへ残す。
25 Override時のAuthority
Manual Modeに入ると、
AI Physical Executionを停止する。
対象Automationを停止する。
Human Control Pathを有効にする。
SensorとMemoryは継続する。
つまり、
Automation OFF
Observation ON
Memory ON
Human Authority ON
である。
26 安全の優先順位
Physical Runtime v0.1のPriorityを最終確定する。
1 Safety
2 Human Authority
3 Audio Continuity
4 Core Runtime
5 Program Timing
6 Lighting
7 Operational Observation
8 AI Assistance
9 Cloud Synchronization
10 Background Analytics
上位を下位のために犠牲にしない。
27 AI Failure
Python Intelligenceが停止した場合、
AI
Unavailable
↓
Program Runtime continues
↓
Instructor continues
↓
Physical Session continues
とする。
AIはEnhancementであり、45分の唯一の成立条件ではない。
28 Cloud Failure
AWSとのConnectionが切れた場合、
Cloud
Unavailable
↓
Rust Runtime continues
↓
Local Memory
↓
Local Buffer
↓
Session continues
とする。
Physical RealityをCloudへ従属させない。
29 Sensor Failure
Sensor
Unavailable
↓
Sensor-dependent AI disabled
↓
Physical Output continues
↓
Human remains authority
である。
30 Lighting Failure
Lighting ControllerにFailureが起きた場合、
Lighting Automation
↓ failure
Fallback / Safe / Manual Lighting
↓
Audio continues if safe
↓
Session continues when permitted
とする。
31 Audio Failure
Audioはより重要なDependencyである。
Primary Playback Failureなら、
Secondary。
Manual。
必要ならSafe Stop。
へ移る。
Primary
↓
Secondary
↓
Manual
↓
Safe Stop
v0.1では少なくともManual Fallbackへの明確な移行を用意する。
32 Edge Failure
Edge Runtimeそのものが落ちた場合はAutomation Coreを失う。
そのため、
Watchdog。
Restart。
Physical Manual Control。
Safe State。
を持つ。
Edge Failure
↓
Automation Lost
↓
Physical Safety Layer remains
↓
Human Manual Control
を成立させる。
33 Failure Matrix
Physical RuntimeのFailureを整理する。
AI Failure
→ Continue without AI
Cloud Failure
→ Continue locally
Sensor Failure
→ Continue without sensing enhancement
Lighting Failure
→ Fallback / Manual
Audio Failure
→ Secondary / Manual / Stop
Edge Failure
→ Manual / Safe
Safety Failure
→ Do not continue automatically
System全体を一つの「正常/異常」だけで扱わない。
34 Health Aggregation
#[derive(Debug)]
struct PhysicalRuntimeHealth {
edge:
DeviceHealth,
audio:
DeviceHealth,
lighting:
DeviceHealth,
sensors:
DeviceHealth,
network:
DeviceHealth,
cloud:
DeviceHealth,
}
Human Interfaceへは意味として圧縮する。
35 Instructor Console
InstructorがSession中に見る情報は最小化する。
12:34
Track
Current Section
Mode
NORMAL
System
OK
AI Suggestion
1
Critical Failure時だけ強く表示する。
Technical DataはStudio Monitorへ任せる。
36 Studio Monitor
Operator側には、
Edge Runtime。
Audio Chain。
Lighting Controller。
Sensor。
Network。
Cloud。
Queue。
Latency。
Fallback。
を表示する。
Physical Runtimeの全体Observer Positionになる。
37 Physical Manual Control
重要な操作をWeb Browserだけに依存させない。
設備条件に応じて、
Audio Mixer。
Lighting Console。
Physical Switch。
Safety System。
などの手動経路を保持する。
Software UI Failure
≠
Loss of Control
である。
38 Session中のLocal Memory
重要EventはまずLocalへ記録する。
Runtime Event
↓
Local Append Log
↓
Physical Execution
↓
Async Cloud Sync
Cloudへ書けたことを確認してからRealityを実行する構造にはしない。
39 Physical Event Log
Local Eventには、
Program Event。
Audio Result。
Lighting Result。
Human Override。
Device Failure。
Sensor Observation。
Mode Transition。
を残す。
#[derive(
Debug,
serde::Serialize,
)]
struct PhysicalRuntimeRecord {
record_id:
uuid::Uuid,
session_id:
uuid::Uuid,
record_type:
String,
session_seconds:
f64,
payload:
serde_json::Value,
}
40 Planned / Commanded / Applied / Observed
Physical Runtime v0.1では、同じRealityを最低四層に分ける。
Planned
↓
Commanded
↓
Applied
↓
Observed
例を挙げる。
Lighting Peak
Planned:
138.500
Commanded:
138.482
Applied:
138.517
Observed:
138.525
このDifferenceがPhysical Learningになる。
41 Human Experienceを第五層にする
さらに、
Experienced
がある。
SensorやHardwareが完全でも、Member Experienceが自動的に良いとは限らない。
したがって最終構造は、
Planned
Commanded
Applied
Observed
Experienced
である。
Physical AIは最後の一つを完全には機械計測できない。
Human Reflectionが必要になる。
42 Session End
45分終了後の順序を確定する。
Program Reaches End
↓
Final Transition
↓
Audio End
↓
Lighting End / Defined Final Scene
↓
Stop New Automation
↓
Session Clock Freeze
↓
Local Memory Finalize
↓
Physical Summary
↓
Cloud Sync
↓
Idle
Cloud Syncが終わらなくてもStudioは次の準備へ進める設計にする。
43 Physical Summary
#[derive(
Debug,
serde::Serialize,
)]
struct PhysicalRuntimeSummary {
session_id:
uuid::Uuid,
runtime_mode_end:
IntegratedRuntimeMode,
audio_availability:
f64,
lighting_availability:
f64,
sensor_availability:
f64,
control_network_availability:
f64,
cloud_availability:
f64,
fallback_count:
u32,
manual_override_count:
u32,
critical_failure_count:
u32,
}
このSummaryをLong-Term Memoryへ戻す。
44 SQLへの統合
CREATE TABLE physical_runtime_summaries (
session_id UUID PRIMARY KEY,
runtime_mode_end TEXT NOT NULL,
audio_availability
DOUBLE PRECISION,
lighting_availability
DOUBLE PRECISION,
sensor_availability
DOUBLE PRECISION,
control_network_availability
DOUBLE PRECISION,
cloud_availability
DOUBLE PRECISION,
fallback_count INTEGER NOT NULL
DEFAULT 0,
manual_override_count INTEGER NOT NULL
DEFAULT 0,
critical_failure_count INTEGER NOT NULL
DEFAULT 0,
generated_at TIMESTAMPTZ NOT NULL
DEFAULT NOW(),
FOREIGN KEY (
session_id
)
REFERENCES sessions(
session_id
)
);
45 End-to-End Verification
Session終了後に、自動Verificationを行う。
最低限、
Session Start / Endがある。
Program Versionが固定されている。
Audio Executionが存在する。
Lighting Executionが存在する。
Runtime Eventが保存されている。
Critical Eventが記録されている。
Local MemoryがCompleteである。
ことを確認する。
46 Verification Result
#[derive(
Debug,
Clone,
)]
struct PhysicalVerification {
execution_complete:
bool,
memory_complete:
bool,
critical_failure:
bool,
unresolved_events:
u32,
}
問題があればOperation Reviewへ送る。
47 Memory Sync
Local Physical MemoryをAWSへ送る。
Physical Events
↓
Local Buffer
↓
Ingestion
↓
SQS
↓
Persistence Worker
↓
RDS / S3
第5章のMemory Architectureとここで完全に接続する。
48 Recovery
Cloud復旧後には未同期Eventを再送する。
Edge再起動後には未完了Session Memoryを検出する。
Boot
↓
Local Recovery Scan
↓
Unsynced Session Found
↓
Integrity Check
↓
Resume Sync
Runtime RecoveryとMemory Recoveryを同時に考える。
49 Physical Runtime Release
Softwareとしてv0.1をVersion化する。
FEELCYCLE Physical Runtime
v0.1.0
Edge Software。
Studio Configuration。
Protocol Schema。
Database Migration。
をRelease Manifestで対応させる。
#[derive(
Debug,
serde::Serialize,
)]
struct PhysicalRuntimeRelease {
runtime_version:
String,
protocol_schema_version:
u32,
configuration_schema_version:
u32,
database_schema_version:
u32,
}
Version Compatibilityを明示する。
50 Release Manifest
{
"runtime_version": "0.1.0",
"protocol_schema_version": 1,
"configuration_schema_version": 1,
"database_schema_version": 1
}
一部だけ無秩序に更新してCompatibilityを壊さない。
51 Deployment
Production Studioへの展開順序は、
Build
↓
Unit Test
↓
Integration Test
↓
Hardware-in-the-Loop
↓
Golden Session
↓
Empty Studio
↓
Staff Test
↓
Controlled Production
↓
Production
とする。
コードを書いたからPhysical Runtimeが完成したとはみなさない。
RealityによるVerificationを必ず通す。
52 Golden Session v0.1
Physical Runtime全体を検証する基準Sessionを持つ。
0 min
Session Start
5 min
Lighting Transition
10 min
Cloud Disconnect
15 min
Sensor Failure
20 min
Sensor Recovery
25 min
Lighting Fallback
30 min
Manual Override
35 min
Automation Restore
40 min
Cloud Recovery
45 min
Session End
このようなTest TimelineによってFailureまで含めて検証する。
53 Testするのは成功だけではない
通常状態だけを45分動かして終わりにしない。
必ず、
断線。
遅延。
Device Failure。
Cloud Failure。
Manual Transition。
Recovery。
をTestする。
Resilienceは正常時には見えない。
54 Physical Runtime v0.1の完成条件
ここでCompletion Criteriaを確定する。
一つのStudio ConfigurationをVersion管理できる。
一つのProgram VersionをLocalへ準備できる。
一つのExecution Manifestを生成できる。
Unified Preflightを実行できる。
Critical / Optional Componentを分離できる。
Human Start Authorityを持てる。
Session Clockを開始できる。
AudioをPhysical Outputできる。
LightingをPhysical Outputできる。
Sensor Observationを取得できる。
Device Healthを取得できる。
Physical Control NetworkでDeviceを接続できる。
Cloud断時にLocalで継続できる。
AI断時にProgramを継続できる。
Sensor断時にDegraded運転できる。
Lighting断時にFallbackできる。
HumanがManual Authorityを取得できる。
Critical Failure時にSafe Stateへ移行できる。
Planned / Commanded / Applied / Observedを区別できる。
Physical EventをLocal Memoryへ保存できる。
Session終了後にSummaryを作れる。
Cloud復旧後にMemoryを同期できる。
Golden SessionをEnd-to-Endで完走できる。
この条件が満たされれば、
FEELCYCLE Physical Runtime v0.1
は成立する。
55 Hardwareが主役なのではない
ここで注意したい。
Physical Runtimeの完成とは、Studioを大量の最新機材で埋めることではない。
Hardwareの数が増えるほど良いわけではない。
Sensorの数が増えるほどAIが良くなるわけでもない。
必要なのは、
一つの45分に本当に必要なPhysical Capabilityを選び、
そのCapabilityが安全に動き、
人間のExperienceを壊さず、
Failureしても縮退でき、
Realityから学べる
ことである。
Minimum Hardware
+
Maximum Meaning
を目指す。
56 AIが目立たないPhysical AI
FEELCYCLE Physical Runtimeが高度に完成したとき、MemberはAIを強く意識しない可能性がある。
むしろ、それが望ましい。
Musicが自然に続く。
Lightingが自然に変化する。
InstructorはTechnologyではなくMemberを見る。
System Failureは背景で吸収される。
AIは必要な時だけSuggestionを出す。
Session中、iPhoneを見る必要はない。
つまり、
More Intelligence
↓
Less Interface Friction
へ進む。
57 Instructorを中心から外さない
Physical Automationが高度化しても、InstructorはRuntimeの末端ではない。
AIが作った45分を再生するOperatorでもない。
その場のRealityを、人間として観測し、判断し、必要ならProgramから逸脱し、新しいExperienceを生成する主体である。
AIは、
Programを理解する。
Differenceを示す。
Timingを支える。
Physical Failureを吸収する。
Memoryを作る。
しかし、
「今この場で何をするか」
についてHuman Authorityを残す。
58 MemberをData Pointにしない
MemberもSensor入力の集合ではない。
Heart Rate。
Participation。
History。
Recommendation Click。
これらはMemberそのものではない。
Physical Runtimeが最終的に守るべきなのは、
測定精度
ではなく、
Experienceが成立する空間
である。
AIがMemberをより細かく測るほど進化するとは限らない。
必要なDataだけで、より良いRealityを成立させる方が重要である。
59 Physical Runtimeは翻訳機である
FEELCYCLE Physical Runtimeの本質を一語で表すなら、Translationである。
Programを音へ翻訳する。
Stateを光へ翻訳する。
Human IntentをCommandへ翻訳する。
Physical RealityをSensor Featureへ翻訳する。
FailureをFallbackへ翻訳する。
RealityをMemoryへ翻訳する。
Meaning
⇄
Code
⇄
Signal
⇄
Device
⇄
Reality
この往復を45分間止めずに継続する。
60 第Ⅴ部で完成したもの
第Ⅴ部の開始時点で、FEELCYCLE AIはまだSoftware中心だった。
ここまでで、
Audio。
Lighting。
Microphone。
Sensor。
Edge Device。
Network。
Controller。
Protocol。
Studio。
が接続された。
つまり、
Software
↓
Hardware
↓
Physical Reality
という境界を越えた。
同時に、
Physical Reality
↓
Observation
↓
Software
という帰路も完成した。
これによってFEELCYCLE AIは、一方向のAutomation Systemではなくなった。
Physical Realityと継続的に往復するRuntimeになった。
61 ここまでの全Stack
ここまで本書で実装したものを積み上げる。
Python
Intelligence
↓
Rust
Runtime
↓
TypeScript
Interface
↓
Swift
Mobile
↓
SQL
Memory
↓
AWS
Cloud
↓
Hardware
Physical Runtime
↓
FEELCYCLE Reality
しかし、これは本当は一直線ではない。
Realityから再び上へ戻る。
Python Intelligence
↓
Rust Runtime
↓
Human Interface
↓
Physical Runtime
↓
Reality
↓
Memory
↓
Python Intelligence
↺
という循環である。
62 残る最後の課題
個々のLayerはここまでで成立した。
Pythonは理解できる。
Rustは実行できる。
TypeScriptは見せられる。
Swiftは個人へ接続できる。
SQLとAWSは記憶できる。
HardwareはRealityを動かせる。
しかし、まだこれらは「七つの完成したLayer」である。
最後に必要なのは、
一つのFEELCYCLE AI
として接続することである。
同じIdentity。
同じSession。
同じProgram Version。
同じState。
同じEvent。
同じMemory。
同じAuthority。
を全Layerで共有する必要がある。
63 次はIntegrationへ
次の第Ⅵ部では、すべてを統合する。
PythonとRustを接続する。
Web、Mobile、Cloudを接続する。
AIとStudioを接続する。
Member、Instructor、Companyを接続する。
そして、
Programを一つ選ぶ。
Sessionを一つ生成する。
StudioをPreflightする。
45分を開始する。
AIが理解する。
Rustが実行する。
人間が判断する。
Physical Spaceが変化する。
RealityをMemoryへ戻す。
次の45分へ学習する。
このEnd-to-End Loopを一つのSystemとして実装する。
FEELCYCLE Physical Runtime v0.1は、ここで完成した。
次に完成させるのは、そのPhysical Runtimeを含む全Stackである。
FEELCYCLE AI v0.1。
人・音楽・身体・空間・会社を、一つのRuntimeとして接続する。
愛と敬意を込めてmandala
