class_name OperationsOSObserver extends RefCounted ## Passive actual Main/runtime observer for P24-02 operations and notification evidence. ## Captures OS process environment, screen scale, bubble state, and modal identity ## without modifying the active simulation model. ## Local unit fixture observations are strictly separated from candidate normal OS ## input evidence (which requires formal native OS capture receipts). var pid := 0 var platform := "" var window_size := Vector2i.ZERO var observations: Array[Dictionary] = [] var bubble_records: Dictionary = {} # Maps actor_id -> latest bubble record var bubble_history: Array[Dictionary] = [] # Chronological history of all bubble state transition events var modal_records: Array[Dictionary] = [] var cutin_records: Array[Dictionary] = [] var save_records: Array[Dictionary] = [] func _init() -> void: pid = OS.get_process_id() platform = OS.get_name() func capture_environment(tree: SceneTree, main: Control) -> Dictionary: var root: Window = tree.root if tree != null else null window_size = root.size if root != null else Vector2i.ZERO var report := { &"pid": pid, &"platform": platform, &"window_size": [window_size.x, window_size.y], &"main_present": is_instance_valid(main), &"captured_at_msec": Time.get_ticks_msec(), &"fixture_scope": &"local_unit_fixture_only_not_native_os_input_evidence", } observations.append(report) return report func record_bubble(actor_id: StringName, kind: StringName, source_state: int) -> void: var record := { &"actor_id": actor_id, &"kind": kind, &"source_state": source_state, &"recorded_at": Time.get_ticks_msec(), } bubble_records[actor_id] = record bubble_history.append(record) func get_latest_bubble(actor_id: StringName) -> Dictionary: return bubble_records.get(actor_id, {}) func get_bubble_history() -> Array[Dictionary]: return bubble_history.duplicate(true) func record_modal_event(dialog_name: String, action: String, details: Dictionary = {}) -> void: modal_records.append({ &"dialog_name": dialog_name, &"action": action, &"details": details.duplicate(true), &"recorded_at": Time.get_ticks_msec(), }) func record_cutin(kind: StringName, heading: String, message: String) -> void: cutin_records.append({ &"kind": kind, &"heading": heading, &"message": message, &"recorded_at": Time.get_ticks_msec(), }) func record_save_label(path: String, display_name: String, is_fresh: bool) -> void: save_records.append({ &"path": path, &"display_name": display_name, &"is_fresh": is_fresh, &"recorded_at": Time.get_ticks_msec(), }) func get_summary() -> Dictionary: return { &"pid": pid, &"platform": platform, &"window_size": [window_size.x, window_size.y], &"observations_count": observations.size(), &"unique_actors_tracked": bubble_records.size(), &"bubbles_tracked": bubble_history.size(), &"bubble_history_count": bubble_history.size(), &"bubble_events_count": bubble_history.size(), &"modals_tracked": modal_records.size(), &"cutins_tracked": cutin_records.size(), &"saves_tracked": save_records.size(), &"fixture_scope": &"local_unit_fixture_only_not_native_os_input_evidence", }