gea-program 0.76.0__tar.gz → 0.77.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 (429) hide show
  1. {gea_program-0.76.0/gea_program.egg-info → gea_program-0.77.0}/PKG-INFO +33 -6
  2. {gea_program-0.76.0 → gea_program-0.77.0}/README.md +32 -5
  3. {gea_program-0.76.0 → gea_program-0.77.0}/gea/__init__.py +1 -1
  4. {gea_program-0.76.0 → gea_program-0.77.0}/gea/__main__.py +16 -3
  5. {gea_program-0.76.0 → gea_program-0.77.0}/gea/acceptance_tests.py +274 -9
  6. gea_program-0.77.0/gea/driller_link.py +278 -0
  7. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/IT_SECURITY.md +9 -0
  8. gea_program-0.77.0/gea/help/driller.md +13 -0
  9. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/install.md +2 -2
  10. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/reader.md +1 -1
  11. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/recorder.md +1 -1
  12. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/01-install.md +2 -2
  13. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/19-dossier-reader.md +1 -1
  14. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/22-updates.md +1 -1
  15. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/25-install-recorder.md +2 -2
  16. gea_program-0.77.0/gea/help/tutorial/28-driller-office.md +24 -0
  17. gea_program-0.77.0/gea/help/tutorial/29-driller-rig.md +21 -0
  18. gea_program-0.77.0/gea/help/tutorial.md +13 -0
  19. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/vpn.md +1 -1
  20. {gea_program-0.76.0 → gea_program-0.77.0}/gea/helplib.py +2 -1
  21. {gea_program-0.76.0 → gea_program-0.77.0}/gea/service.py +26 -0
  22. {gea_program-0.76.0 → gea_program-0.77.0}/gea/tutorial.py +2 -1
  23. {gea_program-0.76.0 → gea_program-0.77.0}/gea/updates.py +3 -3
  24. {gea_program-0.76.0 → gea_program-0.77.0}/gea/vpn.py +2 -1
  25. {gea_program-0.76.0 → gea_program-0.77.0}/gea/web/app.html +29 -1
  26. {gea_program-0.76.0 → gea_program-0.77.0/gea_program.egg-info}/PKG-INFO +33 -6
  27. {gea_program-0.76.0 → gea_program-0.77.0}/gea_program.egg-info/SOURCES.txt +4 -0
  28. {gea_program-0.76.0 → gea_program-0.77.0}/pyproject.toml +1 -1
  29. gea_program-0.76.0/gea/help/tutorial.md +0 -13
  30. {gea_program-0.76.0 → gea_program-0.77.0}/LICENSE +0 -0
  31. {gea_program-0.76.0 → gea_program-0.77.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
  32. {gea_program-0.76.0 → gea_program-0.77.0}/gea/accuracy_statement.py +0 -0
  33. {gea_program-0.76.0 → gea_program-0.77.0}/gea/alarm_engine.py +0 -0
  34. {gea_program-0.76.0 → gea_program-0.77.0}/gea/alerts.py +0 -0
  35. {gea_program-0.76.0 → gea_program-0.77.0}/gea/backup.py +0 -0
  36. {gea_program-0.76.0 → gea_program-0.77.0}/gea/bench.py +0 -0
  37. {gea_program-0.76.0 → gea_program-0.77.0}/gea/bit_seismic.py +0 -0
  38. {gea_program-0.76.0 → gea_program-0.77.0}/gea/blind_harness.py +0 -0
  39. {gea_program-0.76.0 → gea_program-0.77.0}/gea/casing_design.py +0 -0
  40. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
  41. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
  42. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
  43. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
  44. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
  45. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
  46. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
  47. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
  48. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
  49. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
  50. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
  51. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
  52. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
  53. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
  54. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
  55. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
  56. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
  57. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
  58. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
  59. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
  60. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
  61. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
  62. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
  63. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
  64. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
  65. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
  66. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
  67. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
  68. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
  69. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
  70. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
  71. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
  72. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
  73. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
  74. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
  75. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
  76. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
  77. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
  78. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
  79. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
  80. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
  81. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
  82. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
  83. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
  84. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
  85. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
  86. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
  87. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
  88. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
  89. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
  90. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
  91. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
  92. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
  93. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
  94. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
  95. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
  96. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
  97. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
  98. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
  99. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
  100. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
  101. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
  102. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
  103. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
  104. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
  105. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
  106. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
  107. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/med_160_sapropels.txt +0 -0
  108. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
  109. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
  110. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
  111. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
  112. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
  113. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
  114. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
  115. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
  116. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
  117. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
  118. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
  119. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
  120. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
  121. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
  122. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
  123. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
  124. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
  125. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
  126. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
  127. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
  128. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
  129. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
  130. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
  131. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
  132. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
  133. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
  134. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
  135. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
  136. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
  137. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
  138. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
  139. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
  140. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
  141. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
  142. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
  143. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
  144. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog_map.py +0 -0
  145. {gea_program-0.76.0 → gea_program-0.77.0}/gea/catalog_register.py +0 -0
  146. {gea_program-0.76.0 → gea_program-0.77.0}/gea/certificates.py +0 -0
  147. {gea_program-0.76.0 → gea_program-0.77.0}/gea/cli.py +0 -0
  148. {gea_program-0.76.0 → gea_program-0.77.0}/gea/client_reports.py +0 -0
  149. {gea_program-0.76.0 → gea_program-0.77.0}/gea/collision.py +0 -0
  150. {gea_program-0.76.0 → gea_program-0.77.0}/gea/config_versioning.py +0 -0
  151. {gea_program-0.76.0 → gea_program-0.77.0}/gea/conformance.py +0 -0
  152. {gea_program-0.76.0 → gea_program-0.77.0}/gea/control_room.py +0 -0
  153. {gea_program-0.76.0 → gea_program-0.77.0}/gea/correlation.py +0 -0
  154. {gea_program-0.76.0 → gea_program-0.77.0}/gea/dashboard.py +0 -0
  155. {gea_program-0.76.0 → gea_program-0.77.0}/gea/declarations.py +0 -0
  156. {gea_program-0.76.0 → gea_program-0.77.0}/gea/decline.py +0 -0
  157. {gea_program-0.76.0 → gea_program-0.77.0}/gea/deviation.py +0 -0
  158. {gea_program-0.76.0 → gea_program-0.77.0}/gea/dlis.py +0 -0
  159. {gea_program-0.76.0 → gea_program-0.77.0}/gea/dnp3.py +0 -0
  160. {gea_program-0.76.0 → gea_program-0.77.0}/gea/doctor.py +0 -0
  161. {gea_program-0.76.0 → gea_program-0.77.0}/gea/dossier.py +0 -0
  162. {gea_program-0.76.0 → gea_program-0.77.0}/gea/dossier_verify.py +0 -0
  163. {gea_program-0.76.0 → gea_program-0.77.0}/gea/downhole_engine.py +0 -0
  164. {gea_program-0.76.0 → gea_program-0.77.0}/gea/drift_monitor.py +0 -0
  165. {gea_program-0.76.0 → gea_program-0.77.0}/gea/drill_string.py +0 -0
  166. {gea_program-0.76.0 → gea_program-0.77.0}/gea/earth_model.py +0 -0
  167. {gea_program-0.76.0 → gea_program-0.77.0}/gea/economics.py +0 -0
  168. {gea_program-0.76.0 → gea_program-0.77.0}/gea/ed25519.py +0 -0
  169. {gea_program-0.76.0 → gea_program-0.77.0}/gea/edr.py +0 -0
  170. {gea_program-0.76.0 → gea_program-0.77.0}/gea/elevation.py +0 -0
  171. {gea_program-0.76.0 → gea_program-0.77.0}/gea/etp.py +0 -0
  172. {gea_program-0.76.0 → gea_program-0.77.0}/gea/etp12_schemas.json +0 -0
  173. {gea_program-0.76.0 → gea_program-0.77.0}/gea/example_register_map.json +0 -0
  174. {gea_program-0.76.0 → gea_program-0.77.0}/gea/fat_sat.py +0 -0
  175. {gea_program-0.76.0 → gea_program-0.77.0}/gea/field_pull.py +0 -0
  176. {gea_program-0.76.0 → gea_program-0.77.0}/gea/files.py +0 -0
  177. {gea_program-0.76.0 → gea_program-0.77.0}/gea/fixtures/README.md +0 -0
  178. {gea_program-0.76.0 → gea_program-0.77.0}/gea/fixtures/comcat_delaware_basin_2026-09.txt +0 -0
  179. {gea_program-0.76.0 → gea_program-0.77.0}/gea/fixtures/comcat_mahoning_1990-2026.txt +0 -0
  180. {gea_program-0.76.0 → gea_program-0.77.0}/gea/fixtures/comcat_youngstown_2011-2012.txt +0 -0
  181. {gea_program-0.76.0 → gea_program-0.77.0}/gea/fixtures/ne_110m_coastline.json +0 -0
  182. {gea_program-0.76.0 → gea_program-0.77.0}/gea/follower.py +0 -0
  183. {gea_program-0.76.0 → gea_program-0.77.0}/gea/forward_model.py +0 -0
  184. {gea_program-0.76.0 → gea_program-0.77.0}/gea/frac_hits.py +0 -0
  185. {gea_program-0.76.0 → gea_program-0.77.0}/gea/friction_priors.py +0 -0
  186. {gea_program-0.76.0 → gea_program-0.77.0}/gea/gamma.py +0 -0
  187. {gea_program-0.76.0 → gea_program-0.77.0}/gea/gauge_aging.py +0 -0
  188. {gea_program-0.76.0 → gea_program-0.77.0}/gea/gauge_specs.py +0 -0
  189. {gea_program-0.76.0 → gea_program-0.77.0}/gea/geodesy.py +0 -0
  190. {gea_program-0.76.0 → gea_program-0.77.0}/gea/geomag.py +0 -0
  191. {gea_program-0.76.0 → gea_program-0.77.0}/gea/gravity_reference.py +0 -0
  192. {gea_program-0.76.0 → gea_program-0.77.0}/gea/hartip.py +0 -0
  193. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/TESTER_GUIDE.md +0 -0
  194. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/alarms.md +0 -0
  195. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/alerts.md +0 -0
  196. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/audit-update.md +0 -0
  197. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/backup.md +0 -0
  198. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/bit-image.md +0 -0
  199. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/casing.md +0 -0
  200. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/catalog.md +0 -0
  201. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/charts.md +0 -0
  202. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/collision.md +0 -0
  203. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/company-sign-in.md +0 -0
  204. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/conformance.md +0 -0
  205. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/control-room.md +0 -0
  206. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/data-in.md +0 -0
  207. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/declare.md +0 -0
  208. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/decline.md +0 -0
  209. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/dlis.md +0 -0
  210. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/doctor.md +0 -0
  211. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/dossier.md +0 -0
  212. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/drift.md +0 -0
  213. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/drillstring.md +0 -0
  214. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/economics.md +0 -0
  215. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/edr.md +0 -0
  216. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/etp.md +0 -0
  217. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/field-ports.md +0 -0
  218. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/files.md +0 -0
  219. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/frac-hits.md +0 -0
  220. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/historian.md +0 -0
  221. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/https.md +0 -0
  222. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/hydraulics.md +0 -0
  223. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/instruments.md +0 -0
  224. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/interval.md +0 -0
  225. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/invoice-check.md +0 -0
  226. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/map.md +0 -0
  227. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/month-end.md +0 -0
  228. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/notifications.md +0 -0
  229. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/opseis.md +0 -0
  230. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/osdu.md +0 -0
  231. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/pad-summary.md +0 -0
  232. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/patches.md +0 -0
  233. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/penetrator.md +0 -0
  234. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/plan.md +0 -0
  235. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/pore-pressure.md +0 -0
  236. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/ppdm.md +0 -0
  237. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/quakeml.md +0 -0
  238. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/quality.md +0 -0
  239. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/records.md +0 -0
  240. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/report-history.md +0 -0
  241. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/rig-time.md +0 -0
  242. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/rocks.md +0 -0
  243. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/seedlink.md +0 -0
  244. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/seismic.md +0 -0
  245. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/setup.md +0 -0
  246. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/simulation.md +0 -0
  247. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/site.md +0 -0
  248. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/sites.md +0 -0
  249. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/slip.md +0 -0
  250. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/soak.md +0 -0
  251. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/sra.md +0 -0
  252. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/start.md +0 -0
  253. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/structure.md +0 -0
  254. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tools.md +0 -0
  255. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/torque-drag.md +0 -0
  256. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/transients.md +0 -0
  257. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/02-sign-in.md +0 -0
  258. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/03-site.md +0 -0
  259. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/04-add-well.md +0 -0
  260. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/05-records.md +0 -0
  261. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/06-well-page.md +0 -0
  262. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/07-declare.md +0 -0
  263. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/08-patches.md +0 -0
  264. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/09-alarms.md +0 -0
  265. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/10-control-room.md +0 -0
  266. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/11-summary-month.md +0 -0
  267. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/12-where-the-well-is.md +0 -0
  268. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/13-drilling-pages.md +0 -0
  269. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/14-production-pages.md +0 -0
  270. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/15-seismic.md +0 -0
  271. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/16-seismicity.md +0 -0
  272. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/17-recorder-office.md +0 -0
  273. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/18-reports.md +0 -0
  274. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/20-admin.md +0 -0
  275. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/21-upkeep.md +0 -0
  276. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/23-vpn.md +0 -0
  277. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/24-the-box.md +0 -0
  278. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/26-monitor.md +0 -0
  279. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/tutorial/27-mirror-vpn.md +0 -0
  280. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/upkeep.md +0 -0
  281. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/vibration.md +0 -0
  282. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/well-report.md +0 -0
  283. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/well-tests.md +0 -0
  284. {gea_program-0.76.0 → gea_program-0.77.0}/gea/help/well3d.md +0 -0
  285. {gea_program-0.76.0 → gea_program-0.77.0}/gea/housekeeping.py +0 -0
  286. {gea_program-0.76.0 → gea_program-0.77.0}/gea/hydraulics.py +0 -0
  287. {gea_program-0.76.0 → gea_program-0.77.0}/gea/icon.py +0 -0
  288. {gea_program-0.76.0 → gea_program-0.77.0}/gea/interval.py +0 -0
  289. {gea_program-0.76.0 → gea_program-0.77.0}/gea/inverse_engine.py +0 -0
  290. {gea_program-0.76.0 → gea_program-0.77.0}/gea/invoice_check.py +0 -0
  291. {gea_program-0.76.0 → gea_program-0.77.0}/gea/jobs.py +0 -0
  292. {gea_program-0.76.0 → gea_program-0.77.0}/gea/launcher.py +0 -0
  293. {gea_program-0.76.0 → gea_program-0.77.0}/gea/live_ports.py +0 -0
  294. {gea_program-0.76.0 → gea_program-0.77.0}/gea/loadtest.py +0 -0
  295. {gea_program-0.76.0 → gea_program-0.77.0}/gea/matplotlib_demo.py +0 -0
  296. {gea_program-0.76.0 → gea_program-0.77.0}/gea/modbus.py +0 -0
  297. {gea_program-0.76.0 → gea_program-0.77.0}/gea/modbus_rtu.py +0 -0
  298. {gea_program-0.76.0 → gea_program-0.77.0}/gea/model_card.py +0 -0
  299. {gea_program-0.76.0 → gea_program-0.77.0}/gea/month_end.py +0 -0
  300. {gea_program-0.76.0 → gea_program-0.77.0}/gea/mqtt_port.py +0 -0
  301. {gea_program-0.76.0 → gea_program-0.77.0}/gea/notify.py +0 -0
  302. {gea_program-0.76.0 → gea_program-0.77.0}/gea/oidc.py +0 -0
  303. {gea_program-0.76.0 → gea_program-0.77.0}/gea/oidc_mock.py +0 -0
  304. {gea_program-0.76.0 → gea_program-0.77.0}/gea/op_seismicity.py +0 -0
  305. {gea_program-0.76.0 → gea_program-0.77.0}/gea/opcua_port.py +0 -0
  306. {gea_program-0.76.0 → gea_program-0.77.0}/gea/operator_app.py +0 -0
  307. {gea_program-0.76.0 → gea_program-0.77.0}/gea/osdu.py +0 -0
  308. {gea_program-0.76.0 → gea_program-0.77.0}/gea/pad_summary.py +0 -0
  309. {gea_program-0.76.0 → gea_program-0.77.0}/gea/patches.py +0 -0
  310. {gea_program-0.76.0 → gea_program-0.77.0}/gea/pdf_report.py +0 -0
  311. {gea_program-0.76.0 → gea_program-0.77.0}/gea/penetrator.py +0 -0
  312. {gea_program-0.76.0 → gea_program-0.77.0}/gea/permits.py +0 -0
  313. {gea_program-0.76.0 → gea_program-0.77.0}/gea/piwebapi.py +0 -0
  314. {gea_program-0.76.0 → gea_program-0.77.0}/gea/pore_pressure.py +0 -0
  315. {gea_program-0.76.0 → gea_program-0.77.0}/gea/ports.py +0 -0
  316. {gea_program-0.76.0 → gea_program-0.77.0}/gea/ppdm.py +0 -0
  317. {gea_program-0.76.0 → gea_program-0.77.0}/gea/profile_catalog.py +0 -0
  318. {gea_program-0.76.0 → gea_program-0.77.0}/gea/project.py +0 -0
  319. {gea_program-0.76.0 → gea_program-0.77.0}/gea/qt6_downhole_app.py +0 -0
  320. {gea_program-0.76.0 → gea_program-0.77.0}/gea/quakeml.py +0 -0
  321. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reader.py +0 -0
  322. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reader_app.py +0 -0
  323. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reconciler.py +0 -0
  324. {gea_program-0.76.0 → gea_program-0.77.0}/gea/recorder_link.py +0 -0
  325. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
  326. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
  327. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/WMM2025.COF +0 -0
  328. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/eia_henry_hub_daily.csv.gz +0 -0
  329. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/eia_prices.provenance.json +0 -0
  330. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/eia_wti_daily.csv.gz +0 -0
  331. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/iscwsa_rev4_example.json +0 -0
  332. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/iscwsa_rev5_example.json +0 -0
  333. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/l0701_sonic_gr.las.gz +0 -0
  334. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/l0701_sonic_gr.provenance.json +0 -0
  335. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/libmseed_steim.provenance.json +0 -0
  336. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
  337. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
  338. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
  339. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/mahoning_example.json +0 -0
  340. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/mud_motor_specs.json +0 -0
  341. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/owsg_tool_models.json +0 -0
  342. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/penetrator_ratings.json +0 -0
  343. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/seismicity_protocols.json +0 -0
  344. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/tool_sources.json +0 -0
  345. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/us_outline.json +0 -0
  346. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/us_outline.provenance.json +0 -0
  347. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/volve_3d.provenance.json +0 -0
  348. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/volve_f4_interpretation.las.gz +0 -0
  349. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/volve_f4_logs.provenance.json +0 -0
  350. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/volve_f4_lwd.las.gz +0 -0
  351. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/volve_surfaces.json.gz +0 -0
  352. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/volve_traj_F-10.xml.gz +0 -0
  353. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/volve_traj_F-4.xml.gz +0 -0
  354. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/volve_traj_F-5_12.25in.xml.gz +0 -0
  355. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/volve_traj_F-5_17.5in.xml.gz +0 -0
  356. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/volve_traj_F-5_36in.xml.gz +0 -0
  357. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/volve_traj_F-5_8.5in.xml.gz +0 -0
  358. {gea_program-0.76.0 → gea_program-0.77.0}/gea/reference/volve_well_picks.csv.gz +0 -0
  359. {gea_program-0.76.0 → gea_program-0.77.0}/gea/report_history.py +0 -0
  360. {gea_program-0.76.0 → gea_program-0.77.0}/gea/rig_state.py +0 -0
  361. {gea_program-0.76.0 → gea_program-0.77.0}/gea/rock_inventory.py +0 -0
  362. {gea_program-0.76.0 → gea_program-0.77.0}/gea/sample_record.py +0 -0
  363. {gea_program-0.76.0 → gea_program-0.77.0}/gea/sample_well_profile.csv +0 -0
  364. {gea_program-0.76.0 → gea_program-0.77.0}/gea/sbom.py +0 -0
  365. {gea_program-0.76.0 → gea_program-0.77.0}/gea/seedlink.py +0 -0
  366. {gea_program-0.76.0 → gea_program-0.77.0}/gea/segy.py +0 -0
  367. {gea_program-0.76.0 → gea_program-0.77.0}/gea/seismic.py +0 -0
  368. {gea_program-0.76.0 → gea_program-0.77.0}/gea/seismic_array.py +0 -0
  369. {gea_program-0.76.0 → gea_program-0.77.0}/gea/seismic_assoc.py +0 -0
  370. {gea_program-0.76.0 → gea_program-0.77.0}/gea/seismic_detect.py +0 -0
  371. {gea_program-0.76.0 → gea_program-0.77.0}/gea/seismic_film.py +0 -0
  372. {gea_program-0.76.0 → gea_program-0.77.0}/gea/seismic_harmonic.py +0 -0
  373. {gea_program-0.76.0 → gea_program-0.77.0}/gea/seismic_qc.py +0 -0
  374. {gea_program-0.76.0 → gea_program-0.77.0}/gea/seismic_response.py +0 -0
  375. {gea_program-0.76.0 → gea_program-0.77.0}/gea/seismic_signature.py +0 -0
  376. {gea_program-0.76.0 → gea_program-0.77.0}/gea/seismic_track.py +0 -0
  377. {gea_program-0.76.0 → gea_program-0.77.0}/gea/seismic_uncertainty.py +0 -0
  378. {gea_program-0.76.0 → gea_program-0.77.0}/gea/seismic_unlisted.py +0 -0
  379. {gea_program-0.76.0 → gea_program-0.77.0}/gea/seismic_watch.py +0 -0
  380. {gea_program-0.76.0 → gea_program-0.77.0}/gea/sensor_swap.py +0 -0
  381. {gea_program-0.76.0 → gea_program-0.77.0}/gea/series_cache.py +0 -0
  382. {gea_program-0.76.0 → gea_program-0.77.0}/gea/service_life.py +0 -0
  383. {gea_program-0.76.0 → gea_program-0.77.0}/gea/setup_checklist.py +0 -0
  384. {gea_program-0.76.0 → gea_program-0.77.0}/gea/shapefile.py +0 -0
  385. {gea_program-0.76.0 → gea_program-0.77.0}/gea/shell.py +0 -0
  386. {gea_program-0.76.0 → gea_program-0.77.0}/gea/shut_in.py +0 -0
  387. {gea_program-0.76.0 → gea_program-0.77.0}/gea/simulation.py +0 -0
  388. {gea_program-0.76.0 → gea_program-0.77.0}/gea/site_map.py +0 -0
  389. {gea_program-0.76.0 → gea_program-0.77.0}/gea/sla_report.py +0 -0
  390. {gea_program-0.76.0 → gea_program-0.77.0}/gea/slip.py +0 -0
  391. {gea_program-0.76.0 → gea_program-0.77.0}/gea/soak.py +0 -0
  392. {gea_program-0.76.0 → gea_program-0.77.0}/gea/sra.py +0 -0
  393. {gea_program-0.76.0 → gea_program-0.77.0}/gea/store_forward.py +0 -0
  394. {gea_program-0.76.0 → gea_program-0.77.0}/gea/strata_join.py +0 -0
  395. {gea_program-0.76.0 → gea_program-0.77.0}/gea/structure.py +0 -0
  396. {gea_program-0.76.0 → gea_program-0.77.0}/gea/supervisor.py +0 -0
  397. {gea_program-0.76.0 → gea_program-0.77.0}/gea/survey_cmd.py +0 -0
  398. {gea_program-0.76.0 → gea_program-0.77.0}/gea/survey_view.py +0 -0
  399. {gea_program-0.76.0 → gea_program-0.77.0}/gea/telemetry.py +0 -0
  400. {gea_program-0.76.0 → gea_program-0.77.0}/gea/timestamp.py +0 -0
  401. {gea_program-0.76.0 → gea_program-0.77.0}/gea/tls.py +0 -0
  402. {gea_program-0.76.0 → gea_program-0.77.0}/gea/tool_catalog.py +0 -0
  403. {gea_program-0.76.0 → gea_program-0.77.0}/gea/tool_library.py +0 -0
  404. {gea_program-0.76.0 → gea_program-0.77.0}/gea/tool_taxonomy.py +0 -0
  405. {gea_program-0.76.0 → gea_program-0.77.0}/gea/torque_drag.py +0 -0
  406. {gea_program-0.76.0 → gea_program-0.77.0}/gea/transient.py +0 -0
  407. {gea_program-0.76.0 → gea_program-0.77.0}/gea/tray.py +0 -0
  408. {gea_program-0.76.0 → gea_program-0.77.0}/gea/vibration.py +0 -0
  409. {gea_program-0.76.0 → gea_program-0.77.0}/gea/web/reader.html +0 -0
  410. {gea_program-0.76.0 → gea_program-0.77.0}/gea/well3d.py +0 -0
  411. {gea_program-0.76.0 → gea_program-0.77.0}/gea/well_assembler.py +0 -0
  412. {gea_program-0.76.0 → gea_program-0.77.0}/gea/well_records.py +0 -0
  413. {gea_program-0.76.0 → gea_program-0.77.0}/gea/well_report.py +0 -0
  414. {gea_program-0.76.0 → gea_program-0.77.0}/gea/well_test_validation.py +0 -0
  415. {gea_program-0.76.0 → gea_program-0.77.0}/gea/wellplan.py +0 -0
  416. {gea_program-0.76.0 → gea_program-0.77.0}/gea/wellpos.py +0 -0
  417. {gea_program-0.76.0 → gea_program-0.77.0}/gea/winident.py +0 -0
  418. {gea_program-0.76.0 → gea_program-0.77.0}/gea/wits0.py +0 -0
  419. {gea_program-0.76.0 → gea_program-0.77.0}/gea/witsml.py +0 -0
  420. {gea_program-0.76.0 → gea_program-0.77.0}/gea/workspace.py +0 -0
  421. {gea_program-0.76.0 → gea_program-0.77.0}/gea/workspaces.py +0 -0
  422. {gea_program-0.76.0 → gea_program-0.77.0}/gea/x25519.py +0 -0
  423. {gea_program-0.76.0 → gea_program-0.77.0}/gea/xlsx_read.py +0 -0
  424. {gea_program-0.76.0 → gea_program-0.77.0}/gea_program.egg-info/dependency_links.txt +0 -0
  425. {gea_program-0.76.0 → gea_program-0.77.0}/gea_program.egg-info/entry_points.txt +0 -0
  426. {gea_program-0.76.0 → gea_program-0.77.0}/gea_program.egg-info/requires.txt +0 -0
  427. {gea_program-0.76.0 → gea_program-0.77.0}/gea_program.egg-info/top_level.txt +0 -0
  428. {gea_program-0.76.0 → gea_program-0.77.0}/setup.cfg +0 -0
  429. {gea_program-0.76.0 → gea_program-0.77.0}/tests/test_acceptance.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gea-program
3
- Version: 0.76.0
3
+ Version: 0.77.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
@@ -463,9 +463,36 @@ keeps them byte for byte and makes the array and electrode stations of
463
463
  them. `gea help recorder`; the box's README has the parts, the wiring and
464
464
  the clock.
465
465
 
466
+ ### GEA Driller: the directional driller's agent
467
+
468
+ GEA Driller (`driller/`; `GEA-Driller-<version>.tar.gz` on every release;
469
+ since 0.77.0; `gea help driller`) is the program on the rig PC. It reads
470
+ the EDR's WITS0 feed and the pre-drill model of the target layer and, every
471
+ 30 ft of new hole, recommends in the driller's units what to do next:
472
+ build, drop or hold and by how much (toolface and steering ratio for a
473
+ rotary steerable system), the weight on bit, the rotary speed, the flow
474
+ rate, and whether to drill on, circulate, or ream and wash first - with its
475
+ reasons and the confidence of each choice. The driller accepts, rejects or
476
+ records what was done instead, by name; every recommendation, answer and
477
+ command is on record with its hash, and GEA pulls the records into the
478
+ well from the **Drill string** tab's card (`gea workspace --path C:\site
479
+ --action driller-pull --box http://192.168.1.60:8790 --well SWD-1`). The
480
+ agent is a policy trained by proximal policy optimization in a physics
481
+ twin of the lateral - the layer rolling with dip, undulation and faults,
482
+ the gamma and the deep-resistivity boundary the tools read of it, the
483
+ steering tool, the bit, the hydraulics, the hole - on scenes drawn fresh,
484
+ judged against a textbook driller on scenes it never saw; the figures of
485
+ that judgement are a simulation's and are labelled so. Advisory by
486
+ default; the closed loop ships as a design with a switch, armed by a named
487
+ operator for one section, disarming itself on a stale feed, a crossed
488
+ limit or the section's end, through a downlink that keeps every command and
489
+ sends none - no vendor's protocol ships with this version. Before there is
490
+ a rig PC, **Start the twin as the rig** on the same card runs the driller's
491
+ program on the office PC with a scene drilling itself.
492
+
466
493
  ### The tutorial
467
494
 
468
- Every step of GEA and the programs around it, as 27 lessons on the
495
+ Every step of GEA and the programs around it, as 29 lessons on the
469
496
  **Tutorial** tab (since 0.76.0; `gea help tutorial`): the office's lessons
470
497
  first - install, sign in, set up the site, bring wells and data in, the
471
498
  well page, the declarations sheet, the patch panel, alarms and
@@ -475,7 +502,7 @@ seismic, the recorder from the office, reports, the signed dossier and the
475
502
  Reader, users and HTTPS, backups and the gate, new versions from inside
476
503
  the program, GEA-VPN - and the pad attendant's after: the box and its
477
504
  parts, installing the recorder on the Pi, the monitor, the USB mirror and
478
- joining the VPN. Each lesson names who it is for, the page it is done on
505
+ joining the VPN - and GEA Driller from the office and on the rig PC. Each lesson names who it is for, the page it is done on
479
506
  (a button opens it), how long it takes, the numbered steps with the
480
507
  buttons as the page names them, and how you know it worked; each account
481
508
  ticks lessons off. **Print the handout** gives the whole course as one
@@ -800,7 +827,7 @@ unsigned, the key hand-overs - and shows the reports as they were signed. A
800
827
  reader made from the workspace knows the site's key fingerprints, so it
801
828
  says whether a dossier is the site's; it allows no network request, and it
802
829
  leaves the trusted time-stamp to `verify_dossier.py`. For a client who wants
803
- it installed, every release also carries `GEA-Reader-Setup-0.76.0.exe`: GEA
830
+ it installed, every release also carries `GEA-Reader-Setup-0.77.0.exe`: GEA
804
831
  Reader as a Windows program of its own - its own icon and taskbar button,
805
832
  Check with GEA Reader on a dossier's right-click menu, fingerprints the client
806
833
  saves kept on that computer, nothing of GEA-Program. `gea help reader`.
@@ -1565,7 +1592,7 @@ attaches the zips to the GitHub release of that tag.
1565
1592
 
1566
1593
  ### The Windows installer
1567
1594
 
1568
- Every release also carries `GEA-Program-Setup-0.76.0.exe` (for 0.76.0): the
1595
+ Every release also carries `GEA-Program-Setup-0.77.0.exe` (for 0.77.0): the
1569
1596
  same Windows kit installed like any Windows program, for the signed-in user
1570
1597
  alone and with no administrator rights (`%LOCALAPPDATA%\Programs\GEA-Program`).
1571
1598
  It asks for the site workspace (an existing one such as `C:\site` is used as
@@ -1584,7 +1611,7 @@ it, removes the program and leaves the workspace. Silent, for a site's
1584
1611
  software deployment:
1585
1612
 
1586
1613
  ```
1587
- GEA-Program-Setup-0.76.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
1614
+ GEA-Program-Setup-0.77.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
1588
1615
  ```
1589
1616
 
1590
1617
  The setup is built by Inno Setup 6 from `tools/installer.iss` in the same
@@ -424,9 +424,36 @@ keeps them byte for byte and makes the array and electrode stations of
424
424
  them. `gea help recorder`; the box's README has the parts, the wiring and
425
425
  the clock.
426
426
 
427
+ ### GEA Driller: the directional driller's agent
428
+
429
+ GEA Driller (`driller/`; `GEA-Driller-<version>.tar.gz` on every release;
430
+ since 0.77.0; `gea help driller`) is the program on the rig PC. It reads
431
+ the EDR's WITS0 feed and the pre-drill model of the target layer and, every
432
+ 30 ft of new hole, recommends in the driller's units what to do next:
433
+ build, drop or hold and by how much (toolface and steering ratio for a
434
+ rotary steerable system), the weight on bit, the rotary speed, the flow
435
+ rate, and whether to drill on, circulate, or ream and wash first - with its
436
+ reasons and the confidence of each choice. The driller accepts, rejects or
437
+ records what was done instead, by name; every recommendation, answer and
438
+ command is on record with its hash, and GEA pulls the records into the
439
+ well from the **Drill string** tab's card (`gea workspace --path C:\site
440
+ --action driller-pull --box http://192.168.1.60:8790 --well SWD-1`). The
441
+ agent is a policy trained by proximal policy optimization in a physics
442
+ twin of the lateral - the layer rolling with dip, undulation and faults,
443
+ the gamma and the deep-resistivity boundary the tools read of it, the
444
+ steering tool, the bit, the hydraulics, the hole - on scenes drawn fresh,
445
+ judged against a textbook driller on scenes it never saw; the figures of
446
+ that judgement are a simulation's and are labelled so. Advisory by
447
+ default; the closed loop ships as a design with a switch, armed by a named
448
+ operator for one section, disarming itself on a stale feed, a crossed
449
+ limit or the section's end, through a downlink that keeps every command and
450
+ sends none - no vendor's protocol ships with this version. Before there is
451
+ a rig PC, **Start the twin as the rig** on the same card runs the driller's
452
+ program on the office PC with a scene drilling itself.
453
+
427
454
  ### The tutorial
428
455
 
429
- Every step of GEA and the programs around it, as 27 lessons on the
456
+ Every step of GEA and the programs around it, as 29 lessons on the
430
457
  **Tutorial** tab (since 0.76.0; `gea help tutorial`): the office's lessons
431
458
  first - install, sign in, set up the site, bring wells and data in, the
432
459
  well page, the declarations sheet, the patch panel, alarms and
@@ -436,7 +463,7 @@ seismic, the recorder from the office, reports, the signed dossier and the
436
463
  Reader, users and HTTPS, backups and the gate, new versions from inside
437
464
  the program, GEA-VPN - and the pad attendant's after: the box and its
438
465
  parts, installing the recorder on the Pi, the monitor, the USB mirror and
439
- joining the VPN. Each lesson names who it is for, the page it is done on
466
+ joining the VPN - and GEA Driller from the office and on the rig PC. Each lesson names who it is for, the page it is done on
440
467
  (a button opens it), how long it takes, the numbered steps with the
441
468
  buttons as the page names them, and how you know it worked; each account
442
469
  ticks lessons off. **Print the handout** gives the whole course as one
@@ -761,7 +788,7 @@ unsigned, the key hand-overs - and shows the reports as they were signed. A
761
788
  reader made from the workspace knows the site's key fingerprints, so it
762
789
  says whether a dossier is the site's; it allows no network request, and it
763
790
  leaves the trusted time-stamp to `verify_dossier.py`. For a client who wants
764
- it installed, every release also carries `GEA-Reader-Setup-0.76.0.exe`: GEA
791
+ it installed, every release also carries `GEA-Reader-Setup-0.77.0.exe`: GEA
765
792
  Reader as a Windows program of its own - its own icon and taskbar button,
766
793
  Check with GEA Reader on a dossier's right-click menu, fingerprints the client
767
794
  saves kept on that computer, nothing of GEA-Program. `gea help reader`.
@@ -1526,7 +1553,7 @@ attaches the zips to the GitHub release of that tag.
1526
1553
 
1527
1554
  ### The Windows installer
1528
1555
 
1529
- Every release also carries `GEA-Program-Setup-0.76.0.exe` (for 0.76.0): the
1556
+ Every release also carries `GEA-Program-Setup-0.77.0.exe` (for 0.77.0): the
1530
1557
  same Windows kit installed like any Windows program, for the signed-in user
1531
1558
  alone and with no administrator rights (`%LOCALAPPDATA%\Programs\GEA-Program`).
1532
1559
  It asks for the site workspace (an existing one such as `C:\site` is used as
@@ -1545,7 +1572,7 @@ it, removes the program and leaves the workspace. Silent, for a site's
1545
1572
  software deployment:
1546
1573
 
1547
1574
  ```
1548
- GEA-Program-Setup-0.76.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
1575
+ GEA-Program-Setup-0.77.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
1549
1576
  ```
1550
1577
 
1551
1578
  The setup is built by Inno Setup 6 from `tools/installer.iss` in the same
@@ -123,7 +123,7 @@ from .profile_catalog import (
123
123
  read_pangaea_txt,
124
124
  )
125
125
 
126
- __version__ = "0.76.0"
126
+ __version__ = "0.77.0"
127
127
  __all__ = [
128
128
  "aging_rate", "rate_psi_yr", "accuracy_psi",
129
129
  "Sensor", "SimulatorConfig", "DownholeEngine",
@@ -370,7 +370,7 @@ def main(argv=None) -> int:
370
370
  p_ws.add_argument("--path", type=str, required=True, help="the workspace folder")
371
371
  p_ws.add_argument("--action", type=str, default="list",
372
372
  choices=["init", "add-file", "add-catalog", "add-live", "remove", "list", "migrate", "refresh", "audit",
373
- "add-seismic", "refresh-seismic", "remove-seismic", "sar-film", "bit-image", "field-pull", "refresh-all", "add-track", "refresh-track", "remove-track",
373
+ "add-seismic", "refresh-seismic", "remove-seismic", "sar-film", "bit-image", "field-pull", "driller-pull", "refresh-all", "add-track", "refresh-track", "remove-track",
374
374
  "seismic-dataset", "seismic-field", "add-site", "sites", "site-report", "remove-site", "rename",
375
375
  "set-well", "sra-define", "sra-report", "associate", "osdu-export", "quakeml-export", "well-identity", "vibration-report",
376
376
  "add-live-station", "live-fold", "live-run", "month-end", "add-layer", "layers", "remove-layer", "structure", "interval",
@@ -428,7 +428,7 @@ def main(argv=None) -> int:
428
428
  p_ws.add_argument("--truth", type=str, default=None, help="add-track: ground truth CSV (point_id, lat, lon, utc[, note])")
429
429
  p_ws.add_argument("--track", type=str, default=None, help="refresh-track / remove-track: the track id")
430
430
  p_ws.add_argument("--win", type=float, default=600.0, help="add-track: the window length, s (default 600)")
431
- p_ws.add_argument("--box", type=str, default=None, help="field-pull: the recorder's address (http://192.168.1.50:8780, as its page shows) or its mirror folder")
431
+ p_ws.add_argument("--box", type=str, default=None, help="field-pull: the recorder's address (http://192.168.1.50:8780, as its page shows) or its mirror folder; driller-pull: the rig PC's address (http://192.168.1.60:8790)")
432
432
  p_ws.add_argument("--n-stations", type=int, default=24, help="bit-image: ground stations, the reference among them")
433
433
  p_ws.add_argument("--radius", type=float, default=6000.0, help="bit-image: the array's outer ring, ft")
434
434
  p_ws.add_argument("--noise", type=float, default=1.0, help="bit-image: ground noise against a reference arrival of 50")
@@ -1039,7 +1039,7 @@ def main(argv=None) -> int:
1039
1039
  p_vp.add_argument("--subnet", type=str, default=None, help="with --create: the private subnet (default 10.77.0.0/24)")
1040
1040
  p_vp.add_argument("--hub", type=str, default=None, metavar="HOST", help="change the hub's public name or address; every configuration is written again")
1041
1041
  p_vp.add_argument("--add", type=str, default=None, metavar="NAME", help="add a member of this name (Pad 3 box) of the --kind")
1042
- p_vp.add_argument("--kind", type=str, default="box", help="with --add: office, box, operator, reader or other (default box)")
1042
+ p_vp.add_argument("--kind", type=str, default="box", help="with --add: office, box, driller, operator, reader or other (default box)")
1043
1043
  p_vp.add_argument("--remove", type=str, default=None, metavar="ID", help="remove the member of this id (pad-3-box); run the hub installer again after")
1044
1044
  p_vp.add_argument("--bundles", action="store_true", help="write the hub installer and every member's configuration again")
1045
1045
  p_vp.add_argument("--json", action="store_true")
@@ -3563,6 +3563,19 @@ def main(argv=None) -> int:
3563
3563
  if not a.track:
3564
3564
  raise SystemExit("remove-track needs --track TRACK_ID")
3565
3565
  ws.remove_track(a.track, actor=a.actor); print("removed (folder kept):", a.track); return 0
3566
+ elif a.action == "driller-pull":
3567
+ from . import driller_link as DL
3568
+ if not a.box or not a.well:
3569
+ raise SystemExit("driller-pull needs --box http://192.168.1.60:8790 (the rig PC, or the folder of its records) and --well SWD-1")
3570
+ try:
3571
+ r = DL.pull(ws, a.box, a.well, actor=a.actor)
3572
+ except ValueError as e:
3573
+ raise SystemExit(f"driller-pull: {e}")
3574
+ sm = r['summary']
3575
+ print(f"driller-pull: {r['source']} ({r['rig_well']}) into {r['well']}: {len(r['fetched'])} file(s) fetched, {len(r['kept'])} already here, {len(r['bad'])} failed their hash; "
3576
+ f"{sm['decisions']} decisions ({sm['answers']['accept']} accepted, {sm['answers']['reject']} rejected, {sm['answers']['override']} done otherwise), "
3577
+ f"{sm['armed_sections']} armed section(s), {sm['commands']} command(s), {sm['commands_sent']} sent")
3578
+ return 0 if not r['bad'] else 1
3566
3579
  elif a.action == "field-pull":
3567
3580
  from . import field_pull as FP
3568
3581
  if not a.box:
@@ -15243,7 +15243,7 @@ def section_do_reader_program(tmp: str) -> None:
15243
15243
  marks = _re.findall(r'attach-kit\.sh "[^"]*" "[^"]+" "([^"]+)"', wf)
15244
15244
  v = __version__
15245
15245
  assets = [f"gea-program-{v}-win64.zip", f"GEA-Program-Setup-{v}.exe", f"gea-program-{v}-linux-x86_64.zip", f"GEA-Reader-Setup-{v}.exe", f"GEA-Reader-portable-{v}.zip",
15246
- f"GEA-Recorder-{v}.tar.gz"]
15246
+ f"GEA-Recorder-{v}.tar.gz", f"GEA-Driller-{v}.tar.gz"]
15247
15247
  app_id = _re.search(r"AppId=\{\{([0-9A-F-]+)\}", iss)
15248
15248
  c3 = {
15249
15249
  "kit": {"GEA-Reader.html", "GEA-Reader.cmd", "README.txt", "MANIFEST.json", "SHA256SUMS.txt", "reader.ico", "app/gea_reader.py", "app/winident.py",
@@ -15263,7 +15263,7 @@ def section_do_reader_program(tmp: str) -> None:
15263
15263
  and '-m gea_reader ""%1""' in iss,
15264
15264
  "workflow": "windows-reader:" in wf and "tools/build_reader.py" in wf and "tools\\reader_installer.iss" in wf and "-m gea_reader --selftest" in wf
15265
15265
  and "the right-click entry is still there" in wf
15266
- and all(sum(mk in a_ for mk in marks) == 1 for a_ in assets) and len(marks) == 6,
15266
+ and all(sum(mk in a_ for mk in marks) == 1 for a_ in assets) and len(marks) == 7,
15267
15267
  }
15268
15268
  failed3 = [k for k, v_ in c3.items() if not v_]
15269
15269
  ok(not failed3,
@@ -15949,7 +15949,7 @@ def section_ds_updates(tmp: str) -> None:
15949
15949
  pkg = Path(__file__).parent
15950
15950
  d = Path(tmp, "ds"); d.mkdir()
15951
15951
  ws = Workspace.create(str(d / "ws"), "Pad 3 up", actor="tester")
15952
- blobs = {"GEA-Program-Setup-9.9.9.exe": os.urandom(40000), "GEA-Reader-Setup-9.9.9.exe": os.urandom(6000), "GEA-Recorder-9.9.9.tar.gz": os.urandom(2000),
15952
+ blobs = {"GEA-Program-Setup-9.9.9.exe": os.urandom(40000), "GEA-Reader-Setup-9.9.9.exe": os.urandom(6000), "GEA-Recorder-9.9.9.tar.gz": os.urandom(2000), "GEA-Driller-9.9.9.tar.gz": os.urandom(2500),
15953
15953
  "gea-program-9.9.9-win64.zip": os.urandom(500)}
15954
15954
  state = {"port": 0}
15955
15955
 
@@ -15989,14 +15989,14 @@ def section_ds_updates(tmp: str) -> None:
15989
15989
  rec2 = UP.fetch_kits(ws, "tester", release=rel, fetch=fetch)
15990
15990
  on = UP.on_hand(ws)
15991
15991
  c1 = {
15992
- "release": rel["version"] == "9.9.9" and [a["kit"] for a in rel["assets"]] == ["GEA-Program-Setup-", "GEA-Reader-Setup-", "GEA-Recorder-"] and all(a["sha256"] for a in rel["assets"]),
15992
+ "release": rel["version"] == "9.9.9" and [a["kit"] for a in rel["assets"]] == ["GEA-Program-Setup-", "GEA-Reader-Setup-", "GEA-Recorder-", "GEA-Driller-"] and all(a["sha256"] for a in rel["assets"]),
15993
15993
  "unreachable": down.get("error") and down["version"] is None,
15994
- "fetched": all(f["verified"] and f["fetched"] for f in rec["files"]) and len(rec["files"]) == 3 and rec["moved_aside"] == ["GEA-Program-Setup-0.1.0.exe"]
15994
+ "fetched": all(f["verified"] and f["fetched"] for f in rec["files"]) and len(rec["files"]) == 4 and rec["moved_aside"] == ["GEA-Program-Setup-0.1.0.exe"]
15995
15995
  and Path(inst, "_older", "GEA-Program-Setup-0.1.0.exe").is_file() and all(Path(inst, f["name"]).read_bytes() == blobs[f["name"]] for f in rec["files"] if f["name"] != "GEA-Reader-Setup-9.9.9.exe"),
15996
15996
  "state": st["state"] == "behind" and all(st["newest_on_hand"].values()) and st_cur["state"] == "current" and st["last_fetch"]["version"] == "9.9.9",
15997
15997
  "tampered": [f["name"] for f in rec2["files"] if f.get("rejected")] == ["GEA-Reader-Setup-9.9.9.exe"] and not Path(inst, "GEA-Reader-Setup-9.9.9.exe").exists()
15998
- and [f["name"] for f in rec2["files"] if f["verified"] and not f["fetched"]] == ["GEA-Program-Setup-9.9.9.exe", "GEA-Recorder-9.9.9.tar.gz"],
15999
- "on_hand": {h["name"]: h["verified"] for h in on} == {"GEA-Program-Setup-9.9.9.exe": True, "GEA-Recorder-9.9.9.tar.gz": True},
15998
+ and [f["name"] for f in rec2["files"] if f["verified"] and not f["fetched"]] == ["GEA-Program-Setup-9.9.9.exe", "GEA-Recorder-9.9.9.tar.gz", "GEA-Driller-9.9.9.tar.gz"],
15999
+ "on_hand": {h["name"]: h["verified"] for h in on} == {"GEA-Driller-9.9.9.tar.gz": True, "GEA-Program-Setup-9.9.9.exe": True, "GEA-Recorder-9.9.9.tar.gz": True},
16000
16000
  "audit": "update.fetch" in [a["action"] for a in ws.audit_log(20)],
16001
16001
  }
16002
16002
  failed1 = [k for k, v in c1.items() if not v]
@@ -16327,9 +16327,9 @@ def section_du_tutorial(tmp: str) -> None:
16327
16327
  "contract": not bad_contract,
16328
16328
  "pages_exist": not bad_where,
16329
16329
  "both_audiences": {l["who"] for l in ls} == {"office", "pad"} and sum(1 for l in ls if l["who"] == "pad") >= 3,
16330
- "parts": parts_cover and len(TU.PARTS) == 8,
16330
+ "parts": parts_cover and len(TU.PARTS) == 9,
16331
16331
  "buttons_known": not unknown_buttons,
16332
- "every_program": all(any(w in (l["title"] + " " + l["summary"]).lower() for l in ls) for w in ("install", "reader", "recorder", "vpn", "dossier", "patch", "backup")),
16332
+ "every_program": all(any(w in (l["title"] + " " + l["summary"]).lower() for l in ls) for w in ("install", "reader", "recorder", "vpn", "dossier", "patch", "backup", "driller")),
16333
16333
  }
16334
16334
  failed1 = [k for k, v in c1.items() if not v]
16335
16335
  ok(not failed1,
@@ -16409,6 +16409,270 @@ def section_du_tutorial(tmp: str) -> None:
16409
16409
  "it; numbered steps render as a list" + (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
16410
16410
 
16411
16411
 
16412
+ def section_dv_driller(tmp: str) -> None:
16413
+ """Section DV - GEA Driller: the twin's arithmetic (a seed repeats, building turns the bit up, circulating cleans
16414
+ without footage, the limits penalize, a filled hole sticks the pipe), the policy's gradients against finite
16415
+ differences, the shipped policy against the textbook driller on held-out scenes and a short training that
16416
+ learns; the service with the twin as the rig - a decision from the feed, the operator's answers with a name,
16417
+ the records with their hashes, the closed loop armed by name, commanding through the null downlink that sends
16418
+ nothing, disarmed by a crossed limit and by the section's end, refused when not allowed; GEA's pull of the
16419
+ records with a tampered file refused, the summary, the routes, the card, the command, the kit and the help."""
16420
+ import http.cookiejar
16421
+ import importlib
16422
+ import urllib.error
16423
+ import urllib.request
16424
+ from . import __version__
16425
+ from . import driller_link as DL
16426
+ from . import helplib as H
16427
+ from .service import Service, Users
16428
+ from .workspace import Workspace
16429
+ pkg = Path(__file__).parent
16430
+ d = Path(tmp, "dv"); d.mkdir()
16431
+ prog = DL.program()
16432
+ if prog is None:
16433
+ ok(True, "DV the driller's program (gea-driller) is not installed beside GEA in this install; the kit and the setup carry it - nothing to check here")
16434
+ return
16435
+ if prog["env"] and prog["env"] not in sys.path:
16436
+ sys.path.insert(0, prog["env"])
16437
+ T = importlib.import_module("gea_driller.twin"); P = importlib.import_module("gea_driller.policy"); A = importlib.import_module("gea_driller.advisor")
16438
+ C = importlib.import_module("gea_driller.config"); S = importlib.import_module("gea_driller.service")
16439
+ np_ = importlib.import_module("numpy")
16440
+ # -- DV1 the twin ------------------------------------------------------------------------------------------------------
16441
+ r1 = T.run_episode(T.Lateral(T.Scene(0)), T.textbook_action); r2 = T.run_episode(T.Lateral(T.Scene(0)), T.textbook_action)
16442
+ lb = T.Lateral(T.Scene(3)); lb.reset(); lh = T.Lateral(T.Scene(3)); lh.reset()
16443
+ for _ in range(8):
16444
+ lb.step((4, 1, 1, 1, 0)); lh.step((2, 1, 1, 1, 0))
16445
+ lc = T.Lateral(T.Scene(3)); lc.reset(); lc.bed = 0.6; o_, rc, _, ic = lc.step((2, 1, 1, 1, 1))
16446
+ lw = T.Lateral(T.Scene(3)); lw.reset(); lw.bed = 0.05; _, rw, _, _ = lw.step((2, 1, 1, 1, 1)) # conditioning a clean hole costs more
16447
+ # a hole left to fill sticks the pipe, sooner or later, under heavy weight and little flow
16448
+ stuck = 0
16449
+ for sd in range(8):
16450
+ l_ = T.Lateral(T.Scene(100 + sd)); l_.reset(); l_.bed = 0.9
16451
+ while not l_.done and l_.steps < 80:
16452
+ l_.step((2, 2, 0, 0, 0))
16453
+ stuck += 1 if l_.ended == "stuck pipe" else 0
16454
+ # the vibration limit: heavy weight at slow rotation in the shale above costs reward
16455
+ lv = T.Lateral(T.Scene(5)); lv.reset(); lv.tvd = lv.scene.layer_top(0.0) - 15.0
16456
+ _, r_heavy, _, i_heavy = lv.step((2, 2, 0, 1, 0))
16457
+ c1 = {
16458
+ "repeats": abs(r1["reward"] - r2["reward"]) < 1e-9 and r1["footage_ft"] == r2["footage_ft"],
16459
+ "builds": lb.incl > lh.incl + 1.5 and lb.tvd < lh.tvd,
16460
+ "conditioning": lc.bed < 0.6 and lc.footage == 0.0 and rc > rw,
16461
+ "stuck": stuck >= 6,
16462
+ "vibration": i_heavy["vibration"] > T.VIB_LIMIT and r_heavy < 0,
16463
+ "obs": len(T.OBS_NAMES) == T.OBS_SIZE == lb.observe().shape[0] and all(np_.isfinite(lb.observe())),
16464
+ "scene_random": T.Scene(1).thickness != T.Scene(2).thickness and T.Scene(1).describe()["seed"] == 1,
16465
+ }
16466
+ failed1 = [k for k, v in c1.items() if not v]
16467
+ ok(not failed1,
16468
+ "DV1 the twin repeats itself for a seed, building turns the bit upward against holding, conditioning takes no footage and is cheap only when the "
16469
+ "hole needs it, a hole left to fill under heavy weight and little flow sticks the pipe, heavy weight at slow rotation in the shale costs the "
16470
+ "vibration limit, the observation is finite and named, and scenes differ by seed" + (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
16471
+ # -- DV2 the policy ------------------------------------------------------------------------------------------------------
16472
+ pol0 = P.Policy(seed=1)
16473
+ lat = T.Lateral(T.Scene(5)); o = lat.reset(); obs = []; acts = []
16474
+ rr = np_.random.RandomState(0)
16475
+ for _ in range(30):
16476
+ a, lp, v = pol0.act(o, rr); obs.append(o); acts.append(a); o, _, dn, _ = lat.step(a)
16477
+ if dn:
16478
+ o = lat.reset()
16479
+ obs = np_.array(obs); acts = np_.array(acts)
16480
+ old = np_.array([pol0.act(ob, rr)[1] for ob in obs]); adv = rr.normal(size=30); ret = rr.normal(size=30)
16481
+
16482
+ def loss_of(pol):
16483
+ logits, v, _, _ = pol.forward(obs); logp = np_.zeros(30); ent = np_.zeros(30)
16484
+ for hi, sl in enumerate(P.HEAD_SLICES):
16485
+ p_ = P._softmax(logits[:, sl]); logp += np_.log(p_[np_.arange(30), acts[:, hi]]); ent += -(p_ * np_.log(p_)).sum(1)
16486
+ ratio = np_.exp(logp - old)
16487
+ return -np_.mean(np_.minimum(ratio * adv, np_.clip(ratio, 0.8, 1.2) * adv)) + 0.5 * 0.5 * np_.mean((v - ret) ** 2) - 0.01 * ent.mean()
16488
+ g, _ = P._loss_and_grads(pol0, obs, acts, old, adv, ret, 0.2, 0.5, 0.01)
16489
+ grads_ok = True
16490
+ for k in ("W1", "W2", "W3", "b1", "b3"):
16491
+ i = tuple(0 for _ in pol0.p[k].shape); eps = 1e-6
16492
+ pol0.p[k][i] += eps; lp_ = loss_of(pol0); pol0.p[k][i] -= 2 * eps; lm_ = loss_of(pol0); pol0.p[k][i] += eps
16493
+ num = (lp_ - lm_) / (2 * eps)
16494
+ grads_ok = grads_ok and abs(num - g[k][i]) <= 1e-5 * max(1.0, abs(num))
16495
+ shipped = P.Policy.load(S.SHIPPED_POLICY)
16496
+ ev = P.evaluate(P.policy_act_fn(shipped), range(20), "agent"); tb = P.evaluate(T.textbook_action, range(20), "textbook")
16497
+ fresh = P.Policy(seed=5); before = P.evaluate(P.policy_act_fn(fresh), range(10, 14), "fresh")
16498
+ P.train(fresh, seconds=10.0, batch_steps=2048, n_envs=8, scene_seed0=600000)
16499
+ after = P.evaluate(P.policy_act_fn(fresh), range(10, 14), "trained")
16500
+ rt = P.Policy.from_json(shipped.to_json())
16501
+ same = all(np_.allclose(rt.p[k], shipped.p[k]) for k in shipped.p)
16502
+ try:
16503
+ bad = shipped.to_json(); bad["action_sizes"] = [1]; P.Policy.from_json(bad); layout_refused = False
16504
+ except ValueError:
16505
+ layout_refused = True
16506
+ ex = shipped.explain(T.Lateral(T.Scene(2)).reset())
16507
+ c2 = {
16508
+ "gradients": grads_ok,
16509
+ "beats_textbook": ev["reward"] > tb["reward"] and ev["in_layer_pct"] > tb["in_layer_pct"] + 10.0 and ev["stuck"] <= tb["stuck"],
16510
+ "learns": after["reward"] > before["reward"],
16511
+ "file": same and layout_refused and int(shipped.meta.get("trained_steps", 0)) >= 1000000,
16512
+ "explains": set(ex["choices"]) == set(T.ACTION_NAMES) and all(0 < c["confidence"] <= 1 for c in ex["choices"].values()) and ex["choices"]["wob"]["choice"] in T.WOB_CHOICES,
16513
+ }
16514
+ failed2 = [k for k, v in c2.items() if not v]
16515
+ ok(not failed2,
16516
+ f"DV2 the policy's written-out gradients agree with finite differences; the shipped policy ({int(shipped.meta.get('trained_steps', 0)):,} twin steps) beats the "
16517
+ f"textbook driller on twenty held-out scenes (in the layer {ev['in_layer_pct']:.0f}% against {tb['in_layer_pct']:.0f}%, reward {ev['reward']:.0f} against {tb['reward']:.0f}, "
16518
+ "SIMULATION); ten seconds of training raise a fresh policy's return; the file round-trips and another layout is refused; a decision explains itself in "
16519
+ "operational units with a confidence per choice" + (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
16520
+ # -- DV3 the service with the twin as the rig ------------------------------------------------------------------------
16521
+ cfg = json.loads(json.dumps(C.EXAMPLE)); cfg["output"]["dir"] = str(d / "rig"); cfg["status"]["port"] = 0; cfg["status"]["bind"] = "127.0.0.1"
16522
+ cfg["rig"]["transport"] = "sim"; cfg["closed_loop"]["allowed"] = True; cfg["closed_loop"]["stale_s"] = 30; cfg["limits"]["vibration_index"] = 1.2
16523
+ cfg = C.check(cfg)
16524
+ try:
16525
+ C.check(json.loads(json.dumps(cfg)) | {"closed_loop": {"allowed": True, "downlink": "acme"}}); cfg_refused = False
16526
+ except C.ConfigError:
16527
+ cfg_refused = True
16528
+ drl = S.Driller(cfg, policy=shipped, twin_seed=11, twin_pace_s=0.6)
16529
+ drl.start()
16530
+ try:
16531
+ t_end = time.monotonic() + 20
16532
+ while time.monotonic() < t_end and not drl.advisor.current:
16533
+ time.sleep(0.2)
16534
+ cur = dict(drl.advisor.current) if drl.advisor.current else None
16535
+
16536
+ def call(path, body):
16537
+ rq = urllib.request.Request(drl.url + path, data=json.dumps(body).encode(), headers={"Content-Type": "application/json"}, method="POST")
16538
+ try:
16539
+ with urllib.request.urlopen(rq, timeout=5) as r_:
16540
+ return r_.status, json.load(r_)
16541
+ except urllib.error.HTTPError as e:
16542
+ return e.code, json.loads(e.read() or b"{}")
16543
+ s_noname, _ = call("/api/answer", {"what": "accept", "by": ""})
16544
+ s_acc, _ = call("/api/answer", {"what": "accept", "by": "tester"})
16545
+ s_twice, _ = call("/api/answer", {"what": "accept", "by": "tester"})
16546
+ time.sleep(1.5)
16547
+ s_ov, _ = call("/api/answer", {"what": "override", "by": "tester", "note": "held", "override": {"build_deg_100ft": 0.0, "wob_klb": 25}})
16548
+ md = drl.feed.snapshot()["state"]["hole_depth"]
16549
+ s_long, _ = call("/api/arm", {"by": "tester", "to_md": md + 5000})
16550
+ s_arm, armed = call("/api/arm", {"by": "tester", "to_md": md + 150})
16551
+ t_end = time.monotonic() + 30
16552
+ while time.monotonic() < t_end and drl.advisor.armed is not None:
16553
+ time.sleep(0.3)
16554
+ ended_by_section = drl.advisor.arm_log[-1]["event"] == "disarmed" and "drilled" in drl.advisor.arm_log[-1]["reason"]
16555
+ # a crossed limit disarms it at once
16556
+ md = drl.feed.snapshot()["state"]["hole_depth"]
16557
+ s_arm2, _ = call("/api/arm", {"by": "tester", "to_md": md + 400})
16558
+ drl.cfg["limits"]["vibration_index"] = 0.01 # the limit lowered under the running loop: the next look disarms it
16559
+ t_end = time.monotonic() + 8
16560
+ while time.monotonic() < t_end and drl.advisor.armed is not None:
16561
+ time.sleep(0.2)
16562
+ drl.cfg["limits"]["vibration_index"] = 1.2
16563
+ ended_by_limit = drl.advisor.arm_log[-1]["event"] == "disarmed" and "vibration" in drl.advisor.arm_log[-1]["reason"]
16564
+ with urllib.request.urlopen(drl.url + "/live.json", timeout=5) as r_:
16565
+ live = json.load(r_)
16566
+ with urllib.request.urlopen(drl.url + "/live", timeout=5) as r_:
16567
+ screen = r_.read().decode("utf-8")
16568
+ with urllib.request.urlopen(drl.url + "/health", timeout=5) as r_:
16569
+ health = json.load(r_)
16570
+ s_404 = urllib.request.urlopen(urllib.request.Request(drl.url + "/files/../config.json"), timeout=5) if False else None
16571
+ try:
16572
+ urllib.request.urlopen(drl.url + "/files/../../etc/passwd", timeout=5); traversal = False
16573
+ except urllib.error.HTTPError as e:
16574
+ traversal = e.code == 404
16575
+ finally:
16576
+ drl.stop()
16577
+ cmds = [json.loads(l) for l in open(d / "rig" / "commands.jsonl", encoding="utf-8")]
16578
+ decs = [json.loads(l) for l in open(d / "rig" / "decisions.jsonl", encoding="utf-8")]
16579
+ man = json.load(open(d / "rig" / "manifest.json", encoding="utf-8"))
16580
+ # advisory only: arming refused when the config does not allow it
16581
+ cfg2 = json.loads(json.dumps(cfg)); cfg2["output"]["dir"] = str(d / "rig2"); cfg2["closed_loop"]["allowed"] = False
16582
+ drl2 = S.Driller(C.check(cfg2), policy=shipped, twin_seed=12, twin_pace_s=1.0)
16583
+ try:
16584
+ arm_refused = False
16585
+ try:
16586
+ drl2.advisor.arm("tester", 10200.0, 10300.0)
16587
+ except ValueError as e:
16588
+ arm_refused = "not allowed" in str(e)
16589
+ finally:
16590
+ drl2.stop()
16591
+ c3 = {
16592
+ "decision": cur is not None and cur["recommend"]["words"] and cur["recommend"]["wob_klb"] in T.WOB_CHOICES and len(cur["reasons"]) >= 2 and cur["recommend"]["conditioning"] in T.COND_CHOICES,
16593
+ "answers": s_noname == 400 and s_acc == 200 and s_twice == 400 and s_ov == 200 and any((x.get("answer") or {}).get("what") == "override" and x["answer"]["by"] == "tester" for x in decs),
16594
+ "armed": s_long == 400 and s_arm == 200 and armed.get("ok") and s_arm2 == 200 and any(c["event"] == "command" and c["result"]["sent"] is False and c["by"] == "tester" for c in cmds),
16595
+ "disarmed": ended_by_section and ended_by_limit and cmds[-1]["event"] == "disarmed",
16596
+ "refusals": cfg_refused and arm_refused,
16597
+ "screen": live["ok"] and live["twin"]["label"] == "SIMULATION" and "Arm for this section" in screen and "Did something else" in screen and health["program"] == "GEA Driller" and traversal,
16598
+ "manifest": {"decisions.jsonl", "commands.jsonl", "surveys.csv"} <= {f["file"] for f in man["files"]} and all(f["sha256"] for f in man["files"]) and man["program"] == "GEA Driller",
16599
+ }
16600
+ failed3 = [k for k, v in c3.items() if not v]
16601
+ ok(not failed3,
16602
+ "DV3 with the twin as the rig the service makes a decision from the feed in the driller's units with its reasons; answers need a name and come once; "
16603
+ "a section longer than allowed is refused, an armed section's decisions go to the null downlink as commands with the operator's name and nothing sent, "
16604
+ "and the loop disarms itself at the section's end and at a crossed vibration limit; a downlink that does not exist and arming when the config forbids it "
16605
+ "are refused; the screen carries the switch and the answers, the file route refuses a path outside the folder; the manifest names every record with its hash"
16606
+ + (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
16607
+ # -- DV4 GEA's side: the pull, the twin on this computer, the routes, the card, the command, the kit, the help --------------
16608
+ ws = Workspace.create(str(d / "ws"), "Pad 3 driller", actor="tester")
16609
+ w = ws.add_well_records("Pad 3 H-1", actor="tester")
16610
+ r1_ = DL.pull(ws, str(d / "rig"), w["id"], actor="tester")
16611
+ r2_ = DL.pull(ws, str(d / "rig"), w["id"], actor="tester")
16612
+ with open(d / "rig" / "decisions.jsonl", "a", encoding="utf-8") as f:
16613
+ f.write('{"tampered": true}\n')
16614
+ os.remove(Path(ws.path, "wells", w["id"], "driller", "decisions.jsonl")) # the copy here gone, the altered one is fetched and refused
16615
+ r3_ = DL.pull(ws, str(d / "rig"), w["id"], actor="tester")
16616
+ sm = r1_["summary"]
16617
+ try:
16618
+ DL.pull(ws, str(d / "rig"), "no-such-well", actor="tester"); nowell = False
16619
+ except ValueError:
16620
+ nowell = True
16621
+ try:
16622
+ DL.pull(ws, str(d / "ws"), w["id"], actor="tester"); notdriller = False
16623
+ except (ValueError, OSError):
16624
+ notdriller = True
16625
+ Users(str(Path(ws.path, "users.json"))).add("op", "op-pass-123", "operator")
16626
+ svc = Service(ws.path, port=0, scheduler=False).start()
16627
+ base = svc.url.rstrip("/")
16628
+ opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
16629
+
16630
+ def gcall(method, path, body=None):
16631
+ rq = urllib.request.Request(base + path, method=method, data=(json.dumps(body).encode() if body is not None else None))
16632
+ rq.add_header("Content-Type", "application/json"); rq.add_header("X-GEA-Action", "1")
16633
+ try:
16634
+ with opener.open(rq, timeout=60) as rr_:
16635
+ return rr_.status, json.loads(rr_.read())
16636
+ except urllib.error.HTTPError as e:
16637
+ return e.code, json.loads(e.read() or b"{}")
16638
+ try:
16639
+ s_anon, _ = gcall("GET", "/api/driller")
16640
+ gcall("POST", "/api/login", {"name": "op", "password": "op-pass-123"})
16641
+ s_d, dd = gcall("GET", "/api/driller")
16642
+ s_w, dw = gcall("GET", f"/api/driller/{w['id']}")
16643
+ s_bad, _ = gcall("POST", "/api/driller/pull", {"source": "", "well": w["id"]})
16644
+ s_job, job = gcall("POST", "/api/driller/pull", {"source": str(d / "rig"), "well": w["id"]})
16645
+ s_sim_bad, _ = gcall("POST", "/api/driller/sim/start", {"seed": -1})
16646
+ finally:
16647
+ svc.stop()
16648
+ app_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
16649
+ main_src = (pkg / "__main__.py").read_text(encoding="utf-8")
16650
+ wf = (pkg.parent / ".github" / "workflows" / "build-installer.yml").read_text(encoding="utf-8") if (pkg.parent / ".github" / "workflows" / "build-installer.yml").is_file() else None
16651
+ bi = (pkg.parent / "tools" / "build_installer.py").read_text(encoding="utf-8") if (pkg.parent / "tools" / "build_installer.py").is_file() else None
16652
+ from . import vpn as VP
16653
+ c4 = {
16654
+ "pull": set(r1_["fetched"]) == {"decisions.jsonl", "commands.jsonl", "surveys.csv"} and not r1_["bad"] and set(r2_["kept"]) == set(r1_["fetched"]) and not r2_["fetched"],
16655
+ "tampered": r3_["bad"] == ["decisions.jsonl"] and not Path(ws.path, "wells", w["id"], "driller", "decisions.jsonl").is_file() and Path(ws.path, "wells", w["id"], "driller", "commands.jsonl").is_file(),
16656
+ "summary": sm["decisions"] >= 3 and sm["answers"]["accept"] == 1 and sm["answers"]["override"] == 1 and sm["armed_sections"] == 2 and sm["commands"] >= 1 and sm["commands_sent"] == 0
16657
+ and sm["hole_under_advice_ft"] > 0 and sm["answered_by"].get("tester") == 2 and len(sm["last"]) >= 3 and len(sm["disarmed"]) == 2,
16658
+ "refusals": nowell and notdriller,
16659
+ "routes": s_anon in (401, 403) and s_d == 200 and len(dd["wells"]) == 1 and dd["sim"]["label"] == "SIMULATION" and s_w == 200 and dw["well"] == w["id"]
16660
+ and s_bad == 400 and s_job == 200 and "id" in job and s_sim_bad == 400,
16661
+ "audit": {"driller.pull"} <= {a["action"] for a in ws.audit_log()},
16662
+ "card": all(t_ in app_src for t_ in ("drillerCardHtml", "/api/driller/pull", "/api/driller/sim/start", "GEA Driller", "Start the twin as the rig", "Open the driller's screen")),
16663
+ "cli": '"driller-pull"' in main_src and "DL.pull" in main_src,
16664
+ "vpn": VP.KINDS.get("driller") and VP.PORTS.get("driller") == 8790,
16665
+ "kit": (wf is None or ("GEA-Driller-" in wf and "build_driller.py" in wf)) and (bi is None or "gea-driller=={version}" in bi) and (not (pkg.parent / "tools").is_dir() or (pkg.parent / "tools" / "build_driller.py").is_file()),
16666
+ "help": not H.check("driller") and any(t_ == "driller" for t_, _, _ in H.INDEX) and "GEA Driller" in (pkg / "help" / "IT_SECURITY.md").read_text(encoding="utf-8"),
16667
+ }
16668
+ failed4 = [k for k, v in c4.items() if not v]
16669
+ ok(not failed4,
16670
+ "DV4 GEA pulls the driller's records into the well checked against their hashes (a second pull fetches nothing; a file altered after its hash is "
16671
+ "named and not taken), summarizes the decisions, the answers by name, the armed sections and the commands; an unknown well and a folder that is not "
16672
+ "a driller's are refused; the routes (anonymous refused, a bad source 400, the pull as a job, a bad seed 400), the audit line, the Drill string "
16673
+ "card, the workspace command, the VPN kind, the kit and the workflow, and the help page carry it" + (f" [failed: {', '.join(failed4)}]" if failed4 else ""))
16674
+
16675
+
16412
16676
  def main() -> int:
16413
16677
  print("GEA-Program - ACCEPTANCE SUITE (the product gate)")
16414
16678
  # a handle a job subprocess still holds at the end must not turn a finished gate into a traceback on Windows:
@@ -16537,6 +16801,7 @@ def main() -> int:
16537
16801
  section_ds_updates(tmp)
16538
16802
  section_dt_vpn(tmp)
16539
16803
  section_du_tutorial(tmp)
16804
+ section_dv_driller(tmp)
16540
16805
  if _FAILS:
16541
16806
  print(f"[ACCEPTANCE] {len(_FAILS)} FAILURES ({_PASS} passed):")
16542
16807
  for f in _FAILS: