oscura 0.5.0__py3-none-any.whl → 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (513) hide show
  1. oscura/__init__.py +169 -167
  2. oscura/analyzers/__init__.py +3 -0
  3. oscura/analyzers/classification.py +659 -0
  4. oscura/analyzers/digital/__init__.py +0 -48
  5. oscura/analyzers/digital/edges.py +325 -65
  6. oscura/analyzers/digital/extraction.py +0 -195
  7. oscura/analyzers/digital/quality.py +293 -166
  8. oscura/analyzers/digital/timing.py +260 -115
  9. oscura/analyzers/digital/timing_numba.py +334 -0
  10. oscura/analyzers/entropy.py +605 -0
  11. oscura/analyzers/eye/diagram.py +176 -109
  12. oscura/analyzers/eye/metrics.py +5 -5
  13. oscura/analyzers/jitter/__init__.py +6 -4
  14. oscura/analyzers/jitter/ber.py +52 -52
  15. oscura/analyzers/jitter/classification.py +156 -0
  16. oscura/analyzers/jitter/decomposition.py +163 -113
  17. oscura/analyzers/jitter/spectrum.py +80 -64
  18. oscura/analyzers/ml/__init__.py +39 -0
  19. oscura/analyzers/ml/features.py +600 -0
  20. oscura/analyzers/ml/signal_classifier.py +604 -0
  21. oscura/analyzers/packet/daq.py +246 -158
  22. oscura/analyzers/packet/parser.py +12 -1
  23. oscura/analyzers/packet/payload.py +50 -2110
  24. oscura/analyzers/packet/payload_analysis.py +361 -181
  25. oscura/analyzers/packet/payload_patterns.py +133 -70
  26. oscura/analyzers/packet/stream.py +84 -23
  27. oscura/analyzers/patterns/__init__.py +26 -5
  28. oscura/analyzers/patterns/anomaly_detection.py +908 -0
  29. oscura/analyzers/patterns/clustering.py +169 -108
  30. oscura/analyzers/patterns/clustering_optimized.py +227 -0
  31. oscura/analyzers/patterns/discovery.py +1 -1
  32. oscura/analyzers/patterns/matching.py +581 -197
  33. oscura/analyzers/patterns/pattern_mining.py +778 -0
  34. oscura/analyzers/patterns/periodic.py +121 -38
  35. oscura/analyzers/patterns/sequences.py +175 -78
  36. oscura/analyzers/power/conduction.py +1 -1
  37. oscura/analyzers/power/soa.py +6 -6
  38. oscura/analyzers/power/switching.py +250 -110
  39. oscura/analyzers/protocol/__init__.py +17 -1
  40. oscura/analyzers/protocols/__init__.py +1 -22
  41. oscura/analyzers/protocols/base.py +6 -6
  42. oscura/analyzers/protocols/ble/__init__.py +38 -0
  43. oscura/analyzers/protocols/ble/analyzer.py +809 -0
  44. oscura/analyzers/protocols/ble/uuids.py +288 -0
  45. oscura/analyzers/protocols/can.py +257 -127
  46. oscura/analyzers/protocols/can_fd.py +107 -80
  47. oscura/analyzers/protocols/flexray.py +139 -80
  48. oscura/analyzers/protocols/hdlc.py +93 -58
  49. oscura/analyzers/protocols/i2c.py +247 -106
  50. oscura/analyzers/protocols/i2s.py +138 -86
  51. oscura/analyzers/protocols/industrial/__init__.py +40 -0
  52. oscura/analyzers/protocols/industrial/bacnet/__init__.py +33 -0
  53. oscura/analyzers/protocols/industrial/bacnet/analyzer.py +708 -0
  54. oscura/analyzers/protocols/industrial/bacnet/encoding.py +412 -0
  55. oscura/analyzers/protocols/industrial/bacnet/services.py +622 -0
  56. oscura/analyzers/protocols/industrial/ethercat/__init__.py +30 -0
  57. oscura/analyzers/protocols/industrial/ethercat/analyzer.py +474 -0
  58. oscura/analyzers/protocols/industrial/ethercat/mailbox.py +339 -0
  59. oscura/analyzers/protocols/industrial/ethercat/topology.py +166 -0
  60. oscura/analyzers/protocols/industrial/modbus/__init__.py +31 -0
  61. oscura/analyzers/protocols/industrial/modbus/analyzer.py +525 -0
  62. oscura/analyzers/protocols/industrial/modbus/crc.py +79 -0
  63. oscura/analyzers/protocols/industrial/modbus/functions.py +436 -0
  64. oscura/analyzers/protocols/industrial/opcua/__init__.py +21 -0
  65. oscura/analyzers/protocols/industrial/opcua/analyzer.py +552 -0
  66. oscura/analyzers/protocols/industrial/opcua/datatypes.py +446 -0
  67. oscura/analyzers/protocols/industrial/opcua/services.py +264 -0
  68. oscura/analyzers/protocols/industrial/profinet/__init__.py +23 -0
  69. oscura/analyzers/protocols/industrial/profinet/analyzer.py +441 -0
  70. oscura/analyzers/protocols/industrial/profinet/dcp.py +263 -0
  71. oscura/analyzers/protocols/industrial/profinet/ptcp.py +200 -0
  72. oscura/analyzers/protocols/jtag.py +180 -98
  73. oscura/analyzers/protocols/lin.py +219 -114
  74. oscura/analyzers/protocols/manchester.py +4 -4
  75. oscura/analyzers/protocols/onewire.py +253 -149
  76. oscura/analyzers/protocols/parallel_bus/__init__.py +20 -0
  77. oscura/analyzers/protocols/parallel_bus/centronics.py +92 -0
  78. oscura/analyzers/protocols/parallel_bus/gpib.py +137 -0
  79. oscura/analyzers/protocols/spi.py +192 -95
  80. oscura/analyzers/protocols/swd.py +321 -167
  81. oscura/analyzers/protocols/uart.py +267 -125
  82. oscura/analyzers/protocols/usb.py +235 -131
  83. oscura/analyzers/side_channel/power.py +17 -12
  84. oscura/analyzers/signal/__init__.py +15 -0
  85. oscura/analyzers/signal/timing_analysis.py +1086 -0
  86. oscura/analyzers/signal_integrity/__init__.py +4 -1
  87. oscura/analyzers/signal_integrity/sparams.py +2 -19
  88. oscura/analyzers/spectral/chunked.py +129 -60
  89. oscura/analyzers/spectral/chunked_fft.py +300 -94
  90. oscura/analyzers/spectral/chunked_wavelet.py +100 -80
  91. oscura/analyzers/statistical/checksum.py +376 -217
  92. oscura/analyzers/statistical/classification.py +229 -107
  93. oscura/analyzers/statistical/entropy.py +78 -53
  94. oscura/analyzers/statistics/correlation.py +407 -211
  95. oscura/analyzers/statistics/outliers.py +2 -2
  96. oscura/analyzers/statistics/streaming.py +30 -5
  97. oscura/analyzers/validation.py +216 -101
  98. oscura/analyzers/waveform/measurements.py +9 -0
  99. oscura/analyzers/waveform/measurements_with_uncertainty.py +31 -15
  100. oscura/analyzers/waveform/spectral.py +500 -228
  101. oscura/api/__init__.py +31 -5
  102. oscura/api/dsl/__init__.py +582 -0
  103. oscura/{dsl → api/dsl}/commands.py +43 -76
  104. oscura/{dsl → api/dsl}/interpreter.py +26 -51
  105. oscura/{dsl → api/dsl}/parser.py +107 -77
  106. oscura/{dsl → api/dsl}/repl.py +2 -2
  107. oscura/api/dsl.py +1 -1
  108. oscura/{integrations → api/integrations}/__init__.py +1 -1
  109. oscura/{integrations → api/integrations}/llm.py +201 -102
  110. oscura/api/operators.py +3 -3
  111. oscura/api/optimization.py +144 -30
  112. oscura/api/rest_server.py +921 -0
  113. oscura/api/server/__init__.py +17 -0
  114. oscura/api/server/dashboard.py +850 -0
  115. oscura/api/server/static/README.md +34 -0
  116. oscura/api/server/templates/base.html +181 -0
  117. oscura/api/server/templates/export.html +120 -0
  118. oscura/api/server/templates/home.html +284 -0
  119. oscura/api/server/templates/protocols.html +58 -0
  120. oscura/api/server/templates/reports.html +43 -0
  121. oscura/api/server/templates/session_detail.html +89 -0
  122. oscura/api/server/templates/sessions.html +83 -0
  123. oscura/api/server/templates/waveforms.html +73 -0
  124. oscura/automotive/__init__.py +8 -1
  125. oscura/automotive/can/__init__.py +10 -0
  126. oscura/automotive/can/checksum.py +3 -1
  127. oscura/automotive/can/dbc_generator.py +590 -0
  128. oscura/automotive/can/message_wrapper.py +121 -74
  129. oscura/automotive/can/patterns.py +98 -21
  130. oscura/automotive/can/session.py +292 -56
  131. oscura/automotive/can/state_machine.py +6 -3
  132. oscura/automotive/can/stimulus_response.py +97 -75
  133. oscura/automotive/dbc/__init__.py +10 -2
  134. oscura/automotive/dbc/generator.py +84 -56
  135. oscura/automotive/dbc/parser.py +6 -6
  136. oscura/automotive/dtc/data.json +2763 -0
  137. oscura/automotive/dtc/database.py +2 -2
  138. oscura/automotive/flexray/__init__.py +31 -0
  139. oscura/automotive/flexray/analyzer.py +504 -0
  140. oscura/automotive/flexray/crc.py +185 -0
  141. oscura/automotive/flexray/fibex.py +449 -0
  142. oscura/automotive/j1939/__init__.py +45 -8
  143. oscura/automotive/j1939/analyzer.py +605 -0
  144. oscura/automotive/j1939/spns.py +326 -0
  145. oscura/automotive/j1939/transport.py +306 -0
  146. oscura/automotive/lin/__init__.py +47 -0
  147. oscura/automotive/lin/analyzer.py +612 -0
  148. oscura/automotive/loaders/blf.py +13 -2
  149. oscura/automotive/loaders/csv_can.py +143 -72
  150. oscura/automotive/loaders/dispatcher.py +50 -2
  151. oscura/automotive/loaders/mdf.py +86 -45
  152. oscura/automotive/loaders/pcap.py +111 -61
  153. oscura/automotive/uds/__init__.py +4 -0
  154. oscura/automotive/uds/analyzer.py +725 -0
  155. oscura/automotive/uds/decoder.py +140 -58
  156. oscura/automotive/uds/models.py +7 -1
  157. oscura/automotive/visualization.py +1 -1
  158. oscura/cli/analyze.py +348 -0
  159. oscura/cli/batch.py +142 -122
  160. oscura/cli/benchmark.py +275 -0
  161. oscura/cli/characterize.py +137 -82
  162. oscura/cli/compare.py +224 -131
  163. oscura/cli/completion.py +250 -0
  164. oscura/cli/config_cmd.py +361 -0
  165. oscura/cli/decode.py +164 -87
  166. oscura/cli/export.py +286 -0
  167. oscura/cli/main.py +115 -31
  168. oscura/{onboarding → cli/onboarding}/__init__.py +3 -3
  169. oscura/{onboarding → cli/onboarding}/help.py +80 -58
  170. oscura/{onboarding → cli/onboarding}/tutorials.py +97 -72
  171. oscura/{onboarding → cli/onboarding}/wizard.py +55 -36
  172. oscura/cli/progress.py +147 -0
  173. oscura/cli/shell.py +157 -135
  174. oscura/cli/validate_cmd.py +204 -0
  175. oscura/cli/visualize.py +158 -0
  176. oscura/convenience.py +125 -79
  177. oscura/core/__init__.py +4 -2
  178. oscura/core/backend_selector.py +3 -3
  179. oscura/core/cache.py +126 -15
  180. oscura/core/cancellation.py +1 -1
  181. oscura/{config → core/config}/__init__.py +20 -11
  182. oscura/{config → core/config}/defaults.py +1 -1
  183. oscura/{config → core/config}/loader.py +7 -5
  184. oscura/{config → core/config}/memory.py +5 -5
  185. oscura/{config → core/config}/migration.py +1 -1
  186. oscura/{config → core/config}/pipeline.py +99 -23
  187. oscura/{config → core/config}/preferences.py +1 -1
  188. oscura/{config → core/config}/protocol.py +3 -3
  189. oscura/{config → core/config}/schema.py +426 -272
  190. oscura/{config → core/config}/settings.py +1 -1
  191. oscura/{config → core/config}/thresholds.py +195 -153
  192. oscura/core/correlation.py +5 -6
  193. oscura/core/cross_domain.py +0 -2
  194. oscura/core/debug.py +9 -5
  195. oscura/{extensibility → core/extensibility}/docs.py +158 -70
  196. oscura/{extensibility → core/extensibility}/extensions.py +160 -76
  197. oscura/{extensibility → core/extensibility}/logging.py +1 -1
  198. oscura/{extensibility → core/extensibility}/measurements.py +1 -1
  199. oscura/{extensibility → core/extensibility}/plugins.py +1 -1
  200. oscura/{extensibility → core/extensibility}/templates.py +73 -3
  201. oscura/{extensibility → core/extensibility}/validation.py +1 -1
  202. oscura/core/gpu_backend.py +11 -7
  203. oscura/core/log_query.py +101 -11
  204. oscura/core/logging.py +126 -54
  205. oscura/core/logging_advanced.py +5 -5
  206. oscura/core/memory_limits.py +108 -70
  207. oscura/core/memory_monitor.py +2 -2
  208. oscura/core/memory_progress.py +7 -7
  209. oscura/core/memory_warnings.py +1 -1
  210. oscura/core/numba_backend.py +13 -13
  211. oscura/{plugins → core/plugins}/__init__.py +9 -9
  212. oscura/{plugins → core/plugins}/base.py +7 -7
  213. oscura/{plugins → core/plugins}/cli.py +3 -3
  214. oscura/{plugins → core/plugins}/discovery.py +186 -106
  215. oscura/{plugins → core/plugins}/lifecycle.py +1 -1
  216. oscura/{plugins → core/plugins}/manager.py +7 -7
  217. oscura/{plugins → core/plugins}/registry.py +3 -3
  218. oscura/{plugins → core/plugins}/versioning.py +1 -1
  219. oscura/core/progress.py +16 -1
  220. oscura/core/provenance.py +8 -2
  221. oscura/{schemas → core/schemas}/__init__.py +2 -2
  222. oscura/core/schemas/bus_configuration.json +322 -0
  223. oscura/core/schemas/device_mapping.json +182 -0
  224. oscura/core/schemas/packet_format.json +418 -0
  225. oscura/core/schemas/protocol_definition.json +363 -0
  226. oscura/core/types.py +4 -0
  227. oscura/core/uncertainty.py +3 -3
  228. oscura/correlation/__init__.py +52 -0
  229. oscura/correlation/multi_protocol.py +811 -0
  230. oscura/discovery/auto_decoder.py +117 -35
  231. oscura/discovery/comparison.py +191 -86
  232. oscura/discovery/quality_validator.py +155 -68
  233. oscura/discovery/signal_detector.py +196 -79
  234. oscura/export/__init__.py +18 -20
  235. oscura/export/kaitai_struct.py +513 -0
  236. oscura/export/scapy_layer.py +801 -0
  237. oscura/export/wireshark/README.md +15 -15
  238. oscura/export/wireshark/generator.py +1 -1
  239. oscura/export/wireshark/templates/dissector.lua.j2 +2 -2
  240. oscura/export/wireshark_dissector.py +746 -0
  241. oscura/guidance/wizard.py +207 -111
  242. oscura/hardware/__init__.py +19 -0
  243. oscura/{acquisition → hardware/acquisition}/__init__.py +4 -4
  244. oscura/{acquisition → hardware/acquisition}/file.py +2 -2
  245. oscura/{acquisition → hardware/acquisition}/hardware.py +7 -7
  246. oscura/{acquisition → hardware/acquisition}/saleae.py +15 -12
  247. oscura/{acquisition → hardware/acquisition}/socketcan.py +1 -1
  248. oscura/{acquisition → hardware/acquisition}/streaming.py +2 -2
  249. oscura/{acquisition → hardware/acquisition}/synthetic.py +3 -3
  250. oscura/{acquisition → hardware/acquisition}/visa.py +33 -11
  251. oscura/hardware/firmware/__init__.py +29 -0
  252. oscura/hardware/firmware/pattern_recognition.py +874 -0
  253. oscura/hardware/hal_detector.py +736 -0
  254. oscura/hardware/security/__init__.py +37 -0
  255. oscura/hardware/security/side_channel_detector.py +1126 -0
  256. oscura/inference/__init__.py +4 -0
  257. oscura/inference/active_learning/README.md +7 -7
  258. oscura/inference/active_learning/observation_table.py +4 -1
  259. oscura/inference/alignment.py +216 -123
  260. oscura/inference/bayesian.py +113 -33
  261. oscura/inference/crc_reverse.py +101 -55
  262. oscura/inference/logic.py +6 -2
  263. oscura/inference/message_format.py +342 -183
  264. oscura/inference/protocol.py +95 -44
  265. oscura/inference/protocol_dsl.py +180 -82
  266. oscura/inference/signal_intelligence.py +1439 -706
  267. oscura/inference/spectral.py +99 -57
  268. oscura/inference/state_machine.py +810 -158
  269. oscura/inference/stream.py +270 -110
  270. oscura/iot/__init__.py +34 -0
  271. oscura/iot/coap/__init__.py +32 -0
  272. oscura/iot/coap/analyzer.py +668 -0
  273. oscura/iot/coap/options.py +212 -0
  274. oscura/iot/lorawan/__init__.py +21 -0
  275. oscura/iot/lorawan/crypto.py +206 -0
  276. oscura/iot/lorawan/decoder.py +801 -0
  277. oscura/iot/lorawan/mac_commands.py +341 -0
  278. oscura/iot/mqtt/__init__.py +27 -0
  279. oscura/iot/mqtt/analyzer.py +999 -0
  280. oscura/iot/mqtt/properties.py +315 -0
  281. oscura/iot/zigbee/__init__.py +31 -0
  282. oscura/iot/zigbee/analyzer.py +615 -0
  283. oscura/iot/zigbee/security.py +153 -0
  284. oscura/iot/zigbee/zcl.py +349 -0
  285. oscura/jupyter/display.py +125 -45
  286. oscura/{exploratory → jupyter/exploratory}/__init__.py +8 -8
  287. oscura/{exploratory → jupyter/exploratory}/error_recovery.py +298 -141
  288. oscura/jupyter/exploratory/fuzzy.py +746 -0
  289. oscura/{exploratory → jupyter/exploratory}/fuzzy_advanced.py +258 -100
  290. oscura/{exploratory → jupyter/exploratory}/legacy.py +464 -242
  291. oscura/{exploratory → jupyter/exploratory}/parse.py +167 -145
  292. oscura/{exploratory → jupyter/exploratory}/recovery.py +119 -87
  293. oscura/jupyter/exploratory/sync.py +612 -0
  294. oscura/{exploratory → jupyter/exploratory}/unknown.py +299 -176
  295. oscura/jupyter/magic.py +4 -4
  296. oscura/{ui → jupyter/ui}/__init__.py +2 -2
  297. oscura/{ui → jupyter/ui}/formatters.py +3 -3
  298. oscura/{ui → jupyter/ui}/progressive_display.py +153 -82
  299. oscura/loaders/__init__.py +171 -63
  300. oscura/loaders/binary.py +88 -1
  301. oscura/loaders/chipwhisperer.py +153 -137
  302. oscura/loaders/configurable.py +208 -86
  303. oscura/loaders/csv_loader.py +458 -215
  304. oscura/loaders/hdf5_loader.py +278 -119
  305. oscura/loaders/lazy.py +87 -54
  306. oscura/loaders/mmap_loader.py +1 -1
  307. oscura/loaders/numpy_loader.py +253 -116
  308. oscura/loaders/pcap.py +226 -151
  309. oscura/loaders/rigol.py +110 -49
  310. oscura/loaders/sigrok.py +201 -78
  311. oscura/loaders/tdms.py +81 -58
  312. oscura/loaders/tektronix.py +291 -174
  313. oscura/loaders/touchstone.py +182 -87
  314. oscura/loaders/vcd.py +215 -117
  315. oscura/loaders/wav.py +155 -68
  316. oscura/reporting/__init__.py +9 -7
  317. oscura/reporting/analyze.py +352 -146
  318. oscura/reporting/argument_preparer.py +69 -14
  319. oscura/reporting/auto_report.py +97 -61
  320. oscura/reporting/batch.py +131 -58
  321. oscura/reporting/chart_selection.py +57 -45
  322. oscura/reporting/comparison.py +63 -17
  323. oscura/reporting/content/executive.py +76 -24
  324. oscura/reporting/core_formats/multi_format.py +11 -8
  325. oscura/reporting/engine.py +312 -158
  326. oscura/reporting/enhanced_reports.py +949 -0
  327. oscura/reporting/export.py +86 -43
  328. oscura/reporting/formatting/numbers.py +69 -42
  329. oscura/reporting/html.py +139 -58
  330. oscura/reporting/index.py +137 -65
  331. oscura/reporting/output.py +158 -67
  332. oscura/reporting/pdf.py +67 -102
  333. oscura/reporting/plots.py +191 -112
  334. oscura/reporting/sections.py +88 -47
  335. oscura/reporting/standards.py +104 -61
  336. oscura/reporting/summary_generator.py +75 -55
  337. oscura/reporting/tables.py +138 -54
  338. oscura/reporting/templates/enhanced/protocol_re.html +525 -0
  339. oscura/reporting/templates/index.md +13 -13
  340. oscura/sessions/__init__.py +14 -23
  341. oscura/sessions/base.py +3 -3
  342. oscura/sessions/blackbox.py +106 -10
  343. oscura/sessions/generic.py +2 -2
  344. oscura/sessions/legacy.py +783 -0
  345. oscura/side_channel/__init__.py +63 -0
  346. oscura/side_channel/dpa.py +1025 -0
  347. oscura/utils/__init__.py +15 -1
  348. oscura/utils/autodetect.py +1 -5
  349. oscura/utils/bitwise.py +118 -0
  350. oscura/{builders → utils/builders}/__init__.py +1 -1
  351. oscura/{comparison → utils/comparison}/__init__.py +6 -6
  352. oscura/{comparison → utils/comparison}/compare.py +202 -101
  353. oscura/{comparison → utils/comparison}/golden.py +83 -63
  354. oscura/{comparison → utils/comparison}/limits.py +313 -89
  355. oscura/{comparison → utils/comparison}/mask.py +151 -45
  356. oscura/{comparison → utils/comparison}/trace_diff.py +1 -1
  357. oscura/{comparison → utils/comparison}/visualization.py +147 -89
  358. oscura/{component → utils/component}/__init__.py +3 -3
  359. oscura/{component → utils/component}/impedance.py +122 -58
  360. oscura/{component → utils/component}/reactive.py +165 -168
  361. oscura/{component → utils/component}/transmission_line.py +3 -3
  362. oscura/{filtering → utils/filtering}/__init__.py +6 -6
  363. oscura/{filtering → utils/filtering}/base.py +1 -1
  364. oscura/{filtering → utils/filtering}/convenience.py +2 -2
  365. oscura/{filtering → utils/filtering}/design.py +169 -93
  366. oscura/{filtering → utils/filtering}/filters.py +2 -2
  367. oscura/{filtering → utils/filtering}/introspection.py +2 -2
  368. oscura/utils/geometry.py +31 -0
  369. oscura/utils/imports.py +184 -0
  370. oscura/utils/lazy.py +1 -1
  371. oscura/{math → utils/math}/__init__.py +2 -2
  372. oscura/{math → utils/math}/arithmetic.py +114 -48
  373. oscura/{math → utils/math}/interpolation.py +139 -106
  374. oscura/utils/memory.py +129 -66
  375. oscura/utils/memory_advanced.py +92 -9
  376. oscura/utils/memory_extensions.py +10 -8
  377. oscura/{optimization → utils/optimization}/__init__.py +1 -1
  378. oscura/{optimization → utils/optimization}/search.py +2 -2
  379. oscura/utils/performance/__init__.py +58 -0
  380. oscura/utils/performance/caching.py +889 -0
  381. oscura/utils/performance/lsh_clustering.py +333 -0
  382. oscura/utils/performance/memory_optimizer.py +699 -0
  383. oscura/utils/performance/optimizations.py +675 -0
  384. oscura/utils/performance/parallel.py +654 -0
  385. oscura/utils/performance/profiling.py +661 -0
  386. oscura/{pipeline → utils/pipeline}/base.py +1 -1
  387. oscura/{pipeline → utils/pipeline}/composition.py +11 -3
  388. oscura/{pipeline → utils/pipeline}/parallel.py +3 -2
  389. oscura/{pipeline → utils/pipeline}/pipeline.py +1 -1
  390. oscura/{pipeline → utils/pipeline}/reverse_engineering.py +412 -221
  391. oscura/{search → utils/search}/__init__.py +3 -3
  392. oscura/{search → utils/search}/anomaly.py +188 -58
  393. oscura/utils/search/context.py +294 -0
  394. oscura/{search → utils/search}/pattern.py +138 -10
  395. oscura/utils/serial.py +51 -0
  396. oscura/utils/storage/__init__.py +61 -0
  397. oscura/utils/storage/database.py +1166 -0
  398. oscura/{streaming → utils/streaming}/chunked.py +302 -143
  399. oscura/{streaming → utils/streaming}/progressive.py +1 -1
  400. oscura/{streaming → utils/streaming}/realtime.py +3 -2
  401. oscura/{triggering → utils/triggering}/__init__.py +6 -6
  402. oscura/{triggering → utils/triggering}/base.py +6 -6
  403. oscura/{triggering → utils/triggering}/edge.py +2 -2
  404. oscura/{triggering → utils/triggering}/pattern.py +2 -2
  405. oscura/{triggering → utils/triggering}/pulse.py +115 -74
  406. oscura/{triggering → utils/triggering}/window.py +2 -2
  407. oscura/utils/validation.py +32 -0
  408. oscura/validation/__init__.py +121 -0
  409. oscura/{compliance → validation/compliance}/__init__.py +5 -5
  410. oscura/{compliance → validation/compliance}/advanced.py +5 -5
  411. oscura/{compliance → validation/compliance}/masks.py +1 -1
  412. oscura/{compliance → validation/compliance}/reporting.py +127 -53
  413. oscura/{compliance → validation/compliance}/testing.py +114 -52
  414. oscura/validation/compliance_tests.py +915 -0
  415. oscura/validation/fuzzer.py +990 -0
  416. oscura/validation/grammar_tests.py +596 -0
  417. oscura/validation/grammar_validator.py +904 -0
  418. oscura/validation/hil_testing.py +977 -0
  419. oscura/{quality → validation/quality}/__init__.py +4 -4
  420. oscura/{quality → validation/quality}/ensemble.py +251 -171
  421. oscura/{quality → validation/quality}/explainer.py +3 -3
  422. oscura/{quality → validation/quality}/scoring.py +1 -1
  423. oscura/{quality → validation/quality}/warnings.py +4 -4
  424. oscura/validation/regression_suite.py +808 -0
  425. oscura/validation/replay.py +788 -0
  426. oscura/{testing → validation/testing}/__init__.py +2 -2
  427. oscura/{testing → validation/testing}/synthetic.py +5 -5
  428. oscura/visualization/__init__.py +9 -0
  429. oscura/visualization/accessibility.py +1 -1
  430. oscura/visualization/annotations.py +64 -67
  431. oscura/visualization/colors.py +7 -7
  432. oscura/visualization/digital.py +180 -81
  433. oscura/visualization/eye.py +236 -85
  434. oscura/visualization/interactive.py +320 -143
  435. oscura/visualization/jitter.py +587 -247
  436. oscura/visualization/layout.py +169 -134
  437. oscura/visualization/optimization.py +103 -52
  438. oscura/visualization/palettes.py +1 -1
  439. oscura/visualization/power.py +427 -211
  440. oscura/visualization/power_extended.py +626 -297
  441. oscura/visualization/presets.py +2 -0
  442. oscura/visualization/protocols.py +495 -181
  443. oscura/visualization/render.py +79 -63
  444. oscura/visualization/reverse_engineering.py +171 -124
  445. oscura/visualization/signal_integrity.py +460 -279
  446. oscura/visualization/specialized.py +190 -100
  447. oscura/visualization/spectral.py +670 -255
  448. oscura/visualization/thumbnails.py +166 -137
  449. oscura/visualization/waveform.py +150 -63
  450. oscura/workflows/__init__.py +3 -0
  451. oscura/{batch → workflows/batch}/__init__.py +5 -5
  452. oscura/{batch → workflows/batch}/advanced.py +150 -75
  453. oscura/workflows/batch/aggregate.py +531 -0
  454. oscura/workflows/batch/analyze.py +236 -0
  455. oscura/{batch → workflows/batch}/logging.py +2 -2
  456. oscura/{batch → workflows/batch}/metrics.py +1 -1
  457. oscura/workflows/complete_re.py +1144 -0
  458. oscura/workflows/compliance.py +44 -54
  459. oscura/workflows/digital.py +197 -51
  460. oscura/workflows/legacy/__init__.py +12 -0
  461. oscura/{workflow → workflows/legacy}/dag.py +4 -1
  462. oscura/workflows/multi_trace.py +9 -9
  463. oscura/workflows/power.py +42 -62
  464. oscura/workflows/protocol.py +82 -49
  465. oscura/workflows/reverse_engineering.py +351 -150
  466. oscura/workflows/signal_integrity.py +157 -82
  467. oscura-0.6.0.dist-info/METADATA +643 -0
  468. oscura-0.6.0.dist-info/RECORD +590 -0
  469. oscura/analyzers/digital/ic_database.py +0 -498
  470. oscura/analyzers/digital/timing_paths.py +0 -339
  471. oscura/analyzers/digital/vintage.py +0 -377
  472. oscura/analyzers/digital/vintage_result.py +0 -148
  473. oscura/analyzers/protocols/parallel_bus.py +0 -449
  474. oscura/batch/aggregate.py +0 -300
  475. oscura/batch/analyze.py +0 -139
  476. oscura/dsl/__init__.py +0 -73
  477. oscura/exceptions.py +0 -59
  478. oscura/exploratory/fuzzy.py +0 -513
  479. oscura/exploratory/sync.py +0 -384
  480. oscura/export/wavedrom.py +0 -430
  481. oscura/exporters/__init__.py +0 -94
  482. oscura/exporters/csv.py +0 -303
  483. oscura/exporters/exporters.py +0 -44
  484. oscura/exporters/hdf5.py +0 -217
  485. oscura/exporters/html_export.py +0 -701
  486. oscura/exporters/json_export.py +0 -338
  487. oscura/exporters/markdown_export.py +0 -367
  488. oscura/exporters/matlab_export.py +0 -354
  489. oscura/exporters/npz_export.py +0 -219
  490. oscura/exporters/spice_export.py +0 -210
  491. oscura/exporters/vintage_logic_csv.py +0 -247
  492. oscura/reporting/vintage_logic_report.py +0 -523
  493. oscura/search/context.py +0 -149
  494. oscura/session/__init__.py +0 -34
  495. oscura/session/annotations.py +0 -289
  496. oscura/session/history.py +0 -313
  497. oscura/session/session.py +0 -520
  498. oscura/visualization/digital_advanced.py +0 -718
  499. oscura/visualization/figure_manager.py +0 -156
  500. oscura/workflow/__init__.py +0 -13
  501. oscura-0.5.0.dist-info/METADATA +0 -407
  502. oscura-0.5.0.dist-info/RECORD +0 -486
  503. /oscura/core/{config.py → config/legacy.py} +0 -0
  504. /oscura/{extensibility → core/extensibility}/__init__.py +0 -0
  505. /oscura/{extensibility → core/extensibility}/registry.py +0 -0
  506. /oscura/{plugins → core/plugins}/isolation.py +0 -0
  507. /oscura/{builders → utils/builders}/signal_builder.py +0 -0
  508. /oscura/{optimization → utils/optimization}/parallel.py +0 -0
  509. /oscura/{pipeline → utils/pipeline}/__init__.py +0 -0
  510. /oscura/{streaming → utils/streaming}/__init__.py +0 -0
  511. {oscura-0.5.0.dist-info → oscura-0.6.0.dist-info}/WHEEL +0 -0
  512. {oscura-0.5.0.dist-info → oscura-0.6.0.dist-info}/entry_points.txt +0 -0
  513. {oscura-0.5.0.dist-info → oscura-0.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -6,7 +6,7 @@ configuration options.
6
6
 
7
7
 
8
8
  Example:
9
- >>> from oscura.config.settings import get_settings, Settings
9
+ >>> from oscura.core.config.settings import get_settings, Settings
10
10
  >>> settings = get_settings()
11
11
  >>> settings.enable_feature("advanced_analysis")
12
12
  >>> if settings.is_feature_enabled("advanced_analysis"):
@@ -15,7 +15,7 @@ from pathlib import Path
15
15
 
16
16
  import yaml
17
17
 
18
- from oscura.config.schema import validate_against_schema
18
+ from oscura.core.config.schema import validate_against_schema
19
19
  from oscura.core.exceptions import ConfigurationError
20
20
 
21
21
  logger = logging.getLogger(__name__)
@@ -206,129 +206,25 @@ class ThresholdRegistry:
206
206
  # Double-check locking pattern
207
207
  if cls._instance is None:
208
208
  cls._instance = super().__new__(cls)
209
- cls._instance._families = {} # type: ignore[attr-defined]
210
- cls._instance._profiles = {} # type: ignore[attr-defined]
211
- cls._instance._session_overrides = {} # type: ignore[attr-defined]
212
- cls._instance._state_lock = threading.Lock() # type: ignore[attr-defined]
209
+ cls._instance._families = {}
210
+ cls._instance._profiles = {}
211
+ cls._instance._session_overrides = {}
212
+ cls._instance._state_lock = threading.Lock()
213
213
  cls._instance._register_builtins()
214
214
  return cls._instance
215
215
 
216
216
  def _register_builtins(self) -> None:
217
217
  """Register built-in logic family definitions."""
218
- builtins = [
219
- # TTL
220
- LogicFamily(
221
- name="TTL",
222
- VIH=2.0,
223
- VIL=0.8,
224
- VOH=2.4,
225
- VOL=0.4,
226
- VCC=5.0,
227
- description="Standard TTL (74xx series)",
228
- ),
229
- # CMOS variants
230
- LogicFamily(
231
- name="CMOS_5V",
232
- VIH=3.5,
233
- VIL=1.5,
234
- VOH=4.9,
235
- VOL=0.1,
236
- VCC=5.0,
237
- description="CMOS 5V (74HCxx series)",
238
- ),
239
- LogicFamily(
240
- name="LVTTL_3V3",
241
- VIH=2.0,
242
- VIL=0.8,
243
- VOH=2.4,
244
- VOL=0.4,
245
- VCC=3.3,
246
- description="Low Voltage TTL 3.3V",
247
- ),
248
- LogicFamily(
249
- name="LVCMOS_3V3",
250
- VIH=2.0,
251
- VIL=0.7,
252
- VOH=2.4,
253
- VOL=0.4,
254
- VCC=3.3,
255
- description="Low Voltage CMOS 3.3V",
256
- ),
257
- LogicFamily(
258
- name="LVCMOS_2V5",
259
- VIH=1.7,
260
- VIL=0.7,
261
- VOH=2.0,
262
- VOL=0.4,
263
- VCC=2.5,
264
- description="Low Voltage CMOS 2.5V",
265
- ),
266
- LogicFamily(
267
- name="LVCMOS_1V8",
268
- VIH=1.17,
269
- VIL=0.63,
270
- VOH=1.35,
271
- VOL=0.45,
272
- VCC=1.8,
273
- description="Low Voltage CMOS 1.8V",
274
- ),
275
- LogicFamily(
276
- name="LVCMOS_1V5",
277
- VIH=0.975,
278
- VIL=0.525,
279
- VOH=1.125,
280
- VOL=0.375,
281
- VCC=1.5,
282
- description="Low Voltage CMOS 1.5V",
283
- ),
284
- LogicFamily(
285
- name="LVCMOS_1V2",
286
- VIH=0.84, # 0.7 * 1.2
287
- VIL=0.36, # 0.3 * 1.2
288
- VOH=1.1,
289
- VOL=0.1,
290
- VCC=1.2,
291
- description="Low Voltage CMOS 1.2V",
292
- ),
293
- # ECL
294
- LogicFamily(
295
- name="ECL",
296
- VIH=-0.9,
297
- VIL=-1.7,
298
- VOH=-0.9,
299
- VOL=-1.75,
300
- VCC=-5.2,
301
- description="Emitter-Coupled Logic (ECL 10K)",
302
- ),
303
- ]
218
+ builtins = _get_builtin_logic_families()
304
219
 
305
220
  for family in builtins:
306
- self._families[family.name] = family # type: ignore[attr-defined]
221
+ self._families[family.name] = family
307
222
 
308
223
  # Built-in profiles
309
- builtin_profiles = [
310
- ThresholdProfile(
311
- name="strict",
312
- base_family="TTL",
313
- tolerance=0,
314
- description="Exact specification values",
315
- ),
316
- ThresholdProfile(
317
- name="relaxed",
318
- base_family="TTL",
319
- tolerance=20,
320
- description="20% tolerance for real-world signals",
321
- ),
322
- ThresholdProfile(
323
- name="auto",
324
- base_family="TTL",
325
- tolerance=10,
326
- description="Auto-adjusted based on signal confidence",
327
- ),
328
- ]
224
+ builtin_profiles = _get_builtin_profiles()
329
225
 
330
226
  for profile in builtin_profiles:
331
- self._profiles[profile.name] = profile # type: ignore[attr-defined]
227
+ self._profiles[profile.name] = profile
332
228
 
333
229
  def get_family(self, name: str) -> LogicFamily:
334
230
  """Get logic family by name.
@@ -342,32 +238,56 @@ class ThresholdRegistry:
342
238
  Raises:
343
239
  KeyError: If family not found
344
240
  """
345
- with self._state_lock: # type: ignore[attr-defined]
346
- # Try exact match first
347
- if name in self._families: # type: ignore[attr-defined]
348
- family = self._families[name] # type: ignore[attr-defined]
349
- # Try case-insensitive match
350
- elif name.upper() in self._families: # type: ignore[attr-defined]
351
- family = self._families[name.upper()] # type: ignore[attr-defined]
352
- else:
353
- available = list(self._families.keys()) # type: ignore[attr-defined]
354
- raise KeyError(f"Logic family '{name}' not found. Available: {available}")
355
-
356
- # Apply session overrides
357
- if self._session_overrides: # type: ignore[attr-defined]
358
- return LogicFamily(
359
- name=family.name,
360
- VIH=self._session_overrides.get("VIH", family.VIH), # type: ignore[attr-defined]
361
- VIL=self._session_overrides.get("VIL", family.VIL), # type: ignore[attr-defined]
362
- VOH=self._session_overrides.get("VOH", family.VOH), # type: ignore[attr-defined]
363
- VOL=self._session_overrides.get("VOL", family.VOL), # type: ignore[attr-defined]
364
- VCC=self._session_overrides.get("VCC", family.VCC), # type: ignore[attr-defined]
365
- description=family.description,
366
- temperature_range=family.temperature_range,
367
- source="override",
368
- )
241
+ with self._state_lock:
242
+ family = self._lookup_family(name)
243
+ return self._apply_overrides_if_needed(family)
244
+
245
+ def _lookup_family(self, name: str) -> LogicFamily:
246
+ """Look up family by name (exact or case-insensitive).
247
+
248
+ Args:
249
+ name: Family name to look up.
250
+
251
+ Returns:
252
+ Logic family definition.
253
+
254
+ Raises:
255
+ KeyError: If family not found.
256
+ """
257
+ # Try exact match first
258
+ if name in self._families:
259
+ return self._families[name]
260
+
261
+ # Try case-insensitive match
262
+ if name.upper() in self._families:
263
+ return self._families[name.upper()]
264
+
265
+ available = list(self._families.keys())
266
+ raise KeyError(f"Logic family '{name}' not found. Available: {available}")
267
+
268
+ def _apply_overrides_if_needed(self, family: LogicFamily) -> LogicFamily:
269
+ """Apply session overrides to family if configured.
270
+
271
+ Args:
272
+ family: Base family.
369
273
 
370
- return family # type: ignore[no-any-return]
274
+ Returns:
275
+ Family with overrides applied, or original if no overrides.
276
+ """
277
+ if not self._session_overrides:
278
+ return family
279
+
280
+ return LogicFamily(
281
+ name=family.name,
282
+ VIH=self._session_overrides.get("VIH", family.VIH),
283
+ VIL=self._session_overrides.get("VIL", family.VIL),
284
+ VOH=self._session_overrides.get("VOH", family.VOH),
285
+ VOL=self._session_overrides.get("VOL", family.VOL),
286
+ VCC=self._session_overrides.get("VCC", family.VCC),
287
+ description=family.description,
288
+ temperature_range=family.temperature_range,
289
+ source="override",
290
+ )
371
291
 
372
292
  def list_families(self) -> list[str]:
373
293
  """List all available logic families.
@@ -375,8 +295,8 @@ class ThresholdRegistry:
375
295
  Returns:
376
296
  List of family names
377
297
  """
378
- with self._state_lock: # type: ignore[attr-defined]
379
- return sorted(self._families.keys()) # type: ignore[attr-defined]
298
+ with self._state_lock:
299
+ return sorted(self._families.keys())
380
300
 
381
301
  def register_family(self, family: LogicFamily, *, namespace: str = "user") -> None:
382
302
  """Register custom logic family.
@@ -390,7 +310,7 @@ class ThresholdRegistry:
390
310
  >>> registry.register_family(custom)
391
311
  >>> # Available as "user.my_custom"
392
312
  """
393
- with self._state_lock: # type: ignore[attr-defined]
313
+ with self._state_lock:
394
314
  # Namespace custom families
395
315
  if namespace and not family.name.startswith(f"{namespace}."):
396
316
  name = f"{namespace}.{family.name}"
@@ -410,7 +330,7 @@ class ThresholdRegistry:
410
330
  source=family.source,
411
331
  )
412
332
 
413
- self._families[name] = family # type: ignore[attr-defined]
333
+ self._families[name] = family
414
334
  logger.info(f"Registered custom logic family: {name}")
415
335
 
416
336
  def set_threshold_override(self, **kwargs: float) -> None:
@@ -428,20 +348,20 @@ class ThresholdRegistry:
428
348
  >>> registry.set_threshold_override(VIH=2.5, VIL=0.7)
429
349
  """
430
350
  valid_keys = {"VIH", "VIL", "VOH", "VOL", "VCC"}
431
- with self._state_lock: # type: ignore[attr-defined]
351
+ with self._state_lock:
432
352
  for key, value in kwargs.items():
433
353
  if key not in valid_keys:
434
354
  raise ValueError(f"Invalid threshold key: {key}. Valid: {valid_keys}")
435
355
  if not 0.0 <= value <= 10.0:
436
356
  raise ValueError(f"Threshold {key}={value}V out of range (0-10V)")
437
- self._session_overrides[key] = value # type: ignore[attr-defined]
357
+ self._session_overrides[key] = value
438
358
 
439
359
  logger.info(f"Set threshold overrides: {kwargs}")
440
360
 
441
361
  def reset_overrides(self) -> None:
442
362
  """Reset session threshold overrides."""
443
- with self._state_lock: # type: ignore[attr-defined]
444
- self._session_overrides.clear() # type: ignore[attr-defined]
363
+ with self._state_lock:
364
+ self._session_overrides.clear()
445
365
  logger.info("Reset threshold overrides")
446
366
 
447
367
  def get_profile(self, name: str) -> ThresholdProfile:
@@ -456,12 +376,12 @@ class ThresholdRegistry:
456
376
  Raises:
457
377
  KeyError: If profile not found.
458
378
  """
459
- with self._state_lock: # type: ignore[attr-defined]
460
- if name not in self._profiles: # type: ignore[attr-defined]
379
+ with self._state_lock:
380
+ if name not in self._profiles:
461
381
  raise KeyError(
462
382
  f"Profile '{name}' not found. Available: {list(self._profiles.keys())}"
463
- ) # type: ignore[attr-defined]
464
- return self._profiles[name] # type: ignore[no-any-return, attr-defined]
383
+ )
384
+ return self._profiles[name]
465
385
 
466
386
  def apply_profile(self, name: str) -> LogicFamily:
467
387
  """Apply a threshold profile.
@@ -490,14 +410,14 @@ class ThresholdRegistry:
490
410
  >>> registry.set_threshold_override(VIH=2.5)
491
411
  >>> registry.save_profile("my_profile")
492
412
  """
493
- with self._state_lock: # type: ignore[attr-defined]
413
+ with self._state_lock:
494
414
  profile = ThresholdProfile(
495
415
  name=name,
496
416
  base_family=base_family or "TTL",
497
- overrides=dict(self._session_overrides), # type: ignore[attr-defined]
417
+ overrides=dict(self._session_overrides),
498
418
  description=f"User profile {name}",
499
419
  )
500
- self._profiles[name] = profile # type: ignore[attr-defined]
420
+ self._profiles[name] = profile
501
421
 
502
422
  if path:
503
423
  path = Path(path)
@@ -513,6 +433,128 @@ class ThresholdRegistry:
513
433
  logger.info(f"Saved profile to {path}")
514
434
 
515
435
 
436
+ def _get_builtin_logic_families() -> list[LogicFamily]:
437
+ """Get list of built-in logic family definitions.
438
+
439
+ Returns:
440
+ List of standard logic families.
441
+ """
442
+ return [
443
+ # TTL
444
+ LogicFamily(
445
+ name="TTL",
446
+ VIH=2.0,
447
+ VIL=0.8,
448
+ VOH=2.4,
449
+ VOL=0.4,
450
+ VCC=5.0,
451
+ description="Standard TTL (74xx series)",
452
+ ),
453
+ # CMOS variants
454
+ LogicFamily(
455
+ name="CMOS_5V",
456
+ VIH=3.5,
457
+ VIL=1.5,
458
+ VOH=4.9,
459
+ VOL=0.1,
460
+ VCC=5.0,
461
+ description="CMOS 5V (74HCxx series)",
462
+ ),
463
+ LogicFamily(
464
+ name="LVTTL_3V3",
465
+ VIH=2.0,
466
+ VIL=0.8,
467
+ VOH=2.4,
468
+ VOL=0.4,
469
+ VCC=3.3,
470
+ description="Low Voltage TTL 3.3V",
471
+ ),
472
+ LogicFamily(
473
+ name="LVCMOS_3V3",
474
+ VIH=2.0,
475
+ VIL=0.7,
476
+ VOH=2.4,
477
+ VOL=0.4,
478
+ VCC=3.3,
479
+ description="Low Voltage CMOS 3.3V",
480
+ ),
481
+ LogicFamily(
482
+ name="LVCMOS_2V5",
483
+ VIH=1.7,
484
+ VIL=0.7,
485
+ VOH=2.0,
486
+ VOL=0.4,
487
+ VCC=2.5,
488
+ description="Low Voltage CMOS 2.5V",
489
+ ),
490
+ LogicFamily(
491
+ name="LVCMOS_1V8",
492
+ VIH=1.17,
493
+ VIL=0.63,
494
+ VOH=1.35,
495
+ VOL=0.45,
496
+ VCC=1.8,
497
+ description="Low Voltage CMOS 1.8V",
498
+ ),
499
+ LogicFamily(
500
+ name="LVCMOS_1V5",
501
+ VIH=0.975,
502
+ VIL=0.525,
503
+ VOH=1.125,
504
+ VOL=0.375,
505
+ VCC=1.5,
506
+ description="Low Voltage CMOS 1.5V",
507
+ ),
508
+ LogicFamily(
509
+ name="LVCMOS_1V2",
510
+ VIH=0.84, # 0.7 * 1.2
511
+ VIL=0.36, # 0.3 * 1.2
512
+ VOH=1.1,
513
+ VOL=0.1,
514
+ VCC=1.2,
515
+ description="Low Voltage CMOS 1.2V",
516
+ ),
517
+ # ECL
518
+ LogicFamily(
519
+ name="ECL",
520
+ VIH=-0.9,
521
+ VIL=-1.7,
522
+ VOH=-0.9,
523
+ VOL=-1.75,
524
+ VCC=-5.2,
525
+ description="Emitter-Coupled Logic (ECL 10K)",
526
+ ),
527
+ ]
528
+
529
+
530
+ def _get_builtin_profiles() -> list[ThresholdProfile]:
531
+ """Get list of built-in threshold profiles.
532
+
533
+ Returns:
534
+ List of standard threshold profiles.
535
+ """
536
+ return [
537
+ ThresholdProfile(
538
+ name="strict",
539
+ base_family="TTL",
540
+ tolerance=0,
541
+ description="Exact specification values",
542
+ ),
543
+ ThresholdProfile(
544
+ name="relaxed",
545
+ base_family="TTL",
546
+ tolerance=20,
547
+ description="20% tolerance for real-world signals",
548
+ ),
549
+ ThresholdProfile(
550
+ name="auto",
551
+ base_family="TTL",
552
+ tolerance=10,
553
+ description="Auto-adjusted based on signal confidence",
554
+ ),
555
+ ]
556
+
557
+
516
558
  def load_logic_family(path: str | Path) -> LogicFamily:
