gea-program 0.89.0__tar.gz → 0.90.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 (446) hide show
  1. {gea_program-0.89.0/gea_program.egg-info → gea_program-0.90.0}/PKG-INFO +61 -4
  2. {gea_program-0.89.0 → gea_program-0.90.0}/README.md +60 -3
  3. {gea_program-0.89.0 → gea_program-0.90.0}/gea/__init__.py +1 -1
  4. {gea_program-0.89.0 → gea_program-0.90.0}/gea/__main__.py +65 -0
  5. {gea_program-0.89.0 → gea_program-0.90.0}/gea/acceptance_tests.py +214 -7
  6. gea_program-0.90.0/gea/benchmark.py +272 -0
  7. {gea_program-0.89.0 → gea_program-0.90.0}/gea/dysfunction.py +27 -9
  8. {gea_program-0.89.0 → gea_program-0.90.0}/gea/edr.py +73 -6
  9. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/IT_SECURITY.md +5 -1
  10. gea_program-0.90.0/gea/help/benchmark.md +13 -0
  11. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/driller.md +1 -1
  12. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/dysfunction.md +1 -1
  13. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/edr.md +3 -1
  14. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/install.md +2 -2
  15. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/mcp.md +1 -1
  16. gea_program-0.90.0/gea/help/public-data.md +15 -0
  17. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/reader.md +1 -1
  18. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/recorder.md +1 -1
  19. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/roadmap.md +1 -1
  20. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/01-install.md +2 -2
  21. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/13-drilling-pages.md +10 -8
  22. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/19-dossier-reader.md +1 -1
  23. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/22-updates.md +1 -1
  24. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/23-vpn.md +1 -1
  25. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/25-install-recorder.md +2 -2
  26. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/29-driller-rig.md +1 -1
  27. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial.md +2 -2
  28. {gea_program-0.89.0 → gea_program-0.90.0}/gea/helplib.py +3 -1
  29. {gea_program-0.89.0 → gea_program-0.90.0}/gea/mcp_server.py +7 -0
  30. gea_program-0.90.0/gea/public_pad.py +603 -0
  31. {gea_program-0.89.0 → gea_program-0.90.0}/gea/rig_state.py +5 -2
  32. {gea_program-0.89.0 → gea_program-0.90.0}/gea/roadmap.py +26 -7
  33. {gea_program-0.89.0 → gea_program-0.90.0}/gea/service.py +23 -0
  34. {gea_program-0.89.0 → gea_program-0.90.0}/gea/web/app.html +58 -1
  35. {gea_program-0.89.0 → gea_program-0.90.0/gea_program.egg-info}/PKG-INFO +61 -4
  36. {gea_program-0.89.0 → gea_program-0.90.0}/gea_program.egg-info/SOURCES.txt +4 -0
  37. {gea_program-0.89.0 → gea_program-0.90.0}/pyproject.toml +1 -1
  38. {gea_program-0.89.0 → gea_program-0.90.0}/LICENSE +0 -0
  39. {gea_program-0.89.0 → gea_program-0.90.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
  40. {gea_program-0.89.0 → gea_program-0.90.0}/gea/accuracy_statement.py +0 -0
  41. {gea_program-0.89.0 → gea_program-0.90.0}/gea/alarm_engine.py +0 -0
  42. {gea_program-0.89.0 → gea_program-0.90.0}/gea/alerts.py +0 -0
  43. {gea_program-0.89.0 → gea_program-0.90.0}/gea/backup.py +0 -0
  44. {gea_program-0.89.0 → gea_program-0.90.0}/gea/bench.py +0 -0
  45. {gea_program-0.89.0 → gea_program-0.90.0}/gea/bit_seismic.py +0 -0
  46. {gea_program-0.89.0 → gea_program-0.90.0}/gea/blind_harness.py +0 -0
  47. {gea_program-0.89.0 → gea_program-0.90.0}/gea/calibration.py +0 -0
  48. {gea_program-0.89.0 → gea_program-0.90.0}/gea/casing_design.py +0 -0
  49. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
  50. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
  51. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
  52. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
  53. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
  54. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
  55. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
  56. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
  57. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
  58. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
  59. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
  60. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
  61. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
  62. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
  63. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
  64. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
  65. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
  66. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
  67. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
  68. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
  69. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
  70. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
  71. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
  72. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
  73. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
  74. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
  75. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
  76. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
  77. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
  78. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
  79. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
  80. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
  81. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
  82. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
  83. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
  84. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
  85. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
  86. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
  87. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
  88. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
  89. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
  90. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
  91. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
  92. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
  93. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
  94. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
  95. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
  96. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
  97. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
  98. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
  99. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
  100. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
  101. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
  102. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
  103. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
  104. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
  105. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
  106. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
  107. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
  108. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
  109. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
  110. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
  111. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
  112. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
  113. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
  114. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
  115. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
  116. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/med_160_sapropels.txt +0 -0
  117. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
  118. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
  119. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
  120. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
  121. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
  122. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
  123. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
  124. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
  125. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
  126. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
  127. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
  128. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
  129. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
  130. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
  131. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
  132. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
  133. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
  134. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
  135. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
  136. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
  137. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
  138. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
  139. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
  140. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
  141. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
  142. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
  143. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
  144. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
  145. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
  146. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
  147. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
  148. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
  149. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
  150. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
  151. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
  152. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
  153. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog_map.py +0 -0
  154. {gea_program-0.89.0 → gea_program-0.90.0}/gea/catalog_register.py +0 -0
  155. {gea_program-0.89.0 → gea_program-0.90.0}/gea/certificates.py +0 -0
  156. {gea_program-0.89.0 → gea_program-0.90.0}/gea/cli.py +0 -0
  157. {gea_program-0.89.0 → gea_program-0.90.0}/gea/client_reports.py +0 -0
  158. {gea_program-0.89.0 → gea_program-0.90.0}/gea/collision.py +0 -0
  159. {gea_program-0.89.0 → gea_program-0.90.0}/gea/config_versioning.py +0 -0
  160. {gea_program-0.89.0 → gea_program-0.90.0}/gea/conformance.py +0 -0
  161. {gea_program-0.89.0 → gea_program-0.90.0}/gea/control_room.py +0 -0
  162. {gea_program-0.89.0 → gea_program-0.90.0}/gea/correlation.py +0 -0
  163. {gea_program-0.89.0 → gea_program-0.90.0}/gea/dashboard.py +0 -0
  164. {gea_program-0.89.0 → gea_program-0.90.0}/gea/declarations.py +0 -0
  165. {gea_program-0.89.0 → gea_program-0.90.0}/gea/decline.py +0 -0
  166. {gea_program-0.89.0 → gea_program-0.90.0}/gea/deviation.py +0 -0
  167. {gea_program-0.89.0 → gea_program-0.90.0}/gea/dlis.py +0 -0
  168. {gea_program-0.89.0 → gea_program-0.90.0}/gea/dnp3.py +0 -0
  169. {gea_program-0.89.0 → gea_program-0.90.0}/gea/doctor.py +0 -0
  170. {gea_program-0.89.0 → gea_program-0.90.0}/gea/dossier.py +0 -0
  171. {gea_program-0.89.0 → gea_program-0.90.0}/gea/dossier_verify.py +0 -0
  172. {gea_program-0.89.0 → gea_program-0.90.0}/gea/downhole_engine.py +0 -0
  173. {gea_program-0.89.0 → gea_program-0.90.0}/gea/drift_monitor.py +0 -0
  174. {gea_program-0.89.0 → gea_program-0.90.0}/gea/drill_string.py +0 -0
  175. {gea_program-0.89.0 → gea_program-0.90.0}/gea/driller_link.py +0 -0
  176. {gea_program-0.89.0 → gea_program-0.90.0}/gea/earth_model.py +0 -0
  177. {gea_program-0.89.0 → gea_program-0.90.0}/gea/economics.py +0 -0
  178. {gea_program-0.89.0 → gea_program-0.90.0}/gea/ed25519.py +0 -0
  179. {gea_program-0.89.0 → gea_program-0.90.0}/gea/elevation.py +0 -0
  180. {gea_program-0.89.0 → gea_program-0.90.0}/gea/etp.py +0 -0
  181. {gea_program-0.89.0 → gea_program-0.90.0}/gea/etp12_schemas.json +0 -0
  182. {gea_program-0.89.0 → gea_program-0.90.0}/gea/example_register_map.json +0 -0
  183. {gea_program-0.89.0 → gea_program-0.90.0}/gea/fat_sat.py +0 -0
  184. {gea_program-0.89.0 → gea_program-0.90.0}/gea/field_pull.py +0 -0
  185. {gea_program-0.89.0 → gea_program-0.90.0}/gea/files.py +0 -0
  186. {gea_program-0.89.0 → gea_program-0.90.0}/gea/fixtures/README.md +0 -0
  187. {gea_program-0.89.0 → gea_program-0.90.0}/gea/fixtures/comcat_delaware_basin_2026-09.txt +0 -0
  188. {gea_program-0.89.0 → gea_program-0.90.0}/gea/fixtures/comcat_mahoning_1990-2026.txt +0 -0
  189. {gea_program-0.89.0 → gea_program-0.90.0}/gea/fixtures/comcat_youngstown_2011-2012.txt +0 -0
  190. {gea_program-0.89.0 → gea_program-0.90.0}/gea/fixtures/ne_110m_coastline.json +0 -0
  191. {gea_program-0.89.0 → gea_program-0.90.0}/gea/fluid.py +0 -0
  192. {gea_program-0.89.0 → gea_program-0.90.0}/gea/follower.py +0 -0
  193. {gea_program-0.89.0 → gea_program-0.90.0}/gea/forward_model.py +0 -0
  194. {gea_program-0.89.0 → gea_program-0.90.0}/gea/frac_hits.py +0 -0
  195. {gea_program-0.89.0 → gea_program-0.90.0}/gea/friction_priors.py +0 -0
  196. {gea_program-0.89.0 → gea_program-0.90.0}/gea/front.py +0 -0
  197. {gea_program-0.89.0 → gea_program-0.90.0}/gea/gamma.py +0 -0
  198. {gea_program-0.89.0 → gea_program-0.90.0}/gea/gauge_aging.py +0 -0
  199. {gea_program-0.89.0 → gea_program-0.90.0}/gea/gauge_specs.py +0 -0
  200. {gea_program-0.89.0 → gea_program-0.90.0}/gea/geodesy.py +0 -0
  201. {gea_program-0.89.0 → gea_program-0.90.0}/gea/geomag.py +0 -0
  202. {gea_program-0.89.0 → gea_program-0.90.0}/gea/gravity_reference.py +0 -0
  203. {gea_program-0.89.0 → gea_program-0.90.0}/gea/hartip.py +0 -0
  204. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/TESTER_GUIDE.md +0 -0
  205. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/alarms.md +0 -0
  206. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/alerts.md +0 -0
  207. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/audit-update.md +0 -0
  208. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/backup.md +0 -0
  209. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/bit-image.md +0 -0
  210. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/calibration.md +0 -0
  211. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/casing.md +0 -0
  212. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/catalog.md +0 -0
  213. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/charts.md +0 -0
  214. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/collision.md +0 -0
  215. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/company-sign-in.md +0 -0
  216. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/conformance.md +0 -0
  217. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/control-room.md +0 -0
  218. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/data-in.md +0 -0
  219. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/declare.md +0 -0
  220. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/decline.md +0 -0
  221. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/dlis.md +0 -0
  222. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/doctor.md +0 -0
  223. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/dossier.md +0 -0
  224. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/drift.md +0 -0
  225. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/drillstring.md +0 -0
  226. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/economics.md +0 -0
  227. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/etp.md +0 -0
  228. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/field-ports.md +0 -0
  229. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/files.md +0 -0
  230. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/fluid.md +0 -0
  231. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/frac-hits.md +0 -0
  232. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/front.md +0 -0
  233. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/historian.md +0 -0
  234. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/https.md +0 -0
  235. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/hydraulics.md +0 -0
  236. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/instruments.md +0 -0
  237. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/interval.md +0 -0
  238. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/invoice-check.md +0 -0
  239. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/map.md +0 -0
  240. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/month-end.md +0 -0
  241. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/notifications.md +0 -0
  242. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/opseis.md +0 -0
  243. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/osdu.md +0 -0
  244. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/pad-summary.md +0 -0
  245. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/patches.md +0 -0
  246. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/penetrator.md +0 -0
  247. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/plan.md +0 -0
  248. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/plume.md +0 -0
  249. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/pore-pressure.md +0 -0
  250. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/ppdm.md +0 -0
  251. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/quakeml.md +0 -0
  252. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/quality.md +0 -0
  253. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/records.md +0 -0
  254. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/report-history.md +0 -0
  255. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/rig-time.md +0 -0
  256. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/rocks.md +0 -0
  257. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/seedlink.md +0 -0
  258. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/seismic.md +0 -0
  259. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/setup.md +0 -0
  260. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/simulation.md +0 -0
  261. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/site.md +0 -0
  262. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/sites.md +0 -0
  263. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/slip.md +0 -0
  264. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/soak.md +0 -0
  265. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/sra.md +0 -0
  266. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/start.md +0 -0
  267. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/structure.md +0 -0
  268. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tools.md +0 -0
  269. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/torque-drag.md +0 -0
  270. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/transients.md +0 -0
  271. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/02-sign-in.md +0 -0
  272. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/03-site.md +0 -0
  273. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/04-add-well.md +0 -0
  274. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/05-records.md +0 -0
  275. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/06-well-page.md +0 -0
  276. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/07-declare.md +0 -0
  277. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/08-patches.md +0 -0
  278. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/09-alarms.md +0 -0
  279. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/10-control-room.md +0 -0
  280. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/11-summary-month.md +0 -0
  281. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/12-where-the-well-is.md +0 -0
  282. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/14-production-pages.md +0 -0
  283. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/15-seismic.md +0 -0
  284. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/16-seismicity.md +0 -0
  285. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/17-recorder-office.md +0 -0
  286. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/18-reports.md +0 -0
  287. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/20-admin.md +0 -0
  288. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/21-upkeep.md +0 -0
  289. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/24-the-box.md +0 -0
  290. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/26-monitor.md +0 -0
  291. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/27-mirror-vpn.md +0 -0
  292. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/tutorial/28-driller-office.md +0 -0
  293. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/upkeep.md +0 -0
  294. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/vibration.md +0 -0
  295. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/vpn.md +0 -0
  296. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/well-report.md +0 -0
  297. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/well-tests.md +0 -0
  298. {gea_program-0.89.0 → gea_program-0.90.0}/gea/help/well3d.md +0 -0
  299. {gea_program-0.89.0 → gea_program-0.90.0}/gea/housekeeping.py +0 -0
  300. {gea_program-0.89.0 → gea_program-0.90.0}/gea/hydraulics.py +0 -0
  301. {gea_program-0.89.0 → gea_program-0.90.0}/gea/icon.py +0 -0
  302. {gea_program-0.89.0 → gea_program-0.90.0}/gea/interval.py +0 -0
  303. {gea_program-0.89.0 → gea_program-0.90.0}/gea/inverse_engine.py +0 -0
  304. {gea_program-0.89.0 → gea_program-0.90.0}/gea/invoice_check.py +0 -0
  305. {gea_program-0.89.0 → gea_program-0.90.0}/gea/jobs.py +0 -0
  306. {gea_program-0.89.0 → gea_program-0.90.0}/gea/launcher.py +0 -0
  307. {gea_program-0.89.0 → gea_program-0.90.0}/gea/live_ports.py +0 -0
  308. {gea_program-0.89.0 → gea_program-0.90.0}/gea/loadtest.py +0 -0
  309. {gea_program-0.89.0 → gea_program-0.90.0}/gea/matplotlib_demo.py +0 -0
  310. {gea_program-0.89.0 → gea_program-0.90.0}/gea/modbus.py +0 -0
  311. {gea_program-0.89.0 → gea_program-0.90.0}/gea/modbus_rtu.py +0 -0
  312. {gea_program-0.89.0 → gea_program-0.90.0}/gea/model_card.py +0 -0
  313. {gea_program-0.89.0 → gea_program-0.90.0}/gea/month_end.py +0 -0
  314. {gea_program-0.89.0 → gea_program-0.90.0}/gea/mqtt_port.py +0 -0
  315. {gea_program-0.89.0 → gea_program-0.90.0}/gea/notify.py +0 -0
  316. {gea_program-0.89.0 → gea_program-0.90.0}/gea/oidc.py +0 -0
  317. {gea_program-0.89.0 → gea_program-0.90.0}/gea/oidc_mock.py +0 -0
  318. {gea_program-0.89.0 → gea_program-0.90.0}/gea/op_seismicity.py +0 -0
  319. {gea_program-0.89.0 → gea_program-0.90.0}/gea/opcua_port.py +0 -0
  320. {gea_program-0.89.0 → gea_program-0.90.0}/gea/operator_app.py +0 -0
  321. {gea_program-0.89.0 → gea_program-0.90.0}/gea/osdu.py +0 -0
  322. {gea_program-0.89.0 → gea_program-0.90.0}/gea/pad_summary.py +0 -0
  323. {gea_program-0.89.0 → gea_program-0.90.0}/gea/patches.py +0 -0
  324. {gea_program-0.89.0 → gea_program-0.90.0}/gea/pdf_report.py +0 -0
  325. {gea_program-0.89.0 → gea_program-0.90.0}/gea/penetrator.py +0 -0
  326. {gea_program-0.89.0 → gea_program-0.90.0}/gea/permits.py +0 -0
  327. {gea_program-0.89.0 → gea_program-0.90.0}/gea/piwebapi.py +0 -0
  328. {gea_program-0.89.0 → gea_program-0.90.0}/gea/plume.py +0 -0
  329. {gea_program-0.89.0 → gea_program-0.90.0}/gea/pore_pressure.py +0 -0
  330. {gea_program-0.89.0 → gea_program-0.90.0}/gea/ports.py +0 -0
  331. {gea_program-0.89.0 → gea_program-0.90.0}/gea/ppdm.py +0 -0
  332. {gea_program-0.89.0 → gea_program-0.90.0}/gea/profile_catalog.py +0 -0
  333. {gea_program-0.89.0 → gea_program-0.90.0}/gea/project.py +0 -0
  334. {gea_program-0.89.0 → gea_program-0.90.0}/gea/qt6_downhole_app.py +0 -0
  335. {gea_program-0.89.0 → gea_program-0.90.0}/gea/quakeml.py +0 -0
  336. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reader.py +0 -0
  337. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reader_app.py +0 -0
  338. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reconciler.py +0 -0
  339. {gea_program-0.89.0 → gea_program-0.90.0}/gea/recorder_link.py +0 -0
  340. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
  341. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
  342. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/WMM2025.COF +0 -0
  343. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/eia_henry_hub_daily.csv.gz +0 -0
  344. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/eia_prices.provenance.json +0 -0
  345. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/eia_wti_daily.csv.gz +0 -0
  346. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/iscwsa_rev4_example.json +0 -0
  347. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/iscwsa_rev5_example.json +0 -0
  348. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/l0701_sonic_gr.las.gz +0 -0
  349. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/l0701_sonic_gr.provenance.json +0 -0
  350. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/libmseed_steim.provenance.json +0 -0
  351. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
  352. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
  353. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
  354. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/mahoning_example.json +0 -0
  355. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/mud_motor_specs.json +0 -0
  356. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/owsg_tool_models.json +0 -0
  357. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/penetrator_ratings.json +0 -0
  358. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/seismicity_protocols.json +0 -0
  359. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/tool_sources.json +0 -0
  360. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/us_outline.json +0 -0
  361. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/us_outline.provenance.json +0 -0
  362. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/volve_3d.provenance.json +0 -0
  363. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/volve_f4_interpretation.las.gz +0 -0
  364. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/volve_f4_logs.provenance.json +0 -0
  365. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/volve_f4_lwd.las.gz +0 -0
  366. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/volve_surfaces.json.gz +0 -0
  367. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/volve_traj_F-10.xml.gz +0 -0
  368. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/volve_traj_F-4.xml.gz +0 -0
  369. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/volve_traj_F-5_12.25in.xml.gz +0 -0
  370. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/volve_traj_F-5_17.5in.xml.gz +0 -0
  371. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/volve_traj_F-5_36in.xml.gz +0 -0
  372. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/volve_traj_F-5_8.5in.xml.gz +0 -0
  373. {gea_program-0.89.0 → gea_program-0.90.0}/gea/reference/volve_well_picks.csv.gz +0 -0
  374. {gea_program-0.89.0 → gea_program-0.90.0}/gea/report_history.py +0 -0
  375. {gea_program-0.89.0 → gea_program-0.90.0}/gea/rock_inventory.py +0 -0
  376. {gea_program-0.89.0 → gea_program-0.90.0}/gea/sample_record.py +0 -0
  377. {gea_program-0.89.0 → gea_program-0.90.0}/gea/sample_well_profile.csv +0 -0
  378. {gea_program-0.89.0 → gea_program-0.90.0}/gea/sbom.py +0 -0
  379. {gea_program-0.89.0 → gea_program-0.90.0}/gea/seedlink.py +0 -0
  380. {gea_program-0.89.0 → gea_program-0.90.0}/gea/segy.py +0 -0
  381. {gea_program-0.89.0 → gea_program-0.90.0}/gea/seismic.py +0 -0
  382. {gea_program-0.89.0 → gea_program-0.90.0}/gea/seismic_array.py +0 -0
  383. {gea_program-0.89.0 → gea_program-0.90.0}/gea/seismic_assoc.py +0 -0
  384. {gea_program-0.89.0 → gea_program-0.90.0}/gea/seismic_detect.py +0 -0
  385. {gea_program-0.89.0 → gea_program-0.90.0}/gea/seismic_film.py +0 -0
  386. {gea_program-0.89.0 → gea_program-0.90.0}/gea/seismic_harmonic.py +0 -0
  387. {gea_program-0.89.0 → gea_program-0.90.0}/gea/seismic_qc.py +0 -0
  388. {gea_program-0.89.0 → gea_program-0.90.0}/gea/seismic_response.py +0 -0
  389. {gea_program-0.89.0 → gea_program-0.90.0}/gea/seismic_signature.py +0 -0
  390. {gea_program-0.89.0 → gea_program-0.90.0}/gea/seismic_track.py +0 -0
  391. {gea_program-0.89.0 → gea_program-0.90.0}/gea/seismic_uncertainty.py +0 -0
  392. {gea_program-0.89.0 → gea_program-0.90.0}/gea/seismic_unlisted.py +0 -0
  393. {gea_program-0.89.0 → gea_program-0.90.0}/gea/seismic_watch.py +0 -0
  394. {gea_program-0.89.0 → gea_program-0.90.0}/gea/sensor_swap.py +0 -0
  395. {gea_program-0.89.0 → gea_program-0.90.0}/gea/series_cache.py +0 -0
  396. {gea_program-0.89.0 → gea_program-0.90.0}/gea/service_life.py +0 -0
  397. {gea_program-0.89.0 → gea_program-0.90.0}/gea/setup_checklist.py +0 -0
  398. {gea_program-0.89.0 → gea_program-0.90.0}/gea/shapefile.py +0 -0
  399. {gea_program-0.89.0 → gea_program-0.90.0}/gea/shell.py +0 -0
  400. {gea_program-0.89.0 → gea_program-0.90.0}/gea/shut_in.py +0 -0
  401. {gea_program-0.89.0 → gea_program-0.90.0}/gea/simulation.py +0 -0
  402. {gea_program-0.89.0 → gea_program-0.90.0}/gea/site_map.py +0 -0
  403. {gea_program-0.89.0 → gea_program-0.90.0}/gea/sla_report.py +0 -0
  404. {gea_program-0.89.0 → gea_program-0.90.0}/gea/slip.py +0 -0
  405. {gea_program-0.89.0 → gea_program-0.90.0}/gea/soak.py +0 -0
  406. {gea_program-0.89.0 → gea_program-0.90.0}/gea/sra.py +0 -0
  407. {gea_program-0.89.0 → gea_program-0.90.0}/gea/store_forward.py +0 -0
  408. {gea_program-0.89.0 → gea_program-0.90.0}/gea/strata_join.py +0 -0
  409. {gea_program-0.89.0 → gea_program-0.90.0}/gea/structure.py +0 -0
  410. {gea_program-0.89.0 → gea_program-0.90.0}/gea/supervisor.py +0 -0
  411. {gea_program-0.89.0 → gea_program-0.90.0}/gea/survey_cmd.py +0 -0
  412. {gea_program-0.89.0 → gea_program-0.90.0}/gea/survey_view.py +0 -0
  413. {gea_program-0.89.0 → gea_program-0.90.0}/gea/telemetry.py +0 -0
  414. {gea_program-0.89.0 → gea_program-0.90.0}/gea/timestamp.py +0 -0
  415. {gea_program-0.89.0 → gea_program-0.90.0}/gea/tls.py +0 -0
  416. {gea_program-0.89.0 → gea_program-0.90.0}/gea/tool_catalog.py +0 -0
  417. {gea_program-0.89.0 → gea_program-0.90.0}/gea/tool_library.py +0 -0
  418. {gea_program-0.89.0 → gea_program-0.90.0}/gea/tool_taxonomy.py +0 -0
  419. {gea_program-0.89.0 → gea_program-0.90.0}/gea/torque_drag.py +0 -0
  420. {gea_program-0.89.0 → gea_program-0.90.0}/gea/transient.py +0 -0
  421. {gea_program-0.89.0 → gea_program-0.90.0}/gea/tray.py +0 -0
  422. {gea_program-0.89.0 → gea_program-0.90.0}/gea/tutorial.py +0 -0
  423. {gea_program-0.89.0 → gea_program-0.90.0}/gea/updates.py +0 -0
  424. {gea_program-0.89.0 → gea_program-0.90.0}/gea/vibration.py +0 -0
  425. {gea_program-0.89.0 → gea_program-0.90.0}/gea/vpn.py +0 -0
  426. {gea_program-0.89.0 → gea_program-0.90.0}/gea/web/reader.html +0 -0
  427. {gea_program-0.89.0 → gea_program-0.90.0}/gea/well3d.py +0 -0
  428. {gea_program-0.89.0 → gea_program-0.90.0}/gea/well_assembler.py +0 -0
  429. {gea_program-0.89.0 → gea_program-0.90.0}/gea/well_records.py +0 -0
  430. {gea_program-0.89.0 → gea_program-0.90.0}/gea/well_report.py +0 -0
  431. {gea_program-0.89.0 → gea_program-0.90.0}/gea/well_test_validation.py +0 -0
  432. {gea_program-0.89.0 → gea_program-0.90.0}/gea/wellplan.py +0 -0
  433. {gea_program-0.89.0 → gea_program-0.90.0}/gea/wellpos.py +0 -0
  434. {gea_program-0.89.0 → gea_program-0.90.0}/gea/winident.py +0 -0
  435. {gea_program-0.89.0 → gea_program-0.90.0}/gea/wits0.py +0 -0
  436. {gea_program-0.89.0 → gea_program-0.90.0}/gea/witsml.py +0 -0
  437. {gea_program-0.89.0 → gea_program-0.90.0}/gea/workspace.py +0 -0
  438. {gea_program-0.89.0 → gea_program-0.90.0}/gea/workspaces.py +0 -0
  439. {gea_program-0.89.0 → gea_program-0.90.0}/gea/x25519.py +0 -0
  440. {gea_program-0.89.0 → gea_program-0.90.0}/gea/xlsx_read.py +0 -0
  441. {gea_program-0.89.0 → gea_program-0.90.0}/gea_program.egg-info/dependency_links.txt +0 -0
  442. {gea_program-0.89.0 → gea_program-0.90.0}/gea_program.egg-info/entry_points.txt +0 -0
  443. {gea_program-0.89.0 → gea_program-0.90.0}/gea_program.egg-info/requires.txt +0 -0
  444. {gea_program-0.89.0 → gea_program-0.90.0}/gea_program.egg-info/top_level.txt +0 -0
  445. {gea_program-0.89.0 → gea_program-0.90.0}/setup.cfg +0 -0
  446. {gea_program-0.89.0 → gea_program-0.90.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.89.0
3
+ Version: 0.90.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
@@ -847,7 +847,7 @@ unsigned, the key hand-overs - and shows the reports as they were signed. A
847
847
  reader made from the workspace knows the site's key fingerprints, so it
848
848
  says whether a dossier is the site's; it allows no network request, and it
849
849
  leaves the trusted time-stamp to `verify_dossier.py`. For a client who wants
850
- it installed, every release also carries `GEA-Reader-Setup-0.89.0.exe`: GEA
850
+ it installed, every release also carries `GEA-Reader-Setup-0.90.0.exe`: GEA
851
851
  Reader as a Windows program of its own - its own icon and taskbar button,
852
852
  Check with GEA Reader on a dossier's right-click menu, fingerprints the client
853
853
  saves kept on that computer, nothing of GEA-Program. `gea help reader`.
@@ -1073,6 +1073,63 @@ eras of the protocol are spoken: the stateless revision 2026-07-28 and the
1073
1073
  `initialize` handshake of 2025-11-25 and earlier. The **Assistant access**
1074
1074
  tab (one button adds it to Claude Desktop), `gea mcp`, `gea help mcp`.
1075
1075
 
1076
+ ### Benchmark
1077
+
1078
+ The wells of a pad against one another, and each against the best the pad
1079
+ has done. Every well with a drilling record is measured the same way from
1080
+ its own record - the footage, the days from its first stand to its last,
1081
+ feet per day, the rate on bottom, rotary and sliding, the median connection
1082
+ weight to weight, the trip speeds - and ranked on each count. Then each
1083
+ well is set against the pad's best: the well it would have been had every
1084
+ stretch of hole been drilled at the rate of whichever well was fastest
1085
+ through that stretch (300 ft or more of it), and every connection made in
1086
+ the pad's best quarter. The gap is hours the pad has already shown can be
1087
+ saved, on some well in that stretch - not a forecast, and not a cause: the
1088
+ bit, the motor, the mud and the hole size are not in the record. The
1089
+ **Benchmark** tab, `gea benchmark`, `gea help benchmark`; an assistant
1090
+ reads it as the `benchmark` tool.
1091
+
1092
+ ### Public data: a real pad
1093
+
1094
+ A pad anyone may check. The Utah FORGE project - the U.S. Department of
1095
+ Energy's geothermal field laboratory near Milford, Utah - publishes the
1096
+ rig recorders of five wells drilled through the same basin fill and
1097
+ granite between 2017 and 2023, under Creative Commons Attribution 4.0.
1098
+ `gea public-pad` turns those files into a site of its own, so the rig
1099
+ time, the roadmap, the drilling alerts and the benchmark run on real
1100
+ records before any client's. The program does not contain the files and
1101
+ does not fetch them: the site downloads them in a browser from the
1102
+ Geothermal Data Repository, names the folder, and the program checks each
1103
+ file against the size and the SHA-256 it had when this release was checked
1104
+ with it, converts the three layouts that are not the recorder's own
1105
+ export, attaches each well, and keeps on the record what was done to
1106
+ each - 16A(78)-32's bit depth is RECONSTRUCTED from the block and the
1107
+ slips and is marked so on every page. Every page and report of that site
1108
+ ends with the credit the licence asks for.
1109
+
1110
+ What this release made of them, on the five files as published:
1111
+
1112
+ | Well | Drilled, ft | Days | ft/day | On bottom, ft/h | Median connection, min |
1113
+ |---|---|---|---|---|---|
1114
+ | 58-32 (2017) | 6,288 | 43.5 | 145 | 15.9 | 14.4 |
1115
+ | 16A(78)-32 (2020) | 11,035 | 67.8 | 163 | 34.4 | 11.3 |
1116
+ | 56-32 (2021) | 9,232 | 19.0 | 487 | 46.6 | 7.5 |
1117
+ | 78B-32 (2021) | 9,372 | 29.1 | 322 | 84.7 | 7.7 |
1118
+ | 16B(78)-32 (2023) | 10,490 | 52.4 | 200 | 45.7 | 10.2 |
1119
+
1120
+ Against the pad's best the five wells spent 812 of their 1,256 on-bottom
1121
+ hours beyond it. The roadmap's own check on them is split - running nearer
1122
+ the window was the faster half on two wells and the slower on two - which
1123
+ is the page saying, of wells drilled six years apart in three hole sizes,
1124
+ that one well's parameters are not the next well's roadmap. The drilling
1125
+ alerts, replayed, find 27 motor stalls on the three wells whose records
1126
+ can show one, three falls in off-bottom pressure on 78B-32 that no trip followed
1127
+ and one on 58-32 that a trip out of the hole followed within twelve hours.
1128
+ Data: Utah FORGE, Energy & Geoscience Institute at the University of Utah,
1129
+ funded by the U.S. Department of Energy; Geothermal Data Repository,
1130
+ gdr.openei.org; CC BY 4.0. The **Public data** tab, `gea public-pad`,
1131
+ `gea help public-data`.
1132
+
1076
1133
  ### Plan vs actual and the survey tools
1077
1134
 
1078
1135
  Each well against its directional plan: at every survey station, how far
@@ -1737,7 +1794,7 @@ attaches the zips to the GitHub release of that tag.
1737
1794
 
1738
1795
  ### The Windows installer
1739
1796
 
1740
- Every release also carries `GEA-Program-Setup-0.89.0.exe` (for 0.89.0): the
1797
+ Every release also carries `GEA-Program-Setup-0.90.0.exe` (for 0.90.0): the
1741
1798
  same Windows kit installed like any Windows program, for the signed-in user
1742
1799
  alone and with no administrator rights (`%LOCALAPPDATA%\Programs\GEA-Program`).
1743
1800
  It asks for the site workspace (an existing one such as `C:\site` is used as
@@ -1756,7 +1813,7 @@ it, removes the program and leaves the workspace. Silent, for a site's
1756
1813
  software deployment:
1757
1814
 
1758
1815
  ```
1759
- GEA-Program-Setup-0.89.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
1816
+ GEA-Program-Setup-0.90.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
1760
1817
  ```
1761
1818
 
1762
1819
  The setup is built by Inno Setup 6 from `tools/installer.iss` in the same
@@ -808,7 +808,7 @@ unsigned, the key hand-overs - and shows the reports as they were signed. A
808
808
  reader made from the workspace knows the site's key fingerprints, so it
809
809
  says whether a dossier is the site's; it allows no network request, and it
810
810
  leaves the trusted time-stamp to `verify_dossier.py`. For a client who wants
811
- it installed, every release also carries `GEA-Reader-Setup-0.89.0.exe`: GEA
811
+ it installed, every release also carries `GEA-Reader-Setup-0.90.0.exe`: GEA
812
812
  Reader as a Windows program of its own - its own icon and taskbar button,
813
813
  Check with GEA Reader on a dossier's right-click menu, fingerprints the client
814
814
  saves kept on that computer, nothing of GEA-Program. `gea help reader`.
@@ -1034,6 +1034,63 @@ eras of the protocol are spoken: the stateless revision 2026-07-28 and the
1034
1034
  `initialize` handshake of 2025-11-25 and earlier. The **Assistant access**
1035
1035
  tab (one button adds it to Claude Desktop), `gea mcp`, `gea help mcp`.
1036
1036
 
1037
+ ### Benchmark
1038
+
1039
+ The wells of a pad against one another, and each against the best the pad
1040
+ has done. Every well with a drilling record is measured the same way from
1041
+ its own record - the footage, the days from its first stand to its last,
1042
+ feet per day, the rate on bottom, rotary and sliding, the median connection
1043
+ weight to weight, the trip speeds - and ranked on each count. Then each
1044
+ well is set against the pad's best: the well it would have been had every
1045
+ stretch of hole been drilled at the rate of whichever well was fastest
1046
+ through that stretch (300 ft or more of it), and every connection made in
1047
+ the pad's best quarter. The gap is hours the pad has already shown can be
1048
+ saved, on some well in that stretch - not a forecast, and not a cause: the
1049
+ bit, the motor, the mud and the hole size are not in the record. The
1050
+ **Benchmark** tab, `gea benchmark`, `gea help benchmark`; an assistant
1051
+ reads it as the `benchmark` tool.
1052
+
1053
+ ### Public data: a real pad
1054
+
1055
+ A pad anyone may check. The Utah FORGE project - the U.S. Department of
1056
+ Energy's geothermal field laboratory near Milford, Utah - publishes the
1057
+ rig recorders of five wells drilled through the same basin fill and
1058
+ granite between 2017 and 2023, under Creative Commons Attribution 4.0.
1059
+ `gea public-pad` turns those files into a site of its own, so the rig
1060
+ time, the roadmap, the drilling alerts and the benchmark run on real
1061
+ records before any client's. The program does not contain the files and
1062
+ does not fetch them: the site downloads them in a browser from the
1063
+ Geothermal Data Repository, names the folder, and the program checks each
1064
+ file against the size and the SHA-256 it had when this release was checked
1065
+ with it, converts the three layouts that are not the recorder's own
1066
+ export, attaches each well, and keeps on the record what was done to
1067
+ each - 16A(78)-32's bit depth is RECONSTRUCTED from the block and the
1068
+ slips and is marked so on every page. Every page and report of that site
1069
+ ends with the credit the licence asks for.
1070
+
1071
+ What this release made of them, on the five files as published:
1072
+
1073
+ | Well | Drilled, ft | Days | ft/day | On bottom, ft/h | Median connection, min |
1074
+ |---|---|---|---|---|---|
1075
+ | 58-32 (2017) | 6,288 | 43.5 | 145 | 15.9 | 14.4 |
1076
+ | 16A(78)-32 (2020) | 11,035 | 67.8 | 163 | 34.4 | 11.3 |
1077
+ | 56-32 (2021) | 9,232 | 19.0 | 487 | 46.6 | 7.5 |
1078
+ | 78B-32 (2021) | 9,372 | 29.1 | 322 | 84.7 | 7.7 |
1079
+ | 16B(78)-32 (2023) | 10,490 | 52.4 | 200 | 45.7 | 10.2 |
1080
+
1081
+ Against the pad's best the five wells spent 812 of their 1,256 on-bottom
1082
+ hours beyond it. The roadmap's own check on them is split - running nearer
1083
+ the window was the faster half on two wells and the slower on two - which
1084
+ is the page saying, of wells drilled six years apart in three hole sizes,
1085
+ that one well's parameters are not the next well's roadmap. The drilling
1086
+ alerts, replayed, find 27 motor stalls on the three wells whose records
1087
+ can show one, three falls in off-bottom pressure on 78B-32 that no trip followed
1088
+ and one on 58-32 that a trip out of the hole followed within twelve hours.
1089
+ Data: Utah FORGE, Energy & Geoscience Institute at the University of Utah,
1090
+ funded by the U.S. Department of Energy; Geothermal Data Repository,
1091
+ gdr.openei.org; CC BY 4.0. The **Public data** tab, `gea public-pad`,
1092
+ `gea help public-data`.
1093
+
1037
1094
  ### Plan vs actual and the survey tools
1038
1095
 
1039
1096
  Each well against its directional plan: at every survey station, how far
@@ -1698,7 +1755,7 @@ attaches the zips to the GitHub release of that tag.
1698
1755
 
1699
1756
  ### The Windows installer
1700
1757
 
1701
- Every release also carries `GEA-Program-Setup-0.89.0.exe` (for 0.89.0): the
1758
+ Every release also carries `GEA-Program-Setup-0.90.0.exe` (for 0.90.0): the
1702
1759
  same Windows kit installed like any Windows program, for the signed-in user
1703
1760
  alone and with no administrator rights (`%LOCALAPPDATA%\Programs\GEA-Program`).
1704
1761
  It asks for the site workspace (an existing one such as `C:\site` is used as
@@ -1717,7 +1774,7 @@ it, removes the program and leaves the workspace. Silent, for a site's
1717
1774
  software deployment:
1718
1775
 
1719
1776
  ```
1720
- GEA-Program-Setup-0.89.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
1777
+ GEA-Program-Setup-0.90.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
1721
1778
  ```
1722
1779
 
1723
1780
  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.89.0"
126
+ __version__ = "0.90.0"
127
127
  __all__ = [
128
128
  "aging_rate", "rate_psi_yr", "accuracy_psi",
129
129
  "Sensor", "SimulatorConfig", "DownholeEngine",
@@ -677,6 +677,19 @@ def main(argv=None) -> int:
677
677
  p_os.add_argument("--actor", type=str, default="cli")
678
678
  p_os.add_argument("--json", action="store_true")
679
679
 
680
+ p_bm = sub.add_parser("benchmark", help="the wells of a pad against one another: feet per day, on-bottom rate, connections and trips ranked, and each well against the pad's best - every stretch at the rate of the fastest well through it")
681
+ p_bm.add_argument("--workspace", type=str, default=None, help="the workspace folder; without one the self-test runs")
682
+ p_bm.add_argument("--write", action="store_true", help="write reports/benchmark/benchmark.json, .md, .csv and stretches.csv")
683
+ p_bm.add_argument("--actor", type=str, default="cli")
684
+ p_bm.add_argument("--json", action="store_true")
685
+ p_pp = sub.add_parser("public-pad", help="a real pad from public data: the Utah FORGE wells' published rig recorders (CC BY 4.0) made into a site of their own - the files to get and where, checked against their sizes and hashes, converted and attached; the program fetches nothing")
686
+ p_pp.add_argument("--folder", type=str, default=None, help="the folder the downloaded files are in; with nothing else, lists each file and whether it is there. Without a folder the self-test runs (stand-ins in each published layout)")
687
+ p_pp.add_argument("--verify", action="store_true", help="hash each file that is there against the SHA-256 this release was checked with")
688
+ p_pp.add_argument("--build", action="store_true", help="make the site at --site from the files in --folder, or add to it the wells it does not have yet")
689
+ p_pp.add_argument("--site", type=str, default=None, help="--build: the folder the site's workspace is made in")
690
+ p_pp.add_argument("--list", action="store_true", help="list the dataset's files, sizes, hashes and where each is published, and exit")
691
+ p_pp.add_argument("--actor", type=str, default="cli")
692
+ p_pp.add_argument("--json", action="store_true")
680
693
  p_mc = sub.add_parser("mcp", help="the site, readable by an assistant: a Model Context Protocol server on standard input and output - local (no port), read-only (every tool reads one of the program's pages, none changes anything), logged; with --workspace alone it serves until its input closes")
681
694
  p_mc.add_argument("--workspace", type=str, default=None, help="the workspace folder; without one the self-test runs (both eras of the protocol against a labelled site)")
682
695
  p_mc.add_argument("--allow", type=str, default=None, help="serve only these tools this run, comma-separated (never more than the site offers)")
@@ -3575,6 +3588,58 @@ def main(argv=None) -> int:
3575
3588
  for v in f_["versions"][: (50 if a.family else 3)]:
3576
3589
  print(f" {v['utc']} {v.get('report_id') or ''} reports/{v['dir']}")
3577
3590
  return 0
3591
+ elif a.cmd == "benchmark":
3592
+ import json as _json
3593
+ from . import benchmark as _BM
3594
+ from .cli import _safe_stdout
3595
+ from .workspace import Workspace, WorkspaceError
3596
+ _safe_stdout()
3597
+ if not a.workspace:
3598
+ r = _BM.selftest()
3599
+ print("\n".join(f"{'PASS' if c['pass'] else 'FAIL'} {c['check']}: {c['value']}" for c in r["checks"]) + f"\n{'OK' if r['ok'] else 'FAILED'} - {r['label']}")
3600
+ return 0 if r["ok"] else 1
3601
+ try:
3602
+ ws = Workspace(a.workspace)
3603
+ if a.write:
3604
+ from . import __version__ as _ver90b
3605
+ r = _BM.write_report(ws, _ver90b, a.actor)
3606
+ print(f"written: {', '.join(r['files'])} under {r['folder']}")
3607
+ p = _BM.page(ws)
3608
+ except (_BM.BenchmarkError, WorkspaceError, ValueError, OSError) as e:
3609
+ raise SystemExit(f"benchmark: {e.args[0] if e.args else e}")
3610
+ print(_json.dumps(p, default=str) if a.json else _BM.text(p))
3611
+ return 0
3612
+ elif a.cmd == "public-pad":
3613
+ import json as _json
3614
+ from . import public_pad as _PP
3615
+ from .cli import _safe_stdout
3616
+ _safe_stdout()
3617
+ if not a.folder and not a.list:
3618
+ r = _PP.selftest()
3619
+ print("\n".join(f"{'PASS' if c['pass'] else 'FAIL'} {c['check']}: {c['value']}" for c in r["checks"]) + f"\n{'OK' if r['ok'] else 'FAILED'} - {r['label']}")
3620
+ return 0 if r["ok"] else 1
3621
+ try:
3622
+ if a.build:
3623
+ if not a.site:
3624
+ raise SystemExit("public-pad: --build needs --site, the folder the site is made in")
3625
+ last_ = {"t": ""}
3626
+
3627
+ def say_(d_):
3628
+ t_ = f"{d_.get('well', '')} {d_.get('step', '')}".strip()
3629
+ if t_ != last_["t"] and d_.get("step") != "done":
3630
+ last_["t"] = t_
3631
+ print(f" {d_.get('n', '')}/{d_.get('of', '')} {t_}", flush=True)
3632
+ r = _PP.build(a.folder, a.site, a.actor, verify=True, progress=say_)
3633
+ print(f"{r['name']} at {r['path']}: " + (f"added {', '.join(r['added'])}" if r["added"] else "nothing to add") + f"; it has {', '.join(r['wells'])}")
3634
+ for e_ in r["record"]["wells"]:
3635
+ for n_ in e_["notes"]:
3636
+ print(f" {e_['well']}: {n_}")
3637
+ return 0
3638
+ s_ = _PP.status(a.folder or "", verify=a.verify)
3639
+ except (_PP.PublicPadError, OSError) as e:
3640
+ raise SystemExit(f"public-pad: {e.args[0] if e.args else e}")
3641
+ print(_json.dumps(s_, default=str) if a.json else _PP.text(s_))
3642
+ return 0
3578
3643
  elif a.cmd == "mcp":
3579
3644
  import json as _json
3580
3645
  from . import mcp_server as _MC
@@ -18578,10 +18578,10 @@ def section_eg_dysfunction(tmp: str) -> None:
18578
18578
 
18579
18579
  # -- EG2 a workspace: the replay, the live record, the alert ------------------------------------------------------------
18580
18580
  wsp = str(d / "ws"); ws = Workspace.create(wsp, "Pad EG", actor="tester")
18581
- rec = DY.synthetic_record(True)
18581
+ rec = DY.synthetic_record(True, ends_now=True)
18582
18582
  DY.write_edr(rec, str(d / "rig.csv"))
18583
18583
  wid = ws.add_well_file(str(d / "rig.csv"), display="RIG-1", actor="tester")["id"]
18584
- DY.write_edr(DY.synthetic_record(False, seed=5), str(d / "sound.csv"))
18584
+ DY.write_edr(DY.synthetic_record(False, seed=5, ends_now=True), str(d / "sound.csv"))
18585
18585
  wid2 = ws.add_well_file(str(d / "sound.csv"), display="RIG-2", actor="tester")["id"]
18586
18586
  pg = DY.page(ws)
18587
18587
  w1 = next(w_ for w_ in pg["wells"] if w_["well"] == wid); w2 = next(w_ for w_ in pg["wells"] if w_["well"] == wid2)
@@ -18763,7 +18763,7 @@ def section_eh_mcp(tmp: str) -> None:
18763
18763
  plain = MC._plain({"a": np.float64(1.5), "_work": [1, 2], "b": [np.int64(3), float("nan")], "c": np.arange(4), "d": (1, "x")})
18764
18764
  c1 = {
18765
18765
  "selftest": st["ok"] and len(st["checks"]) >= 7,
18766
- "tools": len(defs) == 23 and defs[0]["name"] == "site" and all(d_["annotations"]["readOnlyHint"] is True and d_["annotations"]["destructiveHint"] is False and d_["annotations"]["openWorldHint"] is False
18766
+ "tools": len(defs) == 24 and defs[0]["name"] == "site" and all(d_["annotations"]["readOnlyHint"] is True and d_["annotations"]["destructiveHint"] is False and d_["annotations"]["openWorldHint"] is False
18767
18767
  and d_["inputSchema"]["type"] == "object" and d_["inputSchema"]["additionalProperties"] is False and d_["title"] for d_ in defs)
18768
18768
  and "well" in defs[1]["inputSchema"]["properties"] and "json" in defs[2]["inputSchema"]["properties"] and "json" not in MC.tool_definition("help")["inputSchema"]["properties"]
18769
18769
  and not [n_ for n_ in MC.NAMES if any(w_ in n_ for w_ in ("write", "set", "declare", "attach", "remove", "delete", "run"))],
@@ -18775,7 +18775,7 @@ def section_eh_mcp(tmp: str) -> None:
18775
18775
  failed1 = [k_ for k_, v in c1.items() if not v]
18776
18776
  ok(not failed1,
18777
18777
  "EH1 the MCP server: the self-test (a client of an earlier revision through its handshake and a client of revision 2026-07-28 statelessly, each listing and calling the tools; a line that is "
18778
- "not JSON, a tool, a well, an argument and a method that do not exist, a batch; a withheld tool; the access log; an assistant's configuration file added to and restored); twenty-three tools, "
18778
+ "not JSON, a tool, a well, an argument and a method that do not exist, a batch; a withheld tool; the access log; an assistant's configuration file added to and restored); twenty-four tools, "
18779
18779
  "each read-only by its own declaration with its arguments closed, none named for a change; the revisions spoken; the command a client starts - the console interpreter, never the windowless "
18780
18780
  "one; a page as plain JSON with the working arrays left out" + (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
18781
18781
 
@@ -18853,12 +18853,12 @@ def section_eh_mcp(tmp: str) -> None:
18853
18853
  and "SIMULATION" in answers["pressure_plume"]["text"].splitlines()[0] and "RIG-1" in answers["site"]["text"] and _ver in answers["site"]["text"],
18854
18854
  "json": all(isinstance(v, (dict, list)) for n_, v in parsed.items() if n_ != "well") and parsed["well"] is None and as_json["well"]["is_error"] and parsed["roadmap"]["status"] == "OK" and not [k_ for k_ in parsed["rig_time"] if str(k_).startswith("_")]
18855
18855
  and len(parsed["drilling_alerts"]["wells"]) == 2,
18856
- "child_legacy": rc_o == 0 and len(out_o) == 4 and out_o[0]["result"]["protocolVersion"] == "2025-11-25" and len(out_o[1]["result"]["tools"]) == 23 and "resultType" not in out_o[1]["result"]
18856
+ "child_legacy": rc_o == 0 and len(out_o) == 4 and out_o[0]["result"]["protocolVersion"] == "2025-11-25" and len(out_o[1]["result"]["tools"]) == 24 and "resultType" not in out_o[1]["result"]
18857
18857
  and out_o[2]["result"]["content"][0]["text"] == answers["rig_time"]["text"] and "motor stall" in out_o[3]["result"]["content"][0]["text"] and "Traceback" not in err_o,
18858
18858
  "child_modern": rc_m == 0 and len(out_m) == 4 and out_m[0]["result"]["supportedVersions"] == list(MC.SUPPORTED) and out_m[1]["result"]["resultType"] == "complete"
18859
18859
  and out_m[1]["result"]["cacheScope"] == "private" and out_m[2]["result"]["_meta"][MC.K_SERVER] == {"name": "gea-program", "title": "GEA-Program", "version": _ver}
18860
18860
  and out_m[2]["result"]["isError"] is False and out_m[3]["error"]["code"] == -32022 and out_m[3]["error"]["data"]["requested"] == "2099-01-01" and "Traceback" not in err_m,
18861
- "withheld": kept["tools"] is not None and "audit" not in kept["tools"] and rc_w == 0 and "audit" not in [t_["name"] for t_ in out_w[0]["result"]["tools"]] and len(out_w[0]["result"]["tools"]) == 22
18861
+ "withheld": kept["tools"] is not None and "audit" not in kept["tools"] and rc_w == 0 and "audit" not in [t_["name"] for t_ in out_w[0]["result"]["tools"]] and len(out_w[0]["result"]["tools"]) == 23
18862
18862
  and out_w[1]["error"]["code"] == -32602 and "[cut at 3,000 of" in out_w[2]["result"]["content"][0]["text"],
18863
18863
  "narrowed": rc_a == 0 and [t_["name"] for t_ in out_a[0]["result"]["tools"]] == ["site"] and out_a[1]["error"]["code"] == -32602,
18864
18864
  "no_workspace": rc_x.returncode == 2 and rc_x.stdout == b"" and b"not a workspace" in rc_x.stderr,
@@ -18926,7 +18926,7 @@ def section_eh_mcp(tmp: str) -> None:
18926
18926
  its = (pkg / "help" / "IT_SECURITY.md").read_text(encoding="utf-8")
18927
18927
  backups = sorted(p_.name for p_ in cfgp.parent.iterdir() if ".before-gea-" in p_.name)
18928
18928
  c3 = {
18929
- "api": s_vg == 200 and len(vg["tools"]) == 23 and all(t_["offered"] for t_ in vg["tools"]) and vg["config"]["mcpServers"]["gea"]["args"][-1] == os.path.abspath(wsp) and len(vg["log"]) >= 6
18929
+ "api": s_vg == 200 and len(vg["tools"]) == 24 and all(t_["offered"] for t_ in vg["tools"]) and vg["config"]["mcpServers"]["gea"]["args"][-1] == os.path.abspath(wsp) and len(vg["log"]) >= 6
18930
18930
  and vg["claude_desktop"]["found"] and not vg["claude_desktop"]["installed"] and s_vs == 403 and s_os == 200 and os_["offered"] == ["site", "roadmap", "help"] and os_["max_chars"] == 20000
18931
18931
  and s_bs == 400 and s_oa == 200,
18932
18932
  "claude_desktop": s_oc == 403 and s_ac == 200 and len(ac["done"]) == 1 and cfg_added["globalShortcut"] == "Ctrl+Space" and cfg_added["mcpServers"]["files"] == {"command": "npx", "args": ["-y", "x"]}
@@ -18954,6 +18954,212 @@ def section_eh_mcp(tmp: str) -> None:
18954
18954
  + (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
18955
18955
 
18956
18956
 
18957
+ def section_ei_public_pad_benchmark(tmp: str) -> None:
18958
+ """Section EI - a pad from public data, and the benchmark: the self-tests; the recorder exports read without an
18959
+ on-bottom flag, a depth reamed back through hole already drilled, a ten-second record's pipe speeds, a stand no bit
18960
+ could have drilled; the published layouts converted (stand-ins under the published names) and the site made, with
18961
+ each file's size and hash kept and the credit on every page; the benchmark over it - the counts, the ranks, each
18962
+ well against the pad's best; the routes, the tabs, the commands, the assistant's tool, the help, the README and
18963
+ the lessons."""
18964
+ import http.cookiejar
18965
+ import io as _io
18966
+ import subprocess as _sp
18967
+ import urllib.error
18968
+ import urllib.request
18969
+ from datetime import datetime as _dtm, timedelta as _td
18970
+ from . import __version__ as _ver
18971
+ from . import alerts as AL
18972
+ from . import benchmark as BM
18973
+ from . import dysfunction as DY
18974
+ from . import edr as E
18975
+ from . import helplib as H
18976
+ from . import mcp_server as MC
18977
+ from . import public_pad as PP
18978
+ from . import rig_state as RS
18979
+ from . import roadmap as RM
18980
+ from . import tutorial as TU
18981
+ from .service import Service, Users
18982
+ from .workspace import Workspace
18983
+ pkg = Path(__file__).parent
18984
+ d = Path(tmp, "ei"); d.mkdir()
18985
+ os.environ["GEA_WORKSPACES_FILE"] = str(d / "workspaces.json")
18986
+ # -- EI1 what the published records made the drilling record learn ------------------------------------------------------
18987
+ st_p, st_b = PP.selftest(), BM.selftest()
18988
+ hdr = "YYYY/MM/DD,HH:MM:SS,Hole Depth (feet),Bit Depth (feet),Rate Of Penetration (ft_per_hr),Weight on Bit (klbs),Rotary RPM (RPM),Hook Load (klbs),Standpipe Pressure (psi),Total Pump Output (gal_per_min),Block Height (feet)"
18989
+ t0 = _dtm(2026, 5, 1, 0, 0, 0)
18990
+
18991
+ def write(path, rows, step=1):
18992
+ with open(path, "w", encoding="utf-8", newline="") as f:
18993
+ f.write(hdr + "\n")
18994
+ for k, (hole, bit, rop, wob, rpm) in enumerate(rows):
18995
+ ts = t0 + _td(seconds=k * step)
18996
+ f.write(f"{ts:%Y/%m/%d},{ts:%H:%M:%S},{hole:.2f},{bit:.2f},{rop:.1f},{wob:.1f},{rpm:.1f},180.0,2500.0,550.0,50.0\n")
18997
+ # drilled 1,000 to 2,500 ft at 180 ft/h with 30 klbf; the depth set back to 1,100 and reamed back to 2,400 at 900 ft/h with 3 klbf; then drilled on to 2,700
18998
+ rows = [(1000.0 + 0.05 * k, 1000.0 + 0.05 * k, 180.0, 30.0, 80.0) for k in range(30000)]
18999
+ rows += [(1100.0 + 0.25 * k, 1100.0 + 0.25 * k, 900.0, 3.0, 60.0) for k in range(5200)]
19000
+ rows += [(2400.0 + 0.25 * k, 2400.0 + 0.25 * k, 900.0, 3.0, 60.0) for k in range(400)] # the old depth regained at 2,500
19001
+ rows += [(2500.0 + 0.05 * k, 2500.0 + 0.05 * k, 180.0, 30.0, 80.0) for k in range(4000)]
19002
+ write(str(d / "reamed.csv"), rows)
19003
+ s_r = E.read(str(d / "reamed.csv")); de = E.depth_events(s_r); rec_r = E.record(s_r, de)
19004
+ ev = [e for e in de["events"] if e["type"] == "REAMED BACK"]
19005
+ # the same fall, but the regain is drilled as the hole was (a redrill): not reamed back
19006
+ rows2 = rows[:30000] + [(1100.0 + 0.05 * k, 1100.0 + 0.05 * k, 180.0, 30.0, 80.0) for k in range(8000)]
19007
+ write(str(d / "redrilled.csv"), rows2)
19008
+ de2 = E.depth_events(E.read(str(d / "redrilled.csv")))
19009
+ on, how = E.on_bottom(s_r)
19010
+ # a ten-second record: the bit pulled 600 ft at 1 ft/s is tripping out, not standing still
19011
+ n10 = 400; t10 = np.arange(n10) * 10.0
19012
+ bit10 = np.where(t10 < 600.0, 9000.0 - t10, 8400.0)
19013
+ c10 = RS.classify(t10, {"hookload": np.full(n10, 200.0), "block": np.full(n10, 50.0), "bit": bit10, "hole": np.full(n10, 9700.0), "flow": np.zeros(n10), "spp": None, "rpm": np.zeros(n10)},
19014
+ np.zeros(n10, bool), block_weight=40.0)
19015
+ tq = np.arange(0.0, 3600.0)
19016
+ hole_q = 5000.0 + np.where(tq < 1800.0, tq * 0.05, 90.0 + (tq - 1800.0) * 2.0) # 90 ft drilled at 180 ft/h, then the depth run on at 7,200 ft/h
19017
+ stq = RM.stands_of(tq, hole_q, np.ones(len(tq), bool), np.ones(len(tq), bool), {})
19018
+ c1 = {
19019
+ "selftests": st_p["ok"] and st_b["ok"] and len(st_p["checks"]) >= 9 and len(st_b["checks"]) >= 3,
19020
+ "on_bottom": how is not None and "no On Bottom channel" in how and bool(on.all()) and any("no On Bottom channel" in n_ for n_ in rec_r["notes"]) and E.ON_BOTTOM_FT == 0.1,
19021
+ "reamed_back": len(ev) == 1 and "reamed back in" in ev[0]["effect"] and "3 klbf on the bit where it was drilled with 30" in ev[0]["effect"] and abs(rec_r["feet_drilled"] - 1700.0) < 5.0
19022
+ and not [e for e in de2["events"] if e["type"] == "REAMED BACK"] and [e["type"] for e in de2["events"] if e["from_ft"] > 2000] == ["UNRESOLVED"],
19023
+ "ten_second": float((c10["state"][:55] == RS.TOUT).mean()) > 0.9 and int((c10["state"][70:] == RS.TOUT).sum()) == 0,
19024
+ "implausible": stq["implausible"] >= 30 and stq["n"] == 1 and float(stq["rop"][0]) < 250.0 and float(stq["feet"].sum()) <= 100.0,
19025
+ }
19026
+ failed1 = [k_ for k_, v in c1.items() if not v]
19027
+ ok(not failed1,
19028
+ "EI1 what the published records taught the drilling record, each on a labelled file: an export with no on-bottom flag is read with the bit within 0.1 ft of the hole depth as on bottom, and "
19029
+ "says so; a depth set back 1,400 ft and regained through hole already drilled at five times the rate with a tenth of the weight is the string reamed back in, excluded, and the footage is the "
19030
+ "hole's own 1,700 ft - while the same fall drilled again as it was first drilled is left for the daily report to decide; a ten-second record's pipe pulled at a foot a second is a trip out; "
19031
+ "the stand drilled at 180 ft/h is kept and the thirty-odd behind it, counted at 7,200 ft/h, are left out and counted as such; the public-pad and benchmark self-tests" + (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
19032
+
19033
+ # -- EI2 the site made from the published layouts, and the benchmark over it -------------------------------------------
19034
+ folder, site = str(d / "files"), str(d / "forge-site")
19035
+ made = PP.standins(folder, stands=24)
19036
+ st0 = PP.status(folder, verify=True)
19037
+ seen = []
19038
+ r = PP.build(folder, site, "tester", progress=seen.append)
19039
+ ws = Workspace(site); rec = PP.record(ws); by = {e["well"]: e for e in rec["wells"]}
19040
+ bm = BM.page(ws); rm = RM.page(ws); dy = DY.page(ws)
19041
+ bw = {w_["display"]: w_ for w_ in bm["wells"]}
19042
+ wr = BM.write_report(ws, _ver, "tester")
19043
+ rows_b = (Path(wr["folder"]) / "benchmark.csv").read_text(encoding="utf-8").strip().splitlines()
19044
+ rows_s = (Path(wr["folder"]) / "stretches.csv").read_text(encoding="utf-8").strip().splitlines()
19045
+ raised = AL.check_conditions(ws, None, force=True)
19046
+ again = PP.build(folder, site, "tester")
19047
+ os.remove(os.path.join(folder, "16B(78)-32 Well Survey.zip"))
19048
+ r_ns = PP.build(folder, str(d / "forge-nosurvey"), "tester", wells=["56-32", "16B(78)-32"], verify=False)
19049
+ by_ns = {e["well"]: e for e in r_ns["record"]["wells"]}
19050
+ site_txt = MC.call_tool(ws, "site", {})["text"]; bm_txt = MC.call_tool(ws, "benchmark", {})
19051
+ audit = Path(ws.audit_path).read_text(encoding="utf-8")
19052
+ plain = Workspace.create(str(d / "plain"), "Plain", actor="tester")
19053
+ c2 = {
19054
+ "status": st0["present"] == 5 and st0["ready"] and all(r_["present"] and r_["size_matches"] is False and r_["hash_matches"] is False and len(r_["sha256"]) == 64 for r_ in st0["files"])
19055
+ and [r_["well"] for r_ in st0["files"]] == ["58-32", "16A(78)-32", "56-32", "78B-32", "16B(78)-32"] and st0["total_bytes"] > 2.7e9 and all(r_["page"].startswith("https://gdr.openei.org/submissions/") for r_ in st0["files"]),
19056
+ "built": r["added"] == [r_["well"] for r_ in st0["files"]] and ws.manifest.get("name") == "Utah FORGE - public data" and len(ws.wells()) == 5 and seen[-1] == {"step": "done", "added": r["added"]}
19057
+ and {s_["step"] for s_ in seen} >= {"hashing", "converting", "attaching", "done"} and again["added"] == [] and "public_pad.build" in audit and str(d / "workspaces.json") and Path(d / "workspaces.json").is_file(),
19058
+ "provenance": rec["licence"]["url"].endswith("/by/4.0/") and "U.S. Department of Energy" in rec["credit"] and all(e["sha256"] and e["hash_matches"] is False and e["bytes"] > 0 and e["well_id"] for e in rec["wells"])
19059
+ and by["16A(78)-32"]["bit_depth_reconstructed"] and by["16B(78)-32"]["tvd_from_survey"] and "attached as it is" in by["56-32"]["notes"][-1]
19060
+ and not by_ns["16B(78)-32"]["tvd_from_survey"] and any("measured depth stands in" in n_ for n_ in by_ns["16B(78)-32"]["notes"]),
19061
+ "pages_credit": all(p_["lines"][-1].startswith("Data: Utah FORGE, public, under Creative Commons Attribution 4.0") and p_["public_source"]["name"] == "Utah FORGE" for p_ in (bm, rm, dy))
19062
+ and any("reconstructed" in n_ for n_ in bm["notes"]) and "Data: Utah FORGE" in site_txt and PP.credit(plain) is None and "public_source" not in BM.page(plain),
19063
+ "not_live": all(not w_["live"] for w_ in dy["wells"]) and not [e for e in raised if e["event"].startswith("drilling.")],
19064
+ "benchmark": bm["status"] == "OK" and len(bm["wells"]) == 5 and all(abs(w_["drilled_ft"] - round(made[w_["display"]]["hole_to"] - made[w_["display"]]["hole_from"], -2)) <= 200 and 140 <= w_["rop_ft_h"] <= 160
19065
+ and w_["connections"] >= 20 and 5.0 <= w_["w2w_median_min"] <= 6.5 and w_["gap_h"] >= 0 and w_["compared_h"] > 0 for w_ in bm["wells"])
19066
+ and set(bm["ranks"]["rop_ft_h"].values()) <= {1, 2, 3, 4, 5} and 1 in bm["ranks"]["feet_per_day"].values() and len(bm["curves"]) == 5 and all(len(c_) >= 10 and c_[0][1] < c_[-1][1] for c_ in bm["curves"].values())
19067
+ and bm["pad_best_connection_min"] is not None and len(bm["stretches"]) >= 3 and all(s_["best_well"] in bm["names"] for s_ in bm["stretches"] if s_["best_rop_ft_h"]),
19068
+ "report": set(wr["files"]) == {"benchmark.json", "benchmark.md", "benchmark.csv", "stretches.csv"} and len(rows_b) == 6 and rows_b[0].startswith("display,drilled_ft,days,feet_per_day") and len(rows_s) == len(bm["stretches"]) + 1
19069
+ and "benchmark.report" in audit,
19070
+ "tool": not bm_txt["is_error"] and bm_txt["text"] == BM.text(BM.page(ws)) and "benchmark" in MC.NAMES and len(MC.NAMES) == 24,
19071
+ }
19072
+ failed2 = [k_ for k_, v in c2.items() if not v]
19073
+ ok(not failed2,
19074
+ "EI2 the public pad from stand-ins written in each of the five published layouts under the published names: the folder read against the list (every file there, none the published size or "
19075
+ "hash, and said so); the site made and registered, five wells, each source's hash on the record, the licence and the credit; 16A's bit depth marked reconstructed, 16B's true vertical depth "
19076
+ "from its survey and, without the survey, its measured depth standing in and said to; the credit as the last line of the roadmap, the drilling alerts and the benchmark, and on the "
19077
+ "assistant's site tool; records dated months ago raise no drilling alert though their files are new; built again it adds nothing. The benchmark over it: every well's footage, rate and "
19078
+ "connections, the ranks, the curves, the pad's best and each well's gap; its report with a row a well and a row a stretch; the assistant's benchmark tool the page's own text"
19079
+ + (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
19080
+
19081
+ # -- EI3 the routes, the commands, the tabs, the help -------------------------------------------------------------------
19082
+ Users(str(Path(site, "users.json"))).add("v", "viewer-pass-1", "viewer"); Users(str(Path(site, "users.json"))).add("op", "op-pass-123", "operator"); Users(str(Path(site, "users.json"))).add("ad", "admin-pass-12", "admin")
19083
+ svc = Service(site, port=0, scheduler=False).start()
19084
+ base_url = svc.url.rstrip("/")
19085
+
19086
+ def opener(name, pw_):
19087
+ o = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
19088
+ rq = urllib.request.Request(base_url + "/api/login", method="POST", data=json.dumps({"name": name, "password": pw_}).encode())
19089
+ rq.add_header("Content-Type", "application/json"); rq.add_header("X-GEA-Action", "1"); o.open(rq, timeout=30)
19090
+ return o
19091
+
19092
+ def call(o, method, path, body=None):
19093
+ rq = urllib.request.Request(base_url + path, method=method, data=(json.dumps(body).encode() if body is not None else None))
19094
+ if method == "POST":
19095
+ rq.add_header("Content-Type", "application/json"); rq.add_header("X-GEA-Action", "1")
19096
+ try:
19097
+ with o.open(rq, timeout=300) as rr_:
19098
+ return rr_.status, json.loads(rr_.read())
19099
+ except urllib.error.HTTPError as e:
19100
+ return e.code, json.loads(e.read())
19101
+ from urllib.parse import quote as _q
19102
+ try:
19103
+ V, O, A = opener("v", "viewer-pass-1"), opener("op", "op-pass-123"), opener("ad", "admin-pass-12")
19104
+ s_vb, vb = call(V, "GET", "/api/benchmark")
19105
+ s_vw, _ = call(V, "POST", "/api/benchmark/write", {})
19106
+ s_ow, ow = call(O, "POST", "/api/benchmark/write", {})
19107
+ s_vp, vp = call(V, "GET", "/api/public-pad")
19108
+ s_vf, _ = call(V, "GET", "/api/public-pad?folder=" + _q(folder))
19109
+ s_af, af = call(A, "GET", "/api/public-pad?folder=" + _q(folder))
19110
+ s_ob, _ = call(O, "POST", "/api/public-pad/build", {"folder": folder, "path": str(d / "forge-api")})
19111
+ s_ab, ab = call(A, "POST", "/api/public-pad/build", {"folder": folder, "path": str(d / "forge-api")})
19112
+ job = {}
19113
+ for _ in range(240):
19114
+ _, pj = call(A, "GET", "/api/public-pad")
19115
+ job = pj["job"]
19116
+ if job.get("state") != "running":
19117
+ break
19118
+ time.sleep(0.5)
19119
+ s_bad, _ = call(A, "POST", "/api/public-pad/build", {"folder": str(d / "nowhere"), "path": str(d / "forge-bad")})
19120
+ job_bad = {}
19121
+ for _ in range(60):
19122
+ _, pj = call(A, "GET", "/api/public-pad")
19123
+ job_bad = pj["job"]
19124
+ if job_bad.get("state") != "running":
19125
+ break
19126
+ time.sleep(0.25)
19127
+ finally:
19128
+ svc.stop()
19129
+ env = {**os.environ, "PYTHONPATH": str(pkg.parent) + os.pathsep + os.environ.get("PYTHONPATH", "")}
19130
+ run = lambda *a_: _sp.run([sys.executable, "-m", "gea", *a_], capture_output=True, text=True, env=env, cwd=str(d), timeout=600)
19131
+ cli_l, cli_f, cli_v = run("public-pad", "--list"), run("public-pad", "--folder", folder), run("public-pad", "--folder", folder, "--verify", "--json")
19132
+ cli_b, cli_n = run("public-pad", "--folder", folder, "--build", "--site", str(d / "forge-cli")), run("public-pad", "--folder", folder, "--build")
19133
+ cli_bm, cli_bj, cli_bw = run("benchmark", "--workspace", site), run("benchmark", "--workspace", site, "--json"), run("benchmark", "--workspace", site, "--write")
19134
+ page_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
19135
+ readme = (pkg.parent / "README.md").read_text(encoding="utf-8") if (pkg.parent / "README.md").is_file() else ""
19136
+ lesson = (pkg / "help" / "tutorial" / "13-drilling-pages.md").read_text(encoding="utf-8")
19137
+ c3 = {
19138
+ "api_benchmark": s_vb == 200 and vb["status"] == "OK" and len(vb["wells"]) == 5 and s_vw == 403 and s_ow == 200 and "stretches.csv" in ow["files"],
19139
+ "api_public": s_vp == 200 and vp["folder"] == "" and len(vp["files"]) == 5 and vp["this_site"]["name"] == "Utah FORGE" and s_vf == 403 and s_af == 200 and af["present"] == 5 and s_ob == 403 and s_ab == 200
19140
+ and ab["state"] == "running" and job.get("state") == "done" and job["result"]["wells"] == ["58-32", "16A(78)-32", "56-32", "78B-32", "16B(78)-32"] and len(Workspace(str(d / "forge-api")).wells()) == 5
19141
+ and Path(d / "forge-api", "users.json").is_file() and job_bad.get("state") == "failed" and "no such folder" in job_bad.get("error", ""),
19142
+ "cli": cli_l.returncode == 0 and "Well_58-32_raw_pason_log.csv" in cli_l.stdout and "doi:10.15121/1998591" in cli_l.stdout and cli_f.returncode == 0 and "5 of 5 recorder files" in cli_f.stdout
19143
+ and cli_v.returncode == 0 and json.loads(cli_v.stdout)["files"][0]["hash_matches"] is False and cli_b.returncode == 0 and "added 58-32, 16A(78)-32, 56-32, 78B-32, 16B(78)-32" in cli_b.stdout
19144
+ and "RECONSTRUCTED" in cli_b.stdout and cli_n.returncode != 0 and "--site" in cli_n.stderr and cli_bm.returncode == 0 and "Benchmark: the wells against one another" in cli_bm.stdout
19145
+ and "Data: Utah FORGE" in cli_bm.stdout and cli_bj.returncode == 0 and len(json.loads(cli_bj.stdout)["wells"]) == 5 and cli_bw.returncode == 0 and "stretches.csv" in cli_bw.stdout,
19146
+ "page": all(x in page_src for x in ("VIEWS.benchmark", "['#/benchmark', 'Benchmark']", "bmCurves", "/api/benchmark/write", "help('benchmark')", "VIEWS.publicpad", "['#/publicpad', 'Public data']",
19147
+ "/api/public-pad/build", "help('publicpad')", "does not contain them and does not fetch them")),
19148
+ "help": not H.check("benchmark") and not H.check("public-data") and not H.check("edr") and H.VIEW_TOPIC.get("benchmark") == "benchmark" and H.VIEW_TOPIC.get("publicpad") == "public-data"
19149
+ and all(x in (H.page("public-data") or "") for x in ("gea public-pad --folder C:\\forge --build --site C:\\forge-site", "RECONSTRUCTED", "CC BY 4.0", "does not fetch them", "REAMED BACK"))
19150
+ and all(x in (H.page("benchmark") or "") for x in ("gea benchmark --workspace C:\\site", "300 ft or more", "25th percentile")) and "REAMED BACK" in (H.page("edr") or "") and "within 0.1 ft" in (H.page("edr") or "")
19151
+ and "`benchmark`" in (H.page("mcp") or ""),
19152
+ "readme_lesson": (not readme or ("### Benchmark" in readme and "### Public data: a real pad" in readme and "`gea public-pad`" in readme and "`gea benchmark`" in readme))
19153
+ and "**Benchmark**" in lesson and "**Public data**" in lesson and "benchmark" in lesson.split("Help:")[-1] and "public-data" in lesson.split("Help:")[-1] and not TU.check("drilling-pages"),
19154
+ }
19155
+ failed3 = [k_ for k_, v in c3.items() if not v]
19156
+ ok(not failed3,
19157
+ "EI3 on the API (anyone reads the benchmark and the list of public files; only an operator writes the benchmark's report; only an administrator has a folder of the computer looked into or a "
19158
+ "site made - made in the background with its progress asked after, the accounts copied, and a folder that is not there a failure that says so), the commands (the list with where each file "
19159
+ "is published, the folder, the hashes as JSON, the site built with what was done to each well, a build with no site named stopped; the benchmark, as JSON, its report), the Benchmark and "
19160
+ "Public data tabs, the help pages, the README and lesson 13" + (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
19161
+
19162
+
18957
19163
  def main() -> int:
18958
19164
  print("GEA-Program - ACCEPTANCE SUITE (the product gate)")
18959
19165
  # a handle a job subprocess still holds at the end must not turn a finished gate into a traceback on Windows:
@@ -19095,6 +19301,7 @@ def main() -> int:
19095
19301
  section_ef_roadmap(tmp)
19096
19302
  section_eg_dysfunction(tmp)
19097
19303
  section_eh_mcp(tmp)
19304
+ section_ei_public_pad_benchmark(tmp)
19098
19305
  if _FAILS:
19099
19306
  print(f"[ACCEPTANCE] {len(_FAILS)} FAILURES ({_PASS} passed):")
19100
19307
  for f in _FAILS: