tnfr 4.5.2__py3-none-any.whl → 8.5.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.

Potentially problematic release.


This version of tnfr might be problematic. Click here for more details.

Files changed (365) hide show
  1. tnfr/__init__.py +334 -50
  2. tnfr/__init__.pyi +33 -0
  3. tnfr/_compat.py +10 -0
  4. tnfr/_generated_version.py +34 -0
  5. tnfr/_version.py +49 -0
  6. tnfr/_version.pyi +7 -0
  7. tnfr/alias.py +214 -37
  8. tnfr/alias.pyi +108 -0
  9. tnfr/backends/__init__.py +354 -0
  10. tnfr/backends/jax_backend.py +173 -0
  11. tnfr/backends/numpy_backend.py +238 -0
  12. tnfr/backends/optimized_numpy.py +420 -0
  13. tnfr/backends/torch_backend.py +408 -0
  14. tnfr/cache.py +149 -556
  15. tnfr/cache.pyi +13 -0
  16. tnfr/cli/__init__.py +51 -16
  17. tnfr/cli/__init__.pyi +26 -0
  18. tnfr/cli/arguments.py +344 -32
  19. tnfr/cli/arguments.pyi +29 -0
  20. tnfr/cli/execution.py +676 -50
  21. tnfr/cli/execution.pyi +70 -0
  22. tnfr/cli/interactive_validator.py +614 -0
  23. tnfr/cli/utils.py +18 -3
  24. tnfr/cli/utils.pyi +7 -0
  25. tnfr/cli/validate.py +236 -0
  26. tnfr/compat/__init__.py +85 -0
  27. tnfr/compat/dataclass.py +136 -0
  28. tnfr/compat/jsonschema_stub.py +61 -0
  29. tnfr/compat/matplotlib_stub.py +73 -0
  30. tnfr/compat/numpy_stub.py +155 -0
  31. tnfr/config/__init__.py +224 -0
  32. tnfr/config/__init__.pyi +10 -0
  33. tnfr/{constants_glyphs.py → config/constants.py} +26 -20
  34. tnfr/config/constants.pyi +12 -0
  35. tnfr/config/defaults.py +54 -0
  36. tnfr/{constants/core.py → config/defaults_core.py} +59 -6
  37. tnfr/config/defaults_init.py +33 -0
  38. tnfr/config/defaults_metric.py +104 -0
  39. tnfr/config/feature_flags.py +81 -0
  40. tnfr/config/feature_flags.pyi +16 -0
  41. tnfr/config/glyph_constants.py +31 -0
  42. tnfr/config/init.py +77 -0
  43. tnfr/config/init.pyi +8 -0
  44. tnfr/config/operator_names.py +254 -0
  45. tnfr/config/operator_names.pyi +36 -0
  46. tnfr/config/physics_derivation.py +354 -0
  47. tnfr/config/presets.py +83 -0
  48. tnfr/config/presets.pyi +7 -0
  49. tnfr/config/security.py +927 -0
  50. tnfr/config/thresholds.py +114 -0
  51. tnfr/config/tnfr_config.py +498 -0
  52. tnfr/constants/__init__.py +51 -133
  53. tnfr/constants/__init__.pyi +92 -0
  54. tnfr/constants/aliases.py +33 -0
  55. tnfr/constants/aliases.pyi +27 -0
  56. tnfr/constants/init.py +3 -1
  57. tnfr/constants/init.pyi +12 -0
  58. tnfr/constants/metric.py +9 -15
  59. tnfr/constants/metric.pyi +19 -0
  60. tnfr/core/__init__.py +33 -0
  61. tnfr/core/container.py +226 -0
  62. tnfr/core/default_implementations.py +329 -0
  63. tnfr/core/interfaces.py +279 -0
  64. tnfr/dynamics/__init__.py +213 -633
  65. tnfr/dynamics/__init__.pyi +83 -0
  66. tnfr/dynamics/adaptation.py +267 -0
  67. tnfr/dynamics/adaptation.pyi +7 -0
  68. tnfr/dynamics/adaptive_sequences.py +189 -0
  69. tnfr/dynamics/adaptive_sequences.pyi +14 -0
  70. tnfr/dynamics/aliases.py +23 -0
  71. tnfr/dynamics/aliases.pyi +19 -0
  72. tnfr/dynamics/bifurcation.py +232 -0
  73. tnfr/dynamics/canonical.py +229 -0
  74. tnfr/dynamics/canonical.pyi +48 -0
  75. tnfr/dynamics/coordination.py +385 -0
  76. tnfr/dynamics/coordination.pyi +25 -0
  77. tnfr/dynamics/dnfr.py +2699 -398
  78. tnfr/dynamics/dnfr.pyi +26 -0
  79. tnfr/dynamics/dynamic_limits.py +225 -0
  80. tnfr/dynamics/feedback.py +252 -0
  81. tnfr/dynamics/feedback.pyi +24 -0
  82. tnfr/dynamics/fused_dnfr.py +454 -0
  83. tnfr/dynamics/homeostasis.py +157 -0
  84. tnfr/dynamics/homeostasis.pyi +14 -0
  85. tnfr/dynamics/integrators.py +496 -102
  86. tnfr/dynamics/integrators.pyi +36 -0
  87. tnfr/dynamics/learning.py +310 -0
  88. tnfr/dynamics/learning.pyi +33 -0
  89. tnfr/dynamics/metabolism.py +254 -0
  90. tnfr/dynamics/nbody.py +796 -0
  91. tnfr/dynamics/nbody_tnfr.py +783 -0
  92. tnfr/dynamics/propagation.py +326 -0
  93. tnfr/dynamics/runtime.py +908 -0
  94. tnfr/dynamics/runtime.pyi +77 -0
  95. tnfr/dynamics/sampling.py +10 -5
  96. tnfr/dynamics/sampling.pyi +7 -0
  97. tnfr/dynamics/selectors.py +711 -0
  98. tnfr/dynamics/selectors.pyi +85 -0
  99. tnfr/dynamics/structural_clip.py +207 -0
  100. tnfr/errors/__init__.py +37 -0
  101. tnfr/errors/contextual.py +492 -0
  102. tnfr/execution.py +77 -55
  103. tnfr/execution.pyi +45 -0
  104. tnfr/extensions/__init__.py +205 -0
  105. tnfr/extensions/__init__.pyi +18 -0
  106. tnfr/extensions/base.py +173 -0
  107. tnfr/extensions/base.pyi +35 -0
  108. tnfr/extensions/business/__init__.py +71 -0
  109. tnfr/extensions/business/__init__.pyi +11 -0
  110. tnfr/extensions/business/cookbook.py +88 -0
  111. tnfr/extensions/business/cookbook.pyi +8 -0
  112. tnfr/extensions/business/health_analyzers.py +202 -0
  113. tnfr/extensions/business/health_analyzers.pyi +9 -0
  114. tnfr/extensions/business/patterns.py +183 -0
  115. tnfr/extensions/business/patterns.pyi +8 -0
  116. tnfr/extensions/medical/__init__.py +73 -0
  117. tnfr/extensions/medical/__init__.pyi +11 -0
  118. tnfr/extensions/medical/cookbook.py +88 -0
  119. tnfr/extensions/medical/cookbook.pyi +8 -0
  120. tnfr/extensions/medical/health_analyzers.py +181 -0
  121. tnfr/extensions/medical/health_analyzers.pyi +9 -0
  122. tnfr/extensions/medical/patterns.py +163 -0
  123. tnfr/extensions/medical/patterns.pyi +8 -0
  124. tnfr/flatten.py +29 -50
  125. tnfr/flatten.pyi +21 -0
  126. tnfr/gamma.py +66 -53
  127. tnfr/gamma.pyi +36 -0
  128. tnfr/glyph_history.py +144 -57
  129. tnfr/glyph_history.pyi +35 -0
  130. tnfr/glyph_runtime.py +19 -0
  131. tnfr/glyph_runtime.pyi +8 -0
  132. tnfr/immutable.py +70 -30
  133. tnfr/immutable.pyi +36 -0
  134. tnfr/initialization.py +22 -16
  135. tnfr/initialization.pyi +65 -0
  136. tnfr/io.py +5 -241
  137. tnfr/io.pyi +13 -0
  138. tnfr/locking.pyi +7 -0
  139. tnfr/mathematics/__init__.py +79 -0
  140. tnfr/mathematics/backend.py +453 -0
  141. tnfr/mathematics/backend.pyi +99 -0
  142. tnfr/mathematics/dynamics.py +408 -0
  143. tnfr/mathematics/dynamics.pyi +90 -0
  144. tnfr/mathematics/epi.py +391 -0
  145. tnfr/mathematics/epi.pyi +65 -0
  146. tnfr/mathematics/generators.py +242 -0
  147. tnfr/mathematics/generators.pyi +29 -0
  148. tnfr/mathematics/metrics.py +119 -0
  149. tnfr/mathematics/metrics.pyi +16 -0
  150. tnfr/mathematics/operators.py +239 -0
  151. tnfr/mathematics/operators.pyi +59 -0
  152. tnfr/mathematics/operators_factory.py +124 -0
  153. tnfr/mathematics/operators_factory.pyi +11 -0
  154. tnfr/mathematics/projection.py +87 -0
  155. tnfr/mathematics/projection.pyi +33 -0
  156. tnfr/mathematics/runtime.py +182 -0
  157. tnfr/mathematics/runtime.pyi +64 -0
  158. tnfr/mathematics/spaces.py +256 -0
  159. tnfr/mathematics/spaces.pyi +83 -0
  160. tnfr/mathematics/transforms.py +305 -0
  161. tnfr/mathematics/transforms.pyi +62 -0
  162. tnfr/metrics/__init__.py +47 -9
  163. tnfr/metrics/__init__.pyi +20 -0
  164. tnfr/metrics/buffer_cache.py +163 -0
  165. tnfr/metrics/buffer_cache.pyi +24 -0
  166. tnfr/metrics/cache_utils.py +214 -0
  167. tnfr/metrics/coherence.py +1510 -330
  168. tnfr/metrics/coherence.pyi +129 -0
  169. tnfr/metrics/common.py +23 -16
  170. tnfr/metrics/common.pyi +35 -0
  171. tnfr/metrics/core.py +251 -36
  172. tnfr/metrics/core.pyi +13 -0
  173. tnfr/metrics/diagnosis.py +709 -110
  174. tnfr/metrics/diagnosis.pyi +86 -0
  175. tnfr/metrics/emergence.py +245 -0
  176. tnfr/metrics/export.py +60 -18
  177. tnfr/metrics/export.pyi +7 -0
  178. tnfr/metrics/glyph_timing.py +233 -43
  179. tnfr/metrics/glyph_timing.pyi +81 -0
  180. tnfr/metrics/learning_metrics.py +280 -0
  181. tnfr/metrics/learning_metrics.pyi +21 -0
  182. tnfr/metrics/phase_coherence.py +351 -0
  183. tnfr/metrics/phase_compatibility.py +349 -0
  184. tnfr/metrics/reporting.py +63 -28
  185. tnfr/metrics/reporting.pyi +25 -0
  186. tnfr/metrics/sense_index.py +1126 -43
  187. tnfr/metrics/sense_index.pyi +9 -0
  188. tnfr/metrics/trig.py +215 -23
  189. tnfr/metrics/trig.pyi +13 -0
  190. tnfr/metrics/trig_cache.py +148 -24
  191. tnfr/metrics/trig_cache.pyi +10 -0
  192. tnfr/multiscale/__init__.py +32 -0
  193. tnfr/multiscale/hierarchical.py +517 -0
  194. tnfr/node.py +646 -140
  195. tnfr/node.pyi +139 -0
  196. tnfr/observers.py +160 -45
  197. tnfr/observers.pyi +31 -0
  198. tnfr/ontosim.py +23 -19
  199. tnfr/ontosim.pyi +28 -0
  200. tnfr/operators/__init__.py +1358 -106
  201. tnfr/operators/__init__.pyi +31 -0
  202. tnfr/operators/algebra.py +277 -0
  203. tnfr/operators/canonical_patterns.py +420 -0
  204. tnfr/operators/cascade.py +267 -0
  205. tnfr/operators/cycle_detection.py +358 -0
  206. tnfr/operators/definitions.py +4108 -0
  207. tnfr/operators/definitions.pyi +78 -0
  208. tnfr/operators/grammar.py +1164 -0
  209. tnfr/operators/grammar.pyi +140 -0
  210. tnfr/operators/hamiltonian.py +710 -0
  211. tnfr/operators/health_analyzer.py +809 -0
  212. tnfr/operators/jitter.py +107 -38
  213. tnfr/operators/jitter.pyi +11 -0
  214. tnfr/operators/lifecycle.py +314 -0
  215. tnfr/operators/metabolism.py +618 -0
  216. tnfr/operators/metrics.py +2138 -0
  217. tnfr/operators/network_analysis/__init__.py +27 -0
  218. tnfr/operators/network_analysis/source_detection.py +186 -0
  219. tnfr/operators/nodal_equation.py +395 -0
  220. tnfr/operators/pattern_detection.py +660 -0
  221. tnfr/operators/patterns.py +669 -0
  222. tnfr/operators/postconditions/__init__.py +38 -0
  223. tnfr/operators/postconditions/mutation.py +236 -0
  224. tnfr/operators/preconditions/__init__.py +1226 -0
  225. tnfr/operators/preconditions/coherence.py +305 -0
  226. tnfr/operators/preconditions/dissonance.py +236 -0
  227. tnfr/operators/preconditions/emission.py +128 -0
  228. tnfr/operators/preconditions/mutation.py +580 -0
  229. tnfr/operators/preconditions/reception.py +125 -0
  230. tnfr/operators/preconditions/resonance.py +364 -0
  231. tnfr/operators/registry.py +74 -0
  232. tnfr/operators/registry.pyi +9 -0
  233. tnfr/operators/remesh.py +1415 -91
  234. tnfr/operators/remesh.pyi +26 -0
  235. tnfr/operators/structural_units.py +268 -0
  236. tnfr/operators/unified_grammar.py +105 -0
  237. tnfr/parallel/__init__.py +54 -0
  238. tnfr/parallel/auto_scaler.py +234 -0
  239. tnfr/parallel/distributed.py +384 -0
  240. tnfr/parallel/engine.py +238 -0
  241. tnfr/parallel/gpu_engine.py +420 -0
  242. tnfr/parallel/monitoring.py +248 -0
  243. tnfr/parallel/partitioner.py +459 -0
  244. tnfr/py.typed +0 -0
  245. tnfr/recipes/__init__.py +22 -0
  246. tnfr/recipes/cookbook.py +743 -0
  247. tnfr/rng.py +75 -151
  248. tnfr/rng.pyi +26 -0
  249. tnfr/schemas/__init__.py +8 -0
  250. tnfr/schemas/grammar.json +94 -0
  251. tnfr/sdk/__init__.py +107 -0
  252. tnfr/sdk/__init__.pyi +19 -0
  253. tnfr/sdk/adaptive_system.py +173 -0
  254. tnfr/sdk/adaptive_system.pyi +21 -0
  255. tnfr/sdk/builders.py +370 -0
  256. tnfr/sdk/builders.pyi +51 -0
  257. tnfr/sdk/fluent.py +1121 -0
  258. tnfr/sdk/fluent.pyi +74 -0
  259. tnfr/sdk/templates.py +342 -0
  260. tnfr/sdk/templates.pyi +41 -0
  261. tnfr/sdk/utils.py +341 -0
  262. tnfr/secure_config.py +46 -0
  263. tnfr/security/__init__.py +70 -0
  264. tnfr/security/database.py +514 -0
  265. tnfr/security/subprocess.py +503 -0
  266. tnfr/security/validation.py +290 -0
  267. tnfr/selector.py +59 -22
  268. tnfr/selector.pyi +19 -0
  269. tnfr/sense.py +92 -67
  270. tnfr/sense.pyi +23 -0
  271. tnfr/services/__init__.py +17 -0
  272. tnfr/services/orchestrator.py +325 -0
  273. tnfr/sparse/__init__.py +39 -0
  274. tnfr/sparse/representations.py +492 -0
  275. tnfr/structural.py +639 -263
  276. tnfr/structural.pyi +83 -0
  277. tnfr/telemetry/__init__.py +35 -0
  278. tnfr/telemetry/cache_metrics.py +226 -0
  279. tnfr/telemetry/cache_metrics.pyi +64 -0
  280. tnfr/telemetry/nu_f.py +422 -0
  281. tnfr/telemetry/nu_f.pyi +108 -0
  282. tnfr/telemetry/verbosity.py +36 -0
  283. tnfr/telemetry/verbosity.pyi +15 -0
  284. tnfr/tokens.py +2 -4
  285. tnfr/tokens.pyi +36 -0
  286. tnfr/tools/__init__.py +20 -0
  287. tnfr/tools/domain_templates.py +478 -0
  288. tnfr/tools/sequence_generator.py +846 -0
  289. tnfr/topology/__init__.py +13 -0
  290. tnfr/topology/asymmetry.py +151 -0
  291. tnfr/trace.py +300 -126
  292. tnfr/trace.pyi +42 -0
  293. tnfr/tutorials/__init__.py +38 -0
  294. tnfr/tutorials/autonomous_evolution.py +285 -0
  295. tnfr/tutorials/interactive.py +1576 -0
  296. tnfr/tutorials/structural_metabolism.py +238 -0
  297. tnfr/types.py +743 -12
  298. tnfr/types.pyi +357 -0
  299. tnfr/units.py +68 -0
  300. tnfr/units.pyi +13 -0
  301. tnfr/utils/__init__.py +282 -0
  302. tnfr/utils/__init__.pyi +215 -0
  303. tnfr/utils/cache.py +4223 -0
  304. tnfr/utils/cache.pyi +470 -0
  305. tnfr/{callback_utils.py → utils/callbacks.py} +26 -39
  306. tnfr/utils/callbacks.pyi +49 -0
  307. tnfr/utils/chunks.py +108 -0
  308. tnfr/utils/chunks.pyi +22 -0
  309. tnfr/utils/data.py +428 -0
  310. tnfr/utils/data.pyi +74 -0
  311. tnfr/utils/graph.py +85 -0
  312. tnfr/utils/graph.pyi +10 -0
  313. tnfr/utils/init.py +821 -0
  314. tnfr/utils/init.pyi +80 -0
  315. tnfr/utils/io.py +559 -0
  316. tnfr/utils/io.pyi +66 -0
  317. tnfr/{helpers → utils}/numeric.py +51 -24
  318. tnfr/utils/numeric.pyi +21 -0
  319. tnfr/validation/__init__.py +257 -0
  320. tnfr/validation/__init__.pyi +85 -0
  321. tnfr/validation/compatibility.py +460 -0
  322. tnfr/validation/compatibility.pyi +6 -0
  323. tnfr/validation/config.py +73 -0
  324. tnfr/validation/graph.py +139 -0
  325. tnfr/validation/graph.pyi +18 -0
  326. tnfr/validation/input_validation.py +755 -0
  327. tnfr/validation/invariants.py +712 -0
  328. tnfr/validation/rules.py +253 -0
  329. tnfr/validation/rules.pyi +44 -0
  330. tnfr/validation/runtime.py +279 -0
  331. tnfr/validation/runtime.pyi +28 -0
  332. tnfr/validation/sequence_validator.py +162 -0
  333. tnfr/validation/soft_filters.py +170 -0
  334. tnfr/validation/soft_filters.pyi +32 -0
  335. tnfr/validation/spectral.py +164 -0
  336. tnfr/validation/spectral.pyi +42 -0
  337. tnfr/validation/validator.py +1266 -0
  338. tnfr/validation/window.py +39 -0
  339. tnfr/validation/window.pyi +1 -0
  340. tnfr/visualization/__init__.py +98 -0
  341. tnfr/visualization/cascade_viz.py +256 -0
  342. tnfr/visualization/hierarchy.py +284 -0
  343. tnfr/visualization/sequence_plotter.py +784 -0
  344. tnfr/viz/__init__.py +60 -0
  345. tnfr/viz/matplotlib.py +278 -0
  346. tnfr/viz/matplotlib.pyi +35 -0
  347. tnfr-8.5.0.dist-info/METADATA +573 -0
  348. tnfr-8.5.0.dist-info/RECORD +353 -0
  349. {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/entry_points.txt +1 -0
  350. {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/licenses/LICENSE.md +1 -1
  351. tnfr/collections_utils.py +0 -300
  352. tnfr/config.py +0 -32
  353. tnfr/grammar.py +0 -344
  354. tnfr/graph_utils.py +0 -84
  355. tnfr/helpers/__init__.py +0 -71
  356. tnfr/import_utils.py +0 -228
  357. tnfr/json_utils.py +0 -162
  358. tnfr/logging_utils.py +0 -116
  359. tnfr/presets.py +0 -60
  360. tnfr/validators.py +0 -84
  361. tnfr/value_utils.py +0 -59
  362. tnfr-4.5.2.dist-info/METADATA +0 -379
  363. tnfr-4.5.2.dist-info/RECORD +0 -67
  364. {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/WHEEL +0 -0
  365. {tnfr-4.5.2.dist-info → tnfr-8.5.0.dist-info}/top_level.txt +0 -0
tnfr/structural.pyi ADDED
@@ -0,0 +1,83 @@
1
+ from __future__ import annotations
2
+
3
+ from .mathematics import (
4
+ BasicStateProjector,
5
+ CoherenceOperator,
6
+ FrequencyOperator,
7
+ HilbertSpace,
8
+ MathematicalDynamicsEngine,
9
+ )
10
+ from .operators.definitions import (
11
+ Coherence as Coherence,
12
+ Contraction as Contraction,
13
+ Coupling as Coupling,
14
+ Dissonance as Dissonance,
15
+ Emission as Emission,
16
+ Expansion as Expansion,
17
+ Mutation as Mutation,
18
+ Operator as Operator,
19
+ Reception as Reception,
20
+ Recursivity as Recursivity,
21
+ Resonance as Resonance,
22
+ SelfOrganization as SelfOrganization,
23
+ Silence as Silence,
24
+ Transition as Transition,
25
+ )
26
+ from .operators.registry import OPERATORS as OPERATORS
27
+ from .types import DeltaNFRHook, NodeId, TNFRGraph
28
+ from tnfr.validation import NFRValidator, validate_sequence as validate_sequence
29
+ from typing import Iterable, Sequence
30
+
31
+ __all__ = [
32
+ "create_nfr",
33
+ "create_math_nfr",
34
+ "Operator",
35
+ "Emission",
36
+ "Reception",
37
+ "Coherence",
38
+ "Dissonance",
39
+ "Coupling",
40
+ "Resonance",
41
+ "Silence",
42
+ "Expansion",
43
+ "Contraction",
44
+ "SelfOrganization",
45
+ "Mutation",
46
+ "Transition",
47
+ "Recursivity",
48
+ "OPERATORS",
49
+ "validate_sequence",
50
+ "run_sequence",
51
+ ]
52
+
53
+ def create_nfr(
54
+ name: str,
55
+ *,
56
+ epi: float = 0.0,
57
+ vf: float = 1.0,
58
+ theta: float = 0.0,
59
+ graph: TNFRGraph | None = None,
60
+ dnfr_hook: DeltaNFRHook = ...,
61
+ ) -> tuple[TNFRGraph, str]: ...
62
+ def create_math_nfr(
63
+ name: str,
64
+ *,
65
+ epi: float = 0.0,
66
+ vf: float = 1.0,
67
+ theta: float = 0.0,
68
+ graph: TNFRGraph | None = None,
69
+ dnfr_hook: DeltaNFRHook = ...,
70
+ dimension: int | None = None,
71
+ hilbert_space: HilbertSpace | None = None,
72
+ coherence_operator: CoherenceOperator | None = None,
73
+ coherence_spectrum: Sequence[float] | None = None,
74
+ coherence_c_min: float | None = None,
75
+ coherence_threshold: float | None = None,
76
+ frequency_operator: FrequencyOperator | None = None,
77
+ frequency_diagonal: Sequence[float] | None = None,
78
+ generator_diagonal: Sequence[float] | None = None,
79
+ state_projector: BasicStateProjector | None = None,
80
+ dynamics_engine: MathematicalDynamicsEngine | None = None,
81
+ validator: NFRValidator | None = None,
82
+ ) -> tuple[TNFRGraph, str]: ...
83
+ def run_sequence(G: TNFRGraph, node: NodeId, ops: Iterable[Operator]) -> None: ...
@@ -0,0 +1,35 @@
1
+ """Telemetry helpers for shared observability settings."""
2
+
3
+ from .cache_metrics import (
4
+ CacheMetricsSnapshot,
5
+ CacheTelemetryPublisher,
6
+ ensure_cache_metrics_publisher,
7
+ publish_graph_cache_metrics,
8
+ )
9
+ from .nu_f import (
10
+ NuFSnapshot,
11
+ NuFTelemetryAccumulator,
12
+ NuFWindow,
13
+ ensure_nu_f_telemetry,
14
+ record_nu_f_window,
15
+ )
16
+ from .verbosity import (
17
+ TELEMETRY_VERBOSITY_DEFAULT,
18
+ TELEMETRY_VERBOSITY_LEVELS,
19
+ TelemetryVerbosity,
20
+ )
21
+
22
+ __all__ = [
23
+ "CacheMetricsSnapshot",
24
+ "CacheTelemetryPublisher",
25
+ "ensure_cache_metrics_publisher",
26
+ "publish_graph_cache_metrics",
27
+ "NuFWindow",
28
+ "NuFSnapshot",
29
+ "NuFTelemetryAccumulator",
30
+ "ensure_nu_f_telemetry",
31
+ "record_nu_f_window",
32
+ "TelemetryVerbosity",
33
+ "TELEMETRY_VERBOSITY_DEFAULT",
34
+ "TELEMETRY_VERBOSITY_LEVELS",
35
+ ]
@@ -0,0 +1,226 @@
1
+ """Cache telemetry publishers for structured observability channels."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import weakref
7
+ from dataclasses import dataclass
8
+ from typing import Any, MutableMapping, TYPE_CHECKING
9
+
10
+ from ..utils import (
11
+ _graph_cache_manager,
12
+ CacheManager,
13
+ CacheStatistics,
14
+ get_logger,
15
+ json_dumps,
16
+ )
17
+
18
+ if TYPE_CHECKING: # pragma: no cover - typing helpers
19
+ from networkx import Graph
20
+
21
+ from ..types import TNFRGraph
22
+
23
+ __all__ = (
24
+ "CacheMetricsSnapshot",
25
+ "CacheTelemetryPublisher",
26
+ "ensure_cache_metrics_publisher",
27
+ "publish_graph_cache_metrics",
28
+ )
29
+
30
+
31
+ @dataclass(frozen=True)
32
+ class CacheMetricsSnapshot:
33
+ """Structured cache metrics enriched with ratios and latency estimates."""
34
+
35
+ cache: str
36
+ hits: int
37
+ misses: int
38
+ evictions: int
39
+ total_time: float
40
+ timings: int
41
+ hit_ratio: float | None
42
+ miss_ratio: float | None
43
+ avg_latency: float | None
44
+
45
+ @classmethod
46
+ def from_statistics(
47
+ cls, name: str, stats: CacheStatistics
48
+ ) -> "CacheMetricsSnapshot":
49
+ """Build a snapshot computing ratios from :class:`CacheStatistics`."""
50
+
51
+ hits = int(stats.hits)
52
+ misses = int(stats.misses)
53
+ evictions = int(stats.evictions)
54
+ total_time = float(stats.total_time)
55
+ timings = int(stats.timings)
56
+ requests = hits + misses
57
+ hit_ratio = (hits / requests) if requests else None
58
+ miss_ratio = (misses / requests) if requests else None
59
+ avg_latency = (total_time / timings) if timings else None
60
+ return cls(
61
+ cache=name,
62
+ hits=hits,
63
+ misses=misses,
64
+ evictions=evictions,
65
+ total_time=total_time,
66
+ timings=timings,
67
+ hit_ratio=hit_ratio,
68
+ miss_ratio=miss_ratio,
69
+ avg_latency=avg_latency,
70
+ )
71
+
72
+ def as_payload(self) -> dict[str, Any]:
73
+ """Return a dictionary suitable for structured logging."""
74
+
75
+ return {
76
+ "cache": self.cache,
77
+ "hits": self.hits,
78
+ "misses": self.misses,
79
+ "evictions": self.evictions,
80
+ "total_time": self.total_time,
81
+ "timings": self.timings,
82
+ "hit_ratio": self.hit_ratio,
83
+ "miss_ratio": self.miss_ratio,
84
+ "avg_latency": self.avg_latency,
85
+ }
86
+
87
+
88
+ class CacheTelemetryPublisher:
89
+ """Metrics publisher broadcasting cache counters to observability channels."""
90
+
91
+ def __init__(
92
+ self,
93
+ *,
94
+ graph: "TNFRGraph | Graph | MutableMapping[str, Any] | None" = None,
95
+ logger: logging.Logger | None = None,
96
+ hit_ratio_alert: float = 0.5,
97
+ latency_alert: float = 0.1,
98
+ ) -> None:
99
+ self._logger = logger or get_logger("tnfr.telemetry.cache")
100
+ self._graph_ref: (
101
+ weakref.ReferenceType["TNFRGraph | Graph | MutableMapping[str, Any]"] | None
102
+ ) = None
103
+ self._hit_ratio_alert = float(hit_ratio_alert)
104
+ self._latency_alert = float(latency_alert)
105
+ self.attach_graph(graph)
106
+
107
+ @property
108
+ def logger(self) -> logging.Logger:
109
+ """Logger used for structured cache telemetry."""
110
+
111
+ return self._logger
112
+
113
+ def attach_graph(
114
+ self, graph: "TNFRGraph | Graph | MutableMapping[str, Any] | None"
115
+ ) -> None:
116
+ """Attach ``graph`` so observability callbacks receive metrics."""
117
+
118
+ if graph is None:
119
+ return
120
+ try:
121
+ self._graph_ref = weakref.ref(graph) # type: ignore[arg-type]
122
+ except TypeError: # pragma: no cover - defensive path for exotic graphs
123
+ self._graph_ref = None
124
+
125
+ def _resolve_graph(
126
+ self,
127
+ ) -> "TNFRGraph | Graph | MutableMapping[str, Any] | None":
128
+ return self._graph_ref() if self._graph_ref is not None else None
129
+
130
+ def __call__(self, name: str, stats: CacheStatistics) -> None:
131
+ """Emit structured telemetry and invoke observability hooks."""
132
+
133
+ snapshot = CacheMetricsSnapshot.from_statistics(name, stats)
134
+ payload = snapshot.as_payload()
135
+ message = json_dumps({"event": "cache_metrics", **payload}, sort_keys=True)
136
+ self._logger.info(message)
137
+
138
+ if (
139
+ snapshot.hit_ratio is not None
140
+ and snapshot.hit_ratio < self._hit_ratio_alert
141
+ and snapshot.misses > 0
142
+ ):
143
+ warning = json_dumps(
144
+ {
145
+ "event": "cache_metrics.low_hit_ratio",
146
+ "cache": name,
147
+ "hit_ratio": snapshot.hit_ratio,
148
+ "threshold": self._hit_ratio_alert,
149
+ "requests": snapshot.hits + snapshot.misses,
150
+ },
151
+ sort_keys=True,
152
+ )
153
+ self._logger.warning(warning)
154
+
155
+ if (
156
+ snapshot.avg_latency is not None
157
+ and snapshot.avg_latency > self._latency_alert
158
+ and snapshot.timings > 0
159
+ ):
160
+ warning = json_dumps(
161
+ {
162
+ "event": "cache_metrics.high_latency",
163
+ "cache": name,
164
+ "avg_latency": snapshot.avg_latency,
165
+ "threshold": self._latency_alert,
166
+ "timings": snapshot.timings,
167
+ },
168
+ sort_keys=True,
169
+ )
170
+ self._logger.warning(warning)
171
+
172
+ graph = self._resolve_graph()
173
+ if graph is not None:
174
+ from ..utils import CallbackEvent, callback_manager
175
+
176
+ ctx = {"cache": name, "metrics": payload}
177
+ callback_manager.invoke_callbacks(graph, CallbackEvent.CACHE_METRICS, ctx)
178
+
179
+
180
+ _PUBLISHER_ATTR = "_tnfr_cache_metrics_publisher"
181
+
182
+
183
+ def ensure_cache_metrics_publisher(
184
+ manager: CacheManager,
185
+ *,
186
+ graph: "TNFRGraph | Graph | MutableMapping[str, Any] | None" = None,
187
+ logger: logging.Logger | None = None,
188
+ hit_ratio_alert: float = 0.5,
189
+ latency_alert: float = 0.1,
190
+ ) -> CacheTelemetryPublisher:
191
+ """Attach a :class:`CacheTelemetryPublisher` to ``manager`` if missing."""
192
+
193
+ publisher = getattr(manager, _PUBLISHER_ATTR, None)
194
+ if not isinstance(publisher, CacheTelemetryPublisher):
195
+ publisher = CacheTelemetryPublisher(
196
+ graph=graph,
197
+ logger=logger,
198
+ hit_ratio_alert=hit_ratio_alert,
199
+ latency_alert=latency_alert,
200
+ )
201
+ manager.register_metrics_publisher(publisher)
202
+ setattr(manager, _PUBLISHER_ATTR, publisher)
203
+ else:
204
+ if graph is not None:
205
+ publisher.attach_graph(graph)
206
+ return publisher
207
+
208
+
209
+ def publish_graph_cache_metrics(
210
+ graph: "TNFRGraph | Graph | MutableMapping[str, Any]",
211
+ *,
212
+ manager: CacheManager | None = None,
213
+ hit_ratio_alert: float = 0.5,
214
+ latency_alert: float = 0.1,
215
+ ) -> None:
216
+ """Publish cache metrics for ``graph`` using the shared manager."""
217
+
218
+ if manager is None:
219
+ manager = _graph_cache_manager(getattr(graph, "graph", graph))
220
+ ensure_cache_metrics_publisher(
221
+ manager,
222
+ graph=graph,
223
+ hit_ratio_alert=hit_ratio_alert,
224
+ latency_alert=latency_alert,
225
+ )
226
+ manager.publish_metrics()
@@ -0,0 +1,64 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from ..types import TNFRGraph
5
+ from ..utils import CacheManager, CacheStatistics
6
+ from dataclasses import dataclass
7
+ from networkx import Graph
8
+ from typing import Any, MutableMapping
9
+
10
+ __all__ = [
11
+ "CacheMetricsSnapshot",
12
+ "CacheTelemetryPublisher",
13
+ "ensure_cache_metrics_publisher",
14
+ "publish_graph_cache_metrics",
15
+ ]
16
+
17
+ @dataclass(frozen=True)
18
+ class CacheMetricsSnapshot:
19
+ cache: str
20
+ hits: int
21
+ misses: int
22
+ evictions: int
23
+ total_time: float
24
+ timings: int
25
+ hit_ratio: float | None
26
+ miss_ratio: float | None
27
+ avg_latency: float | None
28
+ @classmethod
29
+ def from_statistics(
30
+ cls, name: str, stats: CacheStatistics
31
+ ) -> CacheMetricsSnapshot: ...
32
+ def as_payload(self) -> dict[str, Any]: ...
33
+
34
+ class CacheTelemetryPublisher:
35
+ def __init__(
36
+ self,
37
+ *,
38
+ graph: TNFRGraph | Graph | MutableMapping[str, Any] | None = None,
39
+ logger: logging.Logger | None = None,
40
+ hit_ratio_alert: float = 0.5,
41
+ latency_alert: float = 0.1,
42
+ ) -> None: ...
43
+ @property
44
+ def logger(self) -> logging.Logger: ...
45
+ def attach_graph(
46
+ self, graph: TNFRGraph | Graph | MutableMapping[str, Any] | None
47
+ ) -> None: ...
48
+ def __call__(self, name: str, stats: CacheStatistics) -> None: ...
49
+
50
+ def ensure_cache_metrics_publisher(
51
+ manager: CacheManager,
52
+ *,
53
+ graph: TNFRGraph | Graph | MutableMapping[str, Any] | None = None,
54
+ logger: logging.Logger | None = None,
55
+ hit_ratio_alert: float = 0.5,
56
+ latency_alert: float = 0.1,
57
+ ) -> CacheTelemetryPublisher: ...
58
+ def publish_graph_cache_metrics(
59
+ graph: TNFRGraph | Graph | MutableMapping[str, Any],
60
+ *,
61
+ manager: CacheManager | None = None,
62
+ hit_ratio_alert: float = 0.5,
63
+ latency_alert: float = 0.1,
64
+ ) -> None: ...