517
559
  """Load logic family from YAML/JSON file.
518
560
 
@@ -20,8 +20,8 @@ import asyncio
20
20
  import contextvars
21
21
  import functools
22
22
  import uuid
23
- from collections.abc import Callable
24
- from typing import Any, ParamSpec, TypeVar
23
+ from collections.abc import Callable, Coroutine
24
+ from typing import Any, ParamSpec, TypeVar, cast
25
25
 
26
26
  # Context variable for correlation ID (thread-safe and async-safe)
27
27
  _correlation_id: contextvars.ContextVar[str | None] = contextvars.ContextVar(
@@ -180,9 +180,8 @@ def with_correlation_id(
180
180
  async def async_wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
181
181
  with CorrelationContext(corr_id):
182
182
  # func returns a Coroutine, we need to await it
183
- coro = func(*args, **kwargs)
184
- # Type assertion for mypy - we know this is a coroutine
185
- return await coro # type: ignore[misc, no-any-return]
183
+ coro = cast("Coroutine[Any, Any, R]", func(*args, **kwargs))
184
+ return await coro
186
185
 
187
186
  return async_wrapper # type: ignore[return-value]
188
187
  else:
@@ -192,7 +191,7 @@ def with_correlation_id(
192
191
  with CorrelationContext(corr_id):
193
192
  return func(*args, **kwargs)
194
193
 
195
- return sync_wrapper # type: ignore[return-value]
194
+ return sync_wrapper
196
195
 
197
196
  return decorator
198
197
 
@@ -78,8 +78,6 @@ class CorrelationResult:
78
78
  Returns:
79
79
  Coherence score based on agreement/conflict ratio.
80
80
  """
