gea-program 0.1.0__tar.gz → 0.2.0__tar.gz

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 (173) hide show
  1. {gea_program-0.1.0/gea_program.egg-info → gea_program-0.2.0}/PKG-INFO +68 -17
  2. {gea_program-0.1.0 → gea_program-0.2.0}/README.md +57 -16
  3. {gea_program-0.1.0 → gea_program-0.2.0}/gea/BENCH_TEST_PROTOCOL.md +2 -3
  4. {gea_program-0.1.0 → gea_program-0.2.0}/gea/__init__.py +7 -5
  5. {gea_program-0.1.0 → gea_program-0.2.0}/gea/__main__.py +55 -2
  6. {gea_program-0.1.0 → gea_program-0.2.0}/gea/acceptance_tests.py +205 -42
  7. {gea_program-0.1.0 → gea_program-0.2.0}/gea/bench.py +1 -1
  8. {gea_program-0.1.0 → gea_program-0.2.0}/gea/blind_harness.py +5 -5
  9. {gea_program-0.1.0 → gea_program-0.2.0}/gea/case_study.py +13 -14
  10. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +1 -1
  11. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +1 -1
  12. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +1 -1
  13. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +1 -1
  14. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +2 -2
  15. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +1 -1
  16. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +1 -1
  17. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +1 -1
  18. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +2 -2
  19. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +1 -1
  20. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +2 -2
  21. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +1 -1
  22. {gea_program-0.1.0 → gea_program-0.2.0}/gea/client_reports.py +7 -5
  23. {gea_program-0.1.0 → gea_program-0.2.0}/gea/correlation.py +2 -2
  24. {gea_program-0.1.0 → gea_program-0.2.0}/gea/deviation.py +1 -1
  25. {gea_program-0.1.0 → gea_program-0.2.0}/gea/downhole_engine.py +14 -15
  26. {gea_program-0.1.0 → gea_program-0.2.0}/gea/earth_model.py +1 -2
  27. {gea_program-0.1.0 → gea_program-0.2.0}/gea/example_register_map.json +1 -1
  28. {gea_program-0.1.0 → gea_program-0.2.0}/gea/fat_sat.py +1 -0
  29. {gea_program-0.1.0 → gea_program-0.2.0}/gea/follower.py +6 -6
  30. {gea_program-0.1.0 → gea_program-0.2.0}/gea/forward_model.py +11 -13
  31. {gea_program-0.1.0 → gea_program-0.2.0}/gea/gamma.py +3 -3
  32. {gea_program-0.1.0 → gea_program-0.2.0}/gea/gauge_specs.py +8 -8
  33. {gea_program-0.1.0 → gea_program-0.2.0}/gea/gravity_reference.py +4 -5
  34. {gea_program-0.1.0 → gea_program-0.2.0}/gea/inverse_engine.py +2 -2
  35. gea_program-0.2.0/gea/live_ports.py +166 -0
  36. {gea_program-0.1.0 → gea_program-0.2.0}/gea/matplotlib_demo.py +2 -2
  37. {gea_program-0.1.0 → gea_program-0.2.0}/gea/modbus.py +8 -8
  38. {gea_program-0.1.0 → gea_program-0.2.0}/gea/model_card.py +1 -1
  39. gea_program-0.2.0/gea/mqtt_port.py +538 -0
  40. gea_program-0.2.0/gea/opcua_port.py +280 -0
  41. {gea_program-0.1.0 → gea_program-0.2.0}/gea/operator_app.py +10 -10
  42. {gea_program-0.1.0 → gea_program-0.2.0}/gea/ports.py +9 -9
  43. {gea_program-0.1.0 → gea_program-0.2.0}/gea/profile_catalog.py +20 -20
  44. {gea_program-0.1.0 → gea_program-0.2.0}/gea/project.py +3 -3
  45. {gea_program-0.1.0 → gea_program-0.2.0}/gea/qt6_downhole_app.py +8 -9
  46. {gea_program-0.1.0 → gea_program-0.2.0}/gea/quartz_hpht_extension.py +17 -17
  47. {gea_program-0.1.0 → gea_program-0.2.0}/gea/reconciler.py +3 -3
  48. {gea_program-0.1.0 → gea_program-0.2.0}/gea/rock_inventory.py +33 -58
  49. {gea_program-0.1.0 → gea_program-0.2.0}/gea/sample_record.py +2 -2
  50. {gea_program-0.1.0 → gea_program-0.2.0}/gea/sbom.py +3 -1
  51. {gea_program-0.1.0 → gea_program-0.2.0}/gea/segy.py +2 -2
  52. {gea_program-0.1.0 → gea_program-0.2.0}/gea/service_life.py +7 -7
  53. {gea_program-0.1.0 → gea_program-0.2.0}/gea/strata_join.py +1 -1
  54. {gea_program-0.1.0 → gea_program-0.2.0}/gea/survey_cmd.py +3 -4
  55. {gea_program-0.1.0 → gea_program-0.2.0}/gea/survey_view.py +2 -5
  56. {gea_program-0.1.0 → gea_program-0.2.0}/gea/telemetry.py +1 -1
  57. {gea_program-0.1.0 → gea_program-0.2.0}/gea/tool_library.py +9 -9
  58. {gea_program-0.1.0 → gea_program-0.2.0}/gea/well_assembler.py +12 -13
  59. {gea_program-0.1.0 → gea_program-0.2.0/gea_program.egg-info}/PKG-INFO +68 -17
  60. {gea_program-0.1.0 → gea_program-0.2.0}/gea_program.egg-info/SOURCES.txt +3 -1
  61. gea_program-0.2.0/gea_program.egg-info/requires.txt +25 -0
  62. {gea_program-0.1.0 → gea_program-0.2.0}/pyproject.toml +6 -2
  63. {gea_program-0.1.0 → gea_program-0.2.0}/tests/test_acceptance.py +7 -6
  64. gea_program-0.1.0/gea/IMPORT_RECORD.md +0 -61
  65. gea_program-0.1.0/gea_program.egg-info/requires.txt +0 -11
  66. {gea_program-0.1.0 → gea_program-0.2.0}/LICENSE +0 -0
  67. {gea_program-0.1.0 → gea_program-0.2.0}/gea/accuracy_statement.py +0 -0
  68. {gea_program-0.1.0 → gea_program-0.2.0}/gea/alarm_engine.py +0 -0
  69. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
  70. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
  71. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
  72. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
  73. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
  74. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
  75. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
  76. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
  77. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
  78. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
  79. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
  80. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
  81. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
  82. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
  83. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
  84. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
  85. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
  86. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
  87. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
  88. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
  89. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
  90. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
  91. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
  92. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
  93. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
  94. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
  95. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
  96. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
  97. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
  98. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
  99. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
  100. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
  101. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
  102. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
  103. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
  104. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
  105. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
  106. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
  107. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
  108. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
  109. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
  110. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
  111. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
  112. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
  113. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
  114. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
  115. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
  116. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
  117. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
  118. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
  119. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
  120. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
  121. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
  122. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
  123. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
  124. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
  125. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
  126. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
  127. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
  128. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/med_160_sapropels.txt +0 -0
  129. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
  130. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
  131. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
  132. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
  133. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
  134. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
  135. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
  136. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
  137. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
  138. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
  139. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
  140. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
  141. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
  142. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
  143. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
  144. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
  145. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
  146. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
  147. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
  148. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
  149. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
  150. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
  151. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
  152. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
  153. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
  154. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
  155. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
  156. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
  157. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
  158. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
  159. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
  160. {gea_program-0.1.0 → gea_program-0.2.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
  161. {gea_program-0.1.0 → gea_program-0.2.0}/gea/cli.py +0 -0
  162. {gea_program-0.1.0 → gea_program-0.2.0}/gea/config_versioning.py +0 -0
  163. {gea_program-0.1.0 → gea_program-0.2.0}/gea/dashboard.py +0 -0
  164. {gea_program-0.1.0 → gea_program-0.2.0}/gea/drift_monitor.py +0 -0
  165. {gea_program-0.1.0 → gea_program-0.2.0}/gea/sample_well_profile.csv +0 -0
  166. {gea_program-0.1.0 → gea_program-0.2.0}/gea/shell.py +0 -0
  167. {gea_program-0.1.0 → gea_program-0.2.0}/gea/sla_report.py +0 -0
  168. {gea_program-0.1.0 → gea_program-0.2.0}/gea/store_forward.py +0 -0
  169. {gea_program-0.1.0 → gea_program-0.2.0}/gea/well_test_validation.py +0 -0
  170. {gea_program-0.1.0 → gea_program-0.2.0}/gea_program.egg-info/dependency_links.txt +0 -0
  171. {gea_program-0.1.0 → gea_program-0.2.0}/gea_program.egg-info/entry_points.txt +0 -0
  172. {gea_program-0.1.0 → gea_program-0.2.0}/gea_program.egg-info/top_level.txt +0 -0
  173. {gea_program-0.1.0 → gea_program-0.2.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gea-program
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: GEA-Program: downhole gauge monitoring - canonical measurement records, quality rules, drift evaluation with a re-fit change log, well-test validation, alarm management, model cards, store-and-forward, monthly SLA measurement, FAT/SAT protocols and a dashboard, generated from live objects in the client's reporting outline.
5
5
  Author: Daniel T. Murphy
6
6
  License: MPL-2.0
@@ -22,6 +22,16 @@ Requires-Dist: PyQt6>=6.5; extra == "desktop"
22
22
  Requires-Dist: matplotlib>=3.7; extra == "desktop"
23
23
  Provides-Extra: modbus
24
24
  Requires-Dist: pymodbus>=3.0; extra == "modbus"
25
+ Provides-Extra: opcua
26
+ Requires-Dist: asyncua>=1.0; extra == "opcua"
27
+ Provides-Extra: mqtt
28
+ Requires-Dist: paho-mqtt>=2.0; extra == "mqtt"
29
+ Provides-Extra: live
30
+ Requires-Dist: asyncua>=1.0; extra == "live"
31
+ Requires-Dist: paho-mqtt>=2.0; extra == "live"
32
+ Requires-Dist: pymodbus>=3.0; extra == "live"
33
+ Provides-Extra: xls
34
+ Requires-Dist: xlrd>=2.0; extra == "xls"
25
35
  Dynamic: license-file
26
36
 
27
37
  # GEA-Program
@@ -59,6 +69,12 @@ reaches a client document. Nothing unmeasured is ever reported as met.
59
69
  rate-controlled replay, duplicate suppression, per-record latency.
60
70
  - **Configuration versioning, SBOM, monthly SLA, FAT/SAT**
61
71
  (`config_versioning.py`, `sbom.py`, `sla_report.py`, `fat_sat.py`).
72
+ - **Live protocol ports** (`live_ports.py`, `opcua_port.py`, `mqtt_port.py`):
73
+ read-only OPC UA client (read and subscribe) and MQTT subscriber (plain
74
+ number, JSON and Sparkplug B payloads, Sparkplug decoded with no protobuf
75
+ library); every message becomes a measurement record with its source
76
+ timestamp, ingest timestamp and quality flag; every session can be recorded
77
+ and replayed offline. See *Live data* below.
62
78
  - **Dashboard** (`dashboard.py`): tiles, well ranking, alarm wall, drill-down to
63
79
  every report; light and dark; status is always an icon with a label.
64
80
  - **Survey track** (`earth_model.py`, `strata_join.py`, `inverse_engine.py`,
@@ -75,7 +91,7 @@ gea dashboard --catalog-well volve_f12_f14_production_excerpt:15/9-F-12:10000 --
75
91
  gea client-report --report accuracy --out client_report
76
92
  gea model-cards --out model_cards
77
93
  gea sbom --out sbom
78
- gea accept # the product gate (157 checks)
94
+ gea accept # the product gate (172 checks)
79
95
  gea guide # the click-by-click tester guide (docs/TESTER_GUIDE.md)
80
96
  gea gui # the desktop window (pip install "gea-program[desktop]")
81
97
  ```
@@ -83,28 +99,62 @@ gea gui # the desktop window (pip install "gea-program[de
83
99
  `gea` is the front door (`gea/cli.py`); every other subcommand passes through to
84
100
  `python -m gea`. PATH-proof form: `python -m gea.cli ...`. Open `dashboard/index.html`.
85
101
 
102
+ ## Live data
103
+
104
+ The engine reads live data through two protocol ports. Both are **read-only**,
105
+ both map only what the site declares (a tag map the client owns; an empty map
106
+ is declined), and both write every received message to a JSON-lines recording
107
+ that `--replay` turns back into records without a connection - which is how a
108
+ site session is reproduced offline and how the mapping logic is tested.
109
+
110
+ ```
111
+ pip install "gea-program[live]" # asyncua + paho-mqtt (or [opcua] / [mqtt] alone)
112
+ gea opcua --write-example-config opcua.json # edit: endpoint, security, credential env names, nodes
113
+ gea opcua --config opcua.json --read-once --out opc # one read of every mapped node
114
+ gea opcua --config opcua.json --seconds 60 --record opc/session.jsonl --out opc --stream-csv opc/stream.csv
115
+ gea mqtt --write-example-config mqtt.json # edit: broker, TLS, credential env names, topics
116
+ gea mqtt --config mqtt.json --seconds 60 --record mq/session.jsonl --out mq --stream-csv mq/stream.csv
117
+ gea mqtt --config mqtt.json --replay mq/session.jsonl --out mq_replay # no broker needed
118
+ gea ingest --file mq/stream.csv # the stream CSV feeds the historian port like any other
119
+ ```
120
+
121
+ | port | transport | quality | timestamps |
122
+ |---|---|---|---|
123
+ | `opcua` | opc.tcp, read + subscribe; Basic256Sha256 SignAndEncrypt when a certificate and key are given | StatusCode severity bits: Good -> GOOD, Uncertain -> STALE, Bad -> GAP (value withheld); the rule names the code | source timestamp, else server timestamp, else arrival; ingest stamped at arrival |
124
+ | `mqtt` | MQTT v5 / v3.1.1, TLS optional, QoS per topic; `+`/`#` wildcards | number: GOOD or GAP (unparseable, reason kept); JSON: value/time/quality paths and the list of good values; Sparkplug B: `is_null` -> GAP, `Quality` property != 192 -> STALE | JSON time path (ISO / epoch s / epoch ms), Sparkplug metric timestamp, else arrival |
125
+
126
+ Credentials never sit in a config file: the file names the environment variables
127
+ that hold them (`GEA_OPCUA_USER`, `GEA_MQTT_PASSWORD`, ...). Sparkplug B aliases
128
+ are learned from any NBIRTH/DBIRTH on the matching edge node, so alias-only DDATA
129
+ resolves. The example configs are in `docs/examples/`; the acceptance suite
130
+ section AB covers the codec, the mappings, the quality rules, replay and the
131
+ hand-off to the store-and-forward buffer, and runs a live in-process OPC UA
132
+ loopback wherever `asyncua` is installed.
133
+
86
134
  ## Layout
87
135
 
88
136
  ```
89
137
  gea/ the package: engines, record layer, reports, monitor, dashboard, cli, shell, acceptance suite
90
138
  gea/catalog/ 52 public archive entries, each with a provenance file
91
- docs/ TESTER_GUIDE.md, REQUIREMENTS_MATRIX.md (the scope-of-work mirror that shaped the reports),
92
- commercial/ (pilot proposal, bench readiness, renders), HISTORY.md (development history)
93
- tools/ import_from_star_magic.py (the importer), register_audit.py, native/ (cli.py, shell.py sources)
94
- tests/ pytest wrapper around the acceptance suite and the no-corpus check
139
+ docs/ TESTER_GUIDE.md, REQUIREMENTS_MATRIX.md (the scope-of-work mirror that shaped the reports), examples/ (port configs),
140
+ SESSION_LOG.md (the working record, session by session),
141
+ commercial/ (pilot proposal, bench readiness, commercial use), HISTORY.md (the ship-by-ship record)
142
+ tools/ standalone_check.py (the self-contained guard: imports, text, metadata; run by ci and ship.ps1)
143
+ CHANGELOG.md per-release summary (a tag ships only with its section); SHIP_LOG.md is written by ship.ps1
144
+ tests/ pytest wrapper around the acceptance suite and the standalone check
95
145
  ```
96
146
 
97
- ## Where the code came from
147
+ ## Basis
98
148
 
99
- The package was imported from the `uqff_downhole_simulator` package of the
100
- Star-Magic-Program repository by `tools/import_from_star_magic.py`, which renames
101
- the modules, removes every dependency on that repository's physics corpus, puts
102
- the gravity kernel on standard constants (CODATA 2018 G, standard gravity, IUGG
103
- mean radius), keeps the rock inventory's seventeen published density anchors and
104
- Vp ranges without their decompositions, and drops the two modules that existed
105
- only to compose numbers from that corpus. `gea/IMPORT_RECORD.md` lists the
106
- source commit and every file's hash. `tools/register_audit.py` lists what
107
- remains of the source program's vocabulary in comments and docstrings.
149
+ GEA-Program is a self-contained package: every module imports only the
150
+ standard library, numpy, the declared optional extras and the package itself,
151
+ and `tools/standalone_check.py` (run by CI and by `ship.ps1`) fails the build
152
+ if that ever changes or if a tracked file names another program. The physics
153
+ is on standard constants - CODATA 2018 G, standard gravity 9.80665 m/s2, the
154
+ IUGG mean Earth radius - and the rock inventory carries seventeen published
155
+ density anchors and Vp ranges with their citations (Telford, Geldart and
156
+ Sheriff; Schon). Every catalogue entry under `gea/catalog/` has a provenance
157
+ file naming its public source.
108
158
 
109
159
  Two statements the product carries on its own model cards: the gauge aging
110
160
  envelope's lower bound is an engineering model with no field validation on
@@ -117,7 +167,8 @@ ACCEPTABLE at the 95 % target. Both are printed, never claimed otherwise.
117
167
  `pyproject.toml` must equal `gea.__version__` (`-Bump x.y.z` sets both), the tag must
118
168
  not exist anywhere, every version in `SHIP_LOG.md` must have its tag, `python -m gea
119
169
  accept` must be green, `SHIP_MESSAGE.txt` must start with the tag; then commit, tag,
120
- push, and the remote tag must be seen before SHIPPED is printed. `-DryRun` runs every
170
+ push, and the remote tag must be seen before SHIPPED is printed. `CHANGELOG.md` must carry a
171
+ section headed by the tag, and `tools/standalone_check.py` must report no findings. `-DryRun` runs every
121
172
  check and changes nothing; `-NoPush` stops after the local tag.
122
173
 
123
174
  ## Publishing to PyPI
@@ -33,6 +33,12 @@ reaches a client document. Nothing unmeasured is ever reported as met.
33
33
  rate-controlled replay, duplicate suppression, per-record latency.
34
34
  - **Configuration versioning, SBOM, monthly SLA, FAT/SAT**
35
35
  (`config_versioning.py`, `sbom.py`, `sla_report.py`, `fat_sat.py`).
36
+ - **Live protocol ports** (`live_ports.py`, `opcua_port.py`, `mqtt_port.py`):
37
+ read-only OPC UA client (read and subscribe) and MQTT subscriber (plain
38
+ number, JSON and Sparkplug B payloads, Sparkplug decoded with no protobuf
39
+ library); every message becomes a measurement record with its source
40
+ timestamp, ingest timestamp and quality flag; every session can be recorded
41
+ and replayed offline. See *Live data* below.
36
42
  - **Dashboard** (`dashboard.py`): tiles, well ranking, alarm wall, drill-down to
37
43
  every report; light and dark; status is always an icon with a label.
38
44
  - **Survey track** (`earth_model.py`, `strata_join.py`, `inverse_engine.py`,
@@ -49,7 +55,7 @@ gea dashboard --catalog-well volve_f12_f14_production_excerpt:15/9-F-12:10000 --
49
55
  gea client-report --report accuracy --out client_report
50
56
  gea model-cards --out model_cards
51
57
  gea sbom --out sbom
52
- gea accept # the product gate (157 checks)
58
+ gea accept # the product gate (172 checks)
53
59
  gea guide # the click-by-click tester guide (docs/TESTER_GUIDE.md)
54
60
  gea gui # the desktop window (pip install "gea-program[desktop]")
55
61
  ```
@@ -57,28 +63,62 @@ gea gui # the desktop window (pip install "gea-program[de
57
63
  `gea` is the front door (`gea/cli.py`); every other subcommand passes through to
58
64
  `python -m gea`. PATH-proof form: `python -m gea.cli ...`. Open `dashboard/index.html`.
59
65
 
66
+ ## Live data
67
+
68
+ The engine reads live data through two protocol ports. Both are **read-only**,
69
+ both map only what the site declares (a tag map the client owns; an empty map
70
+ is declined), and both write every received message to a JSON-lines recording
71
+ that `--replay` turns back into records without a connection - which is how a
72
+ site session is reproduced offline and how the mapping logic is tested.
73
+
74
+ ```
75
+ pip install "gea-program[live]" # asyncua + paho-mqtt (or [opcua] / [mqtt] alone)
76
+ gea opcua --write-example-config opcua.json # edit: endpoint, security, credential env names, nodes
77
+ gea opcua --config opcua.json --read-once --out opc # one read of every mapped node
78
+ gea opcua --config opcua.json --seconds 60 --record opc/session.jsonl --out opc --stream-csv opc/stream.csv
79
+ gea mqtt --write-example-config mqtt.json # edit: broker, TLS, credential env names, topics
80
+ gea mqtt --config mqtt.json --seconds 60 --record mq/session.jsonl --out mq --stream-csv mq/stream.csv
81
+ gea mqtt --config mqtt.json --replay mq/session.jsonl --out mq_replay # no broker needed
82
+ gea ingest --file mq/stream.csv # the stream CSV feeds the historian port like any other
83
+ ```
84
+
85
+ | port | transport | quality | timestamps |
86
+ |---|---|---|---|
87
+ | `opcua` | opc.tcp, read + subscribe; Basic256Sha256 SignAndEncrypt when a certificate and key are given | StatusCode severity bits: Good -> GOOD, Uncertain -> STALE, Bad -> GAP (value withheld); the rule names the code | source timestamp, else server timestamp, else arrival; ingest stamped at arrival |
88
+ | `mqtt` | MQTT v5 / v3.1.1, TLS optional, QoS per topic; `+`/`#` wildcards | number: GOOD or GAP (unparseable, reason kept); JSON: value/time/quality paths and the list of good values; Sparkplug B: `is_null` -> GAP, `Quality` property != 192 -> STALE | JSON time path (ISO / epoch s / epoch ms), Sparkplug metric timestamp, else arrival |
89
+
90
+ Credentials never sit in a config file: the file names the environment variables
91
+ that hold them (`GEA_OPCUA_USER`, `GEA_MQTT_PASSWORD`, ...). Sparkplug B aliases
92
+ are learned from any NBIRTH/DBIRTH on the matching edge node, so alias-only DDATA
93
+ resolves. The example configs are in `docs/examples/`; the acceptance suite
94
+ section AB covers the codec, the mappings, the quality rules, replay and the
95
+ hand-off to the store-and-forward buffer, and runs a live in-process OPC UA
96
+ loopback wherever `asyncua` is installed.
97
+
60
98
  ## Layout
61
99
 
62
100
  ```
63
101
  gea/ the package: engines, record layer, reports, monitor, dashboard, cli, shell, acceptance suite
64
102
  gea/catalog/ 52 public archive entries, each with a provenance file
65
- docs/ TESTER_GUIDE.md, REQUIREMENTS_MATRIX.md (the scope-of-work mirror that shaped the reports),
66
- commercial/ (pilot proposal, bench readiness, renders), HISTORY.md (development history)
67
- tools/ import_from_star_magic.py (the importer), register_audit.py, native/ (cli.py, shell.py sources)
68
- tests/ pytest wrapper around the acceptance suite and the no-corpus check
103
+ docs/ TESTER_GUIDE.md, REQUIREMENTS_MATRIX.md (the scope-of-work mirror that shaped the reports), examples/ (port configs),
104
+ SESSION_LOG.md (the working record, session by session),
105
+ commercial/ (pilot proposal, bench readiness, commercial use), HISTORY.md (the ship-by-ship record)
106
+ tools/ standalone_check.py (the self-contained guard: imports, text, metadata; run by ci and ship.ps1)
107
+ CHANGELOG.md per-release summary (a tag ships only with its section); SHIP_LOG.md is written by ship.ps1
108
+ tests/ pytest wrapper around the acceptance suite and the standalone check
69
109
  ```
70
110
 
71
- ## Where the code came from
111
+ ## Basis
72
112
 
73
- The package was imported from the `uqff_downhole_simulator` package of the
74
- Star-Magic-Program repository by `tools/import_from_star_magic.py`, which renames
75
- the modules, removes every dependency on that repository's physics corpus, puts
76
- the gravity kernel on standard constants (CODATA 2018 G, standard gravity, IUGG
77
- mean radius), keeps the rock inventory's seventeen published density anchors and
78
- Vp ranges without their decompositions, and drops the two modules that existed
79
- only to compose numbers from that corpus. `gea/IMPORT_RECORD.md` lists the
80
- source commit and every file's hash. `tools/register_audit.py` lists what
81
- remains of the source program's vocabulary in comments and docstrings.
113
+ GEA-Program is a self-contained package: every module imports only the
114
+ standard library, numpy, the declared optional extras and the package itself,
115
+ and `tools/standalone_check.py` (run by CI and by `ship.ps1`) fails the build
116
+ if that ever changes or if a tracked file names another program. The physics
117
+ is on standard constants - CODATA 2018 G, standard gravity 9.80665 m/s2, the
118
+ IUGG mean Earth radius - and the rock inventory carries seventeen published
119
+ density anchors and Vp ranges with their citations (Telford, Geldart and
120
+ Sheriff; Schon). Every catalogue entry under `gea/catalog/` has a provenance
121
+ file naming its public source.
82
122
 
83
123
  Two statements the product carries on its own model cards: the gauge aging
84
124
  envelope's lower bound is an engineering model with no field validation on
@@ -91,7 +131,8 @@ ACCEPTABLE at the 95 % target. Both are printed, never claimed otherwise.
91
131
  `pyproject.toml` must equal `gea.__version__` (`-Bump x.y.z` sets both), the tag must
92
132
  not exist anywhere, every version in `SHIP_LOG.md` must have its tag, `python -m gea
93
133
  accept` must be green, `SHIP_MESSAGE.txt` must start with the tag; then commit, tag,
94
- push, and the remote tag must be seen before SHIPPED is printed. `-DryRun` runs every
134
+ push, and the remote tag must be seen before SHIPPED is printed. `CHANGELOG.md` must carry a
135
+ section headed by the tag, and `tools/standalone_check.py` must report no findings. `-DryRun` runs every
95
136
  check and changes nothing; `-NoPush` stops after the local tag.
96
137
 
97
138
  ## Publishing to PyPI
@@ -1,10 +1,9 @@
1
1
  # Bench-Test Protocol — Measuring the 1.0324 Suppression Ratio
2
2
 
3
- **Field-tier step 8 (independent evaluation, adopted 2026-08-27).**
4
3
  Status of the quantity under test: `canonical_suppression()` = **1.0324 at
5
4
  unity trims** is today a **DERIVED_HYBRID** composition — industry baseline
6
5
  drift (0.215 %FS/yr class) with HPHT stress dressing, divided by a
7
- locked-primitive GEA composition. It is **not** a measured constant, and the
6
+ the program's suppression composition of three locked constants. It is **not** a measured constant, and the
8
7
  product labels it so everywhere it appears. This protocol is the experiment
9
8
  that would change — or refuse to change — that label.
10
9
 
@@ -77,7 +76,7 @@ product's own honesty rule.
77
76
 
78
77
  - **Confirmed:** `canonical_suppression()`'s label may move from
79
78
  DERIVED_HYBRID to MEASURED_ON_BENCH **with the test ID, dates, apparatus
80
- and per-pair results attached**. The composition's primitives are then a
79
+ and per-pair results attached**. The composition's constants are then a
81
80
  measured-consistent model, not just a labeled one.
82
81
  - **Refuted:** the label stays DERIVED_HYBRID; the refutation (conditions,
83
82
  measured R, uncertainty) is recorded beside it. No silent retuning of
@@ -8,10 +8,10 @@ deep-well (TD ~20,300 ft) six-gauge quartz P/T string with GEA-stabilized
8
8
  drift, transient events, live animation (matplotlib / optional PyQt6), and
9
9
  CSV export.
10
10
 
11
- Provenance: ported 2026-08-22 (Daniel GO) from the 22Aug2026 Grok thread
12
- template (grok_cce7a73b); canonical primitives locked, template tuning knobs
13
- renamed to engineering trims per the knob ruling. See README.md and
14
- PAPER_2256.
11
+ The program aging model composes a fixed drift-suppression factor from three
12
+ locked engineering constants (K_MEX = 25/12, PHI_RES = 0.84, F_TRZ = 0.1); the
13
+ user-facing settings are the two instrument trims (k_structural_trim,
14
+ phi_coupling_trim), never the constants. See README.md.
15
15
 
16
16
  Quick use (headless):
17
17
  from gea import DownholeEngine, SimulatorConfig
@@ -97,6 +97,8 @@ from .modbus import (
97
97
  RegisterMap,
98
98
  load_register_map,
99
99
  )
100
+ from .opcua_port import ASYNCUA_AVAILABLE, OpcUaTap # registers the 'opcua' port at import
101
+ from .mqtt_port import PAHO_AVAILABLE, MqttTap # registers the 'mqtt' port at import
100
102
  from .well_assembler import (
101
103
  WellAssembly, WellComponent, assemble, assemble_ktb_hb, assemble_odp_504b,
102
104
  assemble_site_1027, assemble_u1324, BUILTIN_ASSEMBLIES,
@@ -125,7 +127,7 @@ from .profile_catalog import (
125
127
  read_pangaea_txt,
126
128
  )
127
129
 
128
- __version__ = "0.1.0"
130
+ __version__ = "0.2.0"
129
131
  __all__ = [
130
132
  "calculate_quartz_transducer_hpht_program", "canonical_suppression",
131
133
  "conventional_drift", "drift_comparison",
@@ -1,7 +1,7 @@
1
1
  # This Source Code Form is subject to the terms of the Mozilla Public
2
2
  # License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  # file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- """Headless CLI for the GEA Downhole Simulator (v1.6.0 extension).
4
+ """Headless CLI for the GEA Downhole Simulator.
5
5
 
6
6
  python -m gea run --steps 200 --out run.csv
7
7
  python -m gea service-life --years 5 --out curves.csv
@@ -250,6 +250,18 @@ def main(argv=None) -> int:
250
250
  p_db.add_argument("--name", type=str, default="site")
251
251
  p_db.add_argument("--out", type=str, default="dashboard")
252
252
 
253
+ for name, helptxt in (("opcua", "OPC UA client port: read once or subscribe; record; replay a recording offline"),
254
+ ("mqtt", "MQTT subscriber port (3.1.1/5.0; number | json | Sparkplug B): run; record; replay offline")):
255
+ p_lp = sub.add_parser(name, help=helptxt)
256
+ p_lp.add_argument("--config", type=str, default=None, help="site map JSON (client-owned)")
257
+ p_lp.add_argument("--write-example-config", type=str, default=None, help="write an example map here and exit")
258
+ p_lp.add_argument("--replay", type=str, default=None, help="recording (JSON lines) to replay instead of connecting")
259
+ p_lp.add_argument("--record", type=str, default=None, help="write every received message to this recording")
260
+ p_lp.add_argument("--seconds", type=float, default=10.0, help="subscribe/run duration")
261
+ p_lp.add_argument("--read-once", action="store_true", help="opcua: one Read of all nodes instead of a subscription")
262
+ p_lp.add_argument("--out", type=str, default=None, help="write the records CSV here")
263
+ p_lp.add_argument("--stream-csv", type=str, default=None, help="also write a historian-style CSV the other commands ingest")
264
+
253
265
  p_cs = sub.add_parser("case-study", help="depth sweep, write the one-page markdown case")
254
266
  _add_well_args(p_cs)
255
267
  p_cs.add_argument("--points", type=int, default=12)
@@ -339,7 +351,7 @@ def main(argv=None) -> int:
339
351
  asm = maker()
340
352
  except Exception:
341
353
  # operator-tier assemblies on machines without the private
342
- # data: listed honestly, never crashing the listing (v1.77.0)
354
+ # data: listed plainly, never crashing the listing
343
355
  print(f"{name}: OPERATOR-TIER assembly - private data not "
344
356
  "present on this machine (tier is per-machine, never required)")
345
357
  continue
@@ -372,6 +384,47 @@ def main(argv=None) -> int:
372
384
  rep = Reconciler(_build_config(a)).reconcile(stream, station_map=station_map)
373
385
  import json as _json
374
386
  print(_json.dumps(rep, indent=1))
387
+ elif a.cmd in ("opcua", "mqtt"):
388
+ import json as _json
389
+ from .live_ports import records_to_stream, summarize, write_records_csv
390
+ mod = __import__("gea.opcua_port" if a.cmd == "opcua" else "gea.mqtt_port", fromlist=["x"])
391
+ if a.write_example_config:
392
+ print("config:", mod.write_example_config(a.write_example_config))
393
+ return 0
394
+ if not a.config:
395
+ raise SystemExit(f"{a.cmd} needs --config (or --write-example-config to start one)")
396
+ try:
397
+ if a.replay:
398
+ recs = mod.replay(a.config, a.replay)
399
+ src = f"replay {a.replay}"
400
+ elif a.cmd == "opcua":
401
+ tap = mod.OpcUaTap(a.config, recording_path=a.record).connect()
402
+ try:
403
+ recs = tap.read_once() if a.read_once else tap.subscribe(a.seconds)
404
+ finally:
405
+ tap.close()
406
+ src = tap.cfg["endpoint"]
407
+ else:
408
+ tap = mod.MqttTap(a.config, recording_path=a.record)
409
+ recs = tap.run(a.seconds)
410
+ src = tap.cfg["broker"]["host"]
411
+ except (NotImplementedError, ConnectionError, ValueError) as e:
412
+ raise SystemExit(f"{a.cmd}: {e}") # the reason, without a traceback
413
+ print(f"{a.cmd}: {src}")
414
+ print(_json.dumps(summarize(recs), indent=1))
415
+ if a.out:
416
+ print(" records:", write_records_csv(recs, a.out))
417
+ if a.stream_csv and recs:
418
+ st = records_to_stream(recs, name=a.cmd)
419
+ import csv as _csv
420
+ from datetime import datetime as _dt, timedelta as _td
421
+ t0 = _dt.fromisoformat(st.meta["start_time"])
422
+ with open(a.stream_csv, "w", newline="", encoding="utf-8") as f:
423
+ w = _csv.writer(f)
424
+ w.writerow(["timestamp"] + list(st.channels))
425
+ for i, t in enumerate(st.index):
426
+ w.writerow([(t0 + _td(seconds=float(t))).isoformat()] + ["" if st.channels[c].values[i] != st.channels[c].values[i] else round(float(st.channels[c].values[i]), 4) for c in st.channels])
427
+ print(" stream:", a.stream_csv)
375
428
  elif a.cmd == "dashboard":
376
429
  from . import GAUGE_SPECS, load_gauge_spec_json, DEFAULT_TD_FT
377
430
  from .dashboard import orchestrate