81
- if not self.insights:
82
- return 0.5
83
81
  total = self.agreements_detected + self.conflicts_detected
84
82
  if total == 0:
85
83
  return 0.5
oscura/core/debug.py CHANGED
@@ -5,11 +5,11 @@ verbosity levels for troubleshooting and diagnostics.
5
5
 
6
6
 
7
7
  Example:
8
- >>> from oscura.core.debug import enable_debug, is_debug_enabled, debug_context
8
+ >>> from oscura.core.debug import enable_debug, is_debug_enabled, DebugContext
9
9
  >>> enable_debug(level='verbose')
10
10
  >>> if is_debug_enabled():
11
11
  ... logger.debug("Extra diagnostic information")
12
- >>> with debug_context(level='trace'):
12
+ >>> with DebugContext(level='trace'):
13
13
  ... # Temporarily increase verbosity
14
14
  ... analyze_complex_signal()
15
15
 
@@ -157,7 +157,7 @@ def get_debug_level() -> DebugLevel:
157
157
  return DebugLevel(_debug_level.get())
158
158
 
159
159
 
160
- class debug_context:
160
+ class DebugContext:
161
161
  """Context manager for temporary debug level changes.
162
162
 
163
163
  Temporarily sets a debug level for the duration of a code block,
@@ -168,7 +168,7 @@ class debug_context:
168
168
 
169
169
  Example:
170
170
  >>> # Normal debug level
171
- >>> with debug_context(level='trace'):
171
+ >>> with DebugContext(level='trace'):
172
172
  ... # Temporarily enable trace-level debugging
173
173
  ... analyze_signal(complex_data)
174
174
  >>> # Back to normal debug level
@@ -190,7 +190,7 @@ class debug_context:
190
190
  self.token: contextvars.Token | None = None # type: ignore[type-arg]
191
191
  self.previous_log_level: str | None = None
192
192
 
193
- def __enter__(self) -> debug_context:
193
+ def __enter__(self) -> DebugContext:
194
194
  """Enter the debug context and set new level."""
195
195
  # Save current debug level
196
196
  self.token = _debug_level.set(self.level)
@@ -226,6 +226,10 @@ class debug_context:
226
226
  set_log_level(self.previous_log_level)
227
227
 
228
228
 
229
+ # Backward compatibility alias (deprecated, use DebugContext)
230
+ debug_context = DebugContext
231
+
232
+
229
233
  def should_log_debug(min_level: DebugLevel = DebugLevel.NORMAL) -> bool:
230
234
  """Check if debug logging should occur at specified level.
231
235