gea-program 0.86.0__tar.gz → 0.87.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 (436) hide show
  1. {gea_program-0.86.0/gea_program.egg-info → gea_program-0.87.0}/PKG-INFO +26 -4
  2. {gea_program-0.86.0 → gea_program-0.87.0}/README.md +25 -3
  3. {gea_program-0.86.0 → gea_program-0.87.0}/gea/__init__.py +1 -1
  4. {gea_program-0.86.0 → gea_program-0.87.0}/gea/__main__.py +57 -1
  5. {gea_program-0.86.0 → gea_program-0.87.0}/gea/acceptance_tests.py +262 -0
  6. gea_program-0.87.0/gea/calibration.py +976 -0
  7. {gea_program-0.86.0 → gea_program-0.87.0}/gea/dossier.py +6 -1
  8. {gea_program-0.86.0 → gea_program-0.87.0}/gea/fluid.py +21 -11
  9. gea_program-0.87.0/gea/help/calibration.md +13 -0
  10. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/driller.md +1 -1
  11. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/fluid.md +1 -1
  12. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/install.md +2 -2
  13. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/reader.md +1 -1
  14. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/recorder.md +1 -1
  15. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/01-install.md +2 -2
  16. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/14-production-pages.md +6 -5
  17. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/19-dossier-reader.md +1 -1
  18. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/22-updates.md +1 -1
  19. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/23-vpn.md +1 -1
  20. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/25-install-recorder.md +2 -2
  21. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/29-driller-rig.md +1 -1
  22. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial.md +2 -2
  23. {gea_program-0.86.0 → gea_program-0.87.0}/gea/helplib.py +2 -1
  24. {gea_program-0.86.0 → gea_program-0.87.0}/gea/service.py +20 -0
  25. {gea_program-0.86.0 → gea_program-0.87.0}/gea/web/app.html +81 -2
  26. {gea_program-0.86.0 → gea_program-0.87.0/gea_program.egg-info}/PKG-INFO +26 -4
  27. {gea_program-0.86.0 → gea_program-0.87.0}/gea_program.egg-info/SOURCES.txt +2 -0
  28. {gea_program-0.86.0 → gea_program-0.87.0}/pyproject.toml +1 -1
  29. {gea_program-0.86.0 → gea_program-0.87.0}/LICENSE +0 -0
  30. {gea_program-0.86.0 → gea_program-0.87.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
  31. {gea_program-0.86.0 → gea_program-0.87.0}/gea/accuracy_statement.py +0 -0
  32. {gea_program-0.86.0 → gea_program-0.87.0}/gea/alarm_engine.py +0 -0
  33. {gea_program-0.86.0 → gea_program-0.87.0}/gea/alerts.py +0 -0
  34. {gea_program-0.86.0 → gea_program-0.87.0}/gea/backup.py +0 -0
  35. {gea_program-0.86.0 → gea_program-0.87.0}/gea/bench.py +0 -0
  36. {gea_program-0.86.0 → gea_program-0.87.0}/gea/bit_seismic.py +0 -0
  37. {gea_program-0.86.0 → gea_program-0.87.0}/gea/blind_harness.py +0 -0
  38. {gea_program-0.86.0 → gea_program-0.87.0}/gea/casing_design.py +0 -0
  39. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
  40. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
  41. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
  42. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
  43. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
  44. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
  45. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
  46. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
  47. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
  48. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
  49. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
  50. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
  51. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
  52. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
  53. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
  54. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
  55. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
  56. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
  57. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
  58. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
  59. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
  60. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
  61. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
  62. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
  63. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
  64. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
  65. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
  66. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
  67. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
  68. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
  69. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
  70. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
  71. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
  72. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
  73. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
  74. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
  75. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
  76. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
  77. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
  78. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
  79. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
  80. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
  81. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
  82. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
  83. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
  84. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
  85. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
  86. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
  87. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
  88. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
  89. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
  90. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
  91. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
  92. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
  93. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
  94. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
  95. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
  96. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
  97. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
  98. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
  99. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
  100. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
  101. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
  102. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
  103. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
  104. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
  105. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
  106. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/med_160_sapropels.txt +0 -0
  107. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
  108. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
  109. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
  110. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
  111. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
  112. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
  113. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
  114. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
  115. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
  116. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
  117. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
  118. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
  119. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
  120. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
  121. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
  122. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
  123. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
  124. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
  125. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
  126. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
  127. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
  128. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
  129. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
  130. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
  131. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
  132. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
  133. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
  134. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
  135. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
  136. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
  137. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
  138. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
  139. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
  140. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
  141. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
  142. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
  143. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog_map.py +0 -0
  144. {gea_program-0.86.0 → gea_program-0.87.0}/gea/catalog_register.py +0 -0
  145. {gea_program-0.86.0 → gea_program-0.87.0}/gea/certificates.py +0 -0
  146. {gea_program-0.86.0 → gea_program-0.87.0}/gea/cli.py +0 -0
  147. {gea_program-0.86.0 → gea_program-0.87.0}/gea/client_reports.py +0 -0
  148. {gea_program-0.86.0 → gea_program-0.87.0}/gea/collision.py +0 -0
  149. {gea_program-0.86.0 → gea_program-0.87.0}/gea/config_versioning.py +0 -0
  150. {gea_program-0.86.0 → gea_program-0.87.0}/gea/conformance.py +0 -0
  151. {gea_program-0.86.0 → gea_program-0.87.0}/gea/control_room.py +0 -0
  152. {gea_program-0.86.0 → gea_program-0.87.0}/gea/correlation.py +0 -0
  153. {gea_program-0.86.0 → gea_program-0.87.0}/gea/dashboard.py +0 -0
  154. {gea_program-0.86.0 → gea_program-0.87.0}/gea/declarations.py +0 -0
  155. {gea_program-0.86.0 → gea_program-0.87.0}/gea/decline.py +0 -0
  156. {gea_program-0.86.0 → gea_program-0.87.0}/gea/deviation.py +0 -0
  157. {gea_program-0.86.0 → gea_program-0.87.0}/gea/dlis.py +0 -0
  158. {gea_program-0.86.0 → gea_program-0.87.0}/gea/dnp3.py +0 -0
  159. {gea_program-0.86.0 → gea_program-0.87.0}/gea/doctor.py +0 -0
  160. {gea_program-0.86.0 → gea_program-0.87.0}/gea/dossier_verify.py +0 -0
  161. {gea_program-0.86.0 → gea_program-0.87.0}/gea/downhole_engine.py +0 -0
  162. {gea_program-0.86.0 → gea_program-0.87.0}/gea/drift_monitor.py +0 -0
  163. {gea_program-0.86.0 → gea_program-0.87.0}/gea/drill_string.py +0 -0
  164. {gea_program-0.86.0 → gea_program-0.87.0}/gea/driller_link.py +0 -0
  165. {gea_program-0.86.0 → gea_program-0.87.0}/gea/earth_model.py +0 -0
  166. {gea_program-0.86.0 → gea_program-0.87.0}/gea/economics.py +0 -0
  167. {gea_program-0.86.0 → gea_program-0.87.0}/gea/ed25519.py +0 -0
  168. {gea_program-0.86.0 → gea_program-0.87.0}/gea/edr.py +0 -0
  169. {gea_program-0.86.0 → gea_program-0.87.0}/gea/elevation.py +0 -0
  170. {gea_program-0.86.0 → gea_program-0.87.0}/gea/etp.py +0 -0
  171. {gea_program-0.86.0 → gea_program-0.87.0}/gea/etp12_schemas.json +0 -0
  172. {gea_program-0.86.0 → gea_program-0.87.0}/gea/example_register_map.json +0 -0
  173. {gea_program-0.86.0 → gea_program-0.87.0}/gea/fat_sat.py +0 -0
  174. {gea_program-0.86.0 → gea_program-0.87.0}/gea/field_pull.py +0 -0
  175. {gea_program-0.86.0 → gea_program-0.87.0}/gea/files.py +0 -0
  176. {gea_program-0.86.0 → gea_program-0.87.0}/gea/fixtures/README.md +0 -0
  177. {gea_program-0.86.0 → gea_program-0.87.0}/gea/fixtures/comcat_delaware_basin_2026-09.txt +0 -0
  178. {gea_program-0.86.0 → gea_program-0.87.0}/gea/fixtures/comcat_mahoning_1990-2026.txt +0 -0
  179. {gea_program-0.86.0 → gea_program-0.87.0}/gea/fixtures/comcat_youngstown_2011-2012.txt +0 -0
  180. {gea_program-0.86.0 → gea_program-0.87.0}/gea/fixtures/ne_110m_coastline.json +0 -0
  181. {gea_program-0.86.0 → gea_program-0.87.0}/gea/follower.py +0 -0
  182. {gea_program-0.86.0 → gea_program-0.87.0}/gea/forward_model.py +0 -0
  183. {gea_program-0.86.0 → gea_program-0.87.0}/gea/frac_hits.py +0 -0
  184. {gea_program-0.86.0 → gea_program-0.87.0}/gea/friction_priors.py +0 -0
  185. {gea_program-0.86.0 → gea_program-0.87.0}/gea/front.py +0 -0
  186. {gea_program-0.86.0 → gea_program-0.87.0}/gea/gamma.py +0 -0
  187. {gea_program-0.86.0 → gea_program-0.87.0}/gea/gauge_aging.py +0 -0
  188. {gea_program-0.86.0 → gea_program-0.87.0}/gea/gauge_specs.py +0 -0
  189. {gea_program-0.86.0 → gea_program-0.87.0}/gea/geodesy.py +0 -0
  190. {gea_program-0.86.0 → gea_program-0.87.0}/gea/geomag.py +0 -0
  191. {gea_program-0.86.0 → gea_program-0.87.0}/gea/gravity_reference.py +0 -0
  192. {gea_program-0.86.0 → gea_program-0.87.0}/gea/hartip.py +0 -0
  193. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/IT_SECURITY.md +0 -0
  194. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/TESTER_GUIDE.md +0 -0
  195. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/alarms.md +0 -0
  196. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/alerts.md +0 -0
  197. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/audit-update.md +0 -0
  198. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/backup.md +0 -0
  199. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/bit-image.md +0 -0
  200. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/casing.md +0 -0
  201. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/catalog.md +0 -0
  202. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/charts.md +0 -0
  203. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/collision.md +0 -0
  204. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/company-sign-in.md +0 -0
  205. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/conformance.md +0 -0
  206. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/control-room.md +0 -0
  207. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/data-in.md +0 -0
  208. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/declare.md +0 -0
  209. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/decline.md +0 -0
  210. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/dlis.md +0 -0
  211. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/doctor.md +0 -0
  212. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/dossier.md +0 -0
  213. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/drift.md +0 -0
  214. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/drillstring.md +0 -0
  215. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/economics.md +0 -0
  216. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/edr.md +0 -0
  217. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/etp.md +0 -0
  218. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/field-ports.md +0 -0
  219. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/files.md +0 -0
  220. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/frac-hits.md +0 -0
  221. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/front.md +0 -0
  222. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/historian.md +0 -0
  223. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/https.md +0 -0
  224. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/hydraulics.md +0 -0
  225. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/instruments.md +0 -0
  226. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/interval.md +0 -0
  227. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/invoice-check.md +0 -0
  228. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/map.md +0 -0
  229. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/month-end.md +0 -0
  230. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/notifications.md +0 -0
  231. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/opseis.md +0 -0
  232. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/osdu.md +0 -0
  233. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/pad-summary.md +0 -0
  234. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/patches.md +0 -0
  235. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/penetrator.md +0 -0
  236. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/plan.md +0 -0
  237. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/plume.md +0 -0
  238. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/pore-pressure.md +0 -0
  239. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/ppdm.md +0 -0
  240. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/quakeml.md +0 -0
  241. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/quality.md +0 -0
  242. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/records.md +0 -0
  243. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/report-history.md +0 -0
  244. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/rig-time.md +0 -0
  245. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/rocks.md +0 -0
  246. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/seedlink.md +0 -0
  247. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/seismic.md +0 -0
  248. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/setup.md +0 -0
  249. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/simulation.md +0 -0
  250. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/site.md +0 -0
  251. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/sites.md +0 -0
  252. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/slip.md +0 -0
  253. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/soak.md +0 -0
  254. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/sra.md +0 -0
  255. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/start.md +0 -0
  256. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/structure.md +0 -0
  257. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tools.md +0 -0
  258. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/torque-drag.md +0 -0
  259. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/transients.md +0 -0
  260. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/02-sign-in.md +0 -0
  261. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/03-site.md +0 -0
  262. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/04-add-well.md +0 -0
  263. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/05-records.md +0 -0
  264. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/06-well-page.md +0 -0
  265. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/07-declare.md +0 -0
  266. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/08-patches.md +0 -0
  267. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/09-alarms.md +0 -0
  268. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/10-control-room.md +0 -0
  269. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/11-summary-month.md +0 -0
  270. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/12-where-the-well-is.md +0 -0
  271. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/13-drilling-pages.md +0 -0
  272. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/15-seismic.md +0 -0
  273. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/16-seismicity.md +0 -0
  274. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/17-recorder-office.md +0 -0
  275. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/18-reports.md +0 -0
  276. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/20-admin.md +0 -0
  277. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/21-upkeep.md +0 -0
  278. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/24-the-box.md +0 -0
  279. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/26-monitor.md +0 -0
  280. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/27-mirror-vpn.md +0 -0
  281. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/tutorial/28-driller-office.md +0 -0
  282. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/upkeep.md +0 -0
  283. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/vibration.md +0 -0
  284. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/vpn.md +0 -0
  285. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/well-report.md +0 -0
  286. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/well-tests.md +0 -0
  287. {gea_program-0.86.0 → gea_program-0.87.0}/gea/help/well3d.md +0 -0
  288. {gea_program-0.86.0 → gea_program-0.87.0}/gea/housekeeping.py +0 -0
  289. {gea_program-0.86.0 → gea_program-0.87.0}/gea/hydraulics.py +0 -0
  290. {gea_program-0.86.0 → gea_program-0.87.0}/gea/icon.py +0 -0
  291. {gea_program-0.86.0 → gea_program-0.87.0}/gea/interval.py +0 -0
  292. {gea_program-0.86.0 → gea_program-0.87.0}/gea/inverse_engine.py +0 -0
  293. {gea_program-0.86.0 → gea_program-0.87.0}/gea/invoice_check.py +0 -0
  294. {gea_program-0.86.0 → gea_program-0.87.0}/gea/jobs.py +0 -0
  295. {gea_program-0.86.0 → gea_program-0.87.0}/gea/launcher.py +0 -0
  296. {gea_program-0.86.0 → gea_program-0.87.0}/gea/live_ports.py +0 -0
  297. {gea_program-0.86.0 → gea_program-0.87.0}/gea/loadtest.py +0 -0
  298. {gea_program-0.86.0 → gea_program-0.87.0}/gea/matplotlib_demo.py +0 -0
  299. {gea_program-0.86.0 → gea_program-0.87.0}/gea/modbus.py +0 -0
  300. {gea_program-0.86.0 → gea_program-0.87.0}/gea/modbus_rtu.py +0 -0
  301. {gea_program-0.86.0 → gea_program-0.87.0}/gea/model_card.py +0 -0
  302. {gea_program-0.86.0 → gea_program-0.87.0}/gea/month_end.py +0 -0
  303. {gea_program-0.86.0 → gea_program-0.87.0}/gea/mqtt_port.py +0 -0
  304. {gea_program-0.86.0 → gea_program-0.87.0}/gea/notify.py +0 -0
  305. {gea_program-0.86.0 → gea_program-0.87.0}/gea/oidc.py +0 -0
  306. {gea_program-0.86.0 → gea_program-0.87.0}/gea/oidc_mock.py +0 -0
  307. {gea_program-0.86.0 → gea_program-0.87.0}/gea/op_seismicity.py +0 -0
  308. {gea_program-0.86.0 → gea_program-0.87.0}/gea/opcua_port.py +0 -0
  309. {gea_program-0.86.0 → gea_program-0.87.0}/gea/operator_app.py +0 -0
  310. {gea_program-0.86.0 → gea_program-0.87.0}/gea/osdu.py +0 -0
  311. {gea_program-0.86.0 → gea_program-0.87.0}/gea/pad_summary.py +0 -0
  312. {gea_program-0.86.0 → gea_program-0.87.0}/gea/patches.py +0 -0
  313. {gea_program-0.86.0 → gea_program-0.87.0}/gea/pdf_report.py +0 -0
  314. {gea_program-0.86.0 → gea_program-0.87.0}/gea/penetrator.py +0 -0
  315. {gea_program-0.86.0 → gea_program-0.87.0}/gea/permits.py +0 -0
  316. {gea_program-0.86.0 → gea_program-0.87.0}/gea/piwebapi.py +0 -0
  317. {gea_program-0.86.0 → gea_program-0.87.0}/gea/plume.py +0 -0
  318. {gea_program-0.86.0 → gea_program-0.87.0}/gea/pore_pressure.py +0 -0
  319. {gea_program-0.86.0 → gea_program-0.87.0}/gea/ports.py +0 -0
  320. {gea_program-0.86.0 → gea_program-0.87.0}/gea/ppdm.py +0 -0
  321. {gea_program-0.86.0 → gea_program-0.87.0}/gea/profile_catalog.py +0 -0
  322. {gea_program-0.86.0 → gea_program-0.87.0}/gea/project.py +0 -0
  323. {gea_program-0.86.0 → gea_program-0.87.0}/gea/qt6_downhole_app.py +0 -0
  324. {gea_program-0.86.0 → gea_program-0.87.0}/gea/quakeml.py +0 -0
  325. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reader.py +0 -0
  326. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reader_app.py +0 -0
  327. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reconciler.py +0 -0
  328. {gea_program-0.86.0 → gea_program-0.87.0}/gea/recorder_link.py +0 -0
  329. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
  330. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
  331. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/WMM2025.COF +0 -0
  332. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/eia_henry_hub_daily.csv.gz +0 -0
  333. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/eia_prices.provenance.json +0 -0
  334. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/eia_wti_daily.csv.gz +0 -0
  335. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/iscwsa_rev4_example.json +0 -0
  336. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/iscwsa_rev5_example.json +0 -0
  337. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/l0701_sonic_gr.las.gz +0 -0
  338. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/l0701_sonic_gr.provenance.json +0 -0
  339. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/libmseed_steim.provenance.json +0 -0
  340. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
  341. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
  342. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
  343. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/mahoning_example.json +0 -0
  344. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/mud_motor_specs.json +0 -0
  345. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/owsg_tool_models.json +0 -0
  346. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/penetrator_ratings.json +0 -0
  347. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/seismicity_protocols.json +0 -0
  348. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/tool_sources.json +0 -0
  349. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/us_outline.json +0 -0
  350. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/us_outline.provenance.json +0 -0
  351. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/volve_3d.provenance.json +0 -0
  352. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/volve_f4_interpretation.las.gz +0 -0
  353. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/volve_f4_logs.provenance.json +0 -0
  354. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/volve_f4_lwd.las.gz +0 -0
  355. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/volve_surfaces.json.gz +0 -0
  356. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/volve_traj_F-10.xml.gz +0 -0
  357. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/volve_traj_F-4.xml.gz +0 -0
  358. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/volve_traj_F-5_12.25in.xml.gz +0 -0
  359. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/volve_traj_F-5_17.5in.xml.gz +0 -0
  360. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/volve_traj_F-5_36in.xml.gz +0 -0
  361. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/volve_traj_F-5_8.5in.xml.gz +0 -0
  362. {gea_program-0.86.0 → gea_program-0.87.0}/gea/reference/volve_well_picks.csv.gz +0 -0
  363. {gea_program-0.86.0 → gea_program-0.87.0}/gea/report_history.py +0 -0
  364. {gea_program-0.86.0 → gea_program-0.87.0}/gea/rig_state.py +0 -0
  365. {gea_program-0.86.0 → gea_program-0.87.0}/gea/rock_inventory.py +0 -0
  366. {gea_program-0.86.0 → gea_program-0.87.0}/gea/sample_record.py +0 -0
  367. {gea_program-0.86.0 → gea_program-0.87.0}/gea/sample_well_profile.csv +0 -0
  368. {gea_program-0.86.0 → gea_program-0.87.0}/gea/sbom.py +0 -0
  369. {gea_program-0.86.0 → gea_program-0.87.0}/gea/seedlink.py +0 -0
  370. {gea_program-0.86.0 → gea_program-0.87.0}/gea/segy.py +0 -0
  371. {gea_program-0.86.0 → gea_program-0.87.0}/gea/seismic.py +0 -0
  372. {gea_program-0.86.0 → gea_program-0.87.0}/gea/seismic_array.py +0 -0
  373. {gea_program-0.86.0 → gea_program-0.87.0}/gea/seismic_assoc.py +0 -0
  374. {gea_program-0.86.0 → gea_program-0.87.0}/gea/seismic_detect.py +0 -0
  375. {gea_program-0.86.0 → gea_program-0.87.0}/gea/seismic_film.py +0 -0
  376. {gea_program-0.86.0 → gea_program-0.87.0}/gea/seismic_harmonic.py +0 -0
  377. {gea_program-0.86.0 → gea_program-0.87.0}/gea/seismic_qc.py +0 -0
  378. {gea_program-0.86.0 → gea_program-0.87.0}/gea/seismic_response.py +0 -0
  379. {gea_program-0.86.0 → gea_program-0.87.0}/gea/seismic_signature.py +0 -0
  380. {gea_program-0.86.0 → gea_program-0.87.0}/gea/seismic_track.py +0 -0
  381. {gea_program-0.86.0 → gea_program-0.87.0}/gea/seismic_uncertainty.py +0 -0
  382. {gea_program-0.86.0 → gea_program-0.87.0}/gea/seismic_unlisted.py +0 -0
  383. {gea_program-0.86.0 → gea_program-0.87.0}/gea/seismic_watch.py +0 -0
  384. {gea_program-0.86.0 → gea_program-0.87.0}/gea/sensor_swap.py +0 -0
  385. {gea_program-0.86.0 → gea_program-0.87.0}/gea/series_cache.py +0 -0
  386. {gea_program-0.86.0 → gea_program-0.87.0}/gea/service_life.py +0 -0
  387. {gea_program-0.86.0 → gea_program-0.87.0}/gea/setup_checklist.py +0 -0
  388. {gea_program-0.86.0 → gea_program-0.87.0}/gea/shapefile.py +0 -0
  389. {gea_program-0.86.0 → gea_program-0.87.0}/gea/shell.py +0 -0
  390. {gea_program-0.86.0 → gea_program-0.87.0}/gea/shut_in.py +0 -0
  391. {gea_program-0.86.0 → gea_program-0.87.0}/gea/simulation.py +0 -0
  392. {gea_program-0.86.0 → gea_program-0.87.0}/gea/site_map.py +0 -0
  393. {gea_program-0.86.0 → gea_program-0.87.0}/gea/sla_report.py +0 -0
  394. {gea_program-0.86.0 → gea_program-0.87.0}/gea/slip.py +0 -0
  395. {gea_program-0.86.0 → gea_program-0.87.0}/gea/soak.py +0 -0
  396. {gea_program-0.86.0 → gea_program-0.87.0}/gea/sra.py +0 -0
  397. {gea_program-0.86.0 → gea_program-0.87.0}/gea/store_forward.py +0 -0
  398. {gea_program-0.86.0 → gea_program-0.87.0}/gea/strata_join.py +0 -0
  399. {gea_program-0.86.0 → gea_program-0.87.0}/gea/structure.py +0 -0
  400. {gea_program-0.86.0 → gea_program-0.87.0}/gea/supervisor.py +0 -0
  401. {gea_program-0.86.0 → gea_program-0.87.0}/gea/survey_cmd.py +0 -0
  402. {gea_program-0.86.0 → gea_program-0.87.0}/gea/survey_view.py +0 -0
  403. {gea_program-0.86.0 → gea_program-0.87.0}/gea/telemetry.py +0 -0
  404. {gea_program-0.86.0 → gea_program-0.87.0}/gea/timestamp.py +0 -0
  405. {gea_program-0.86.0 → gea_program-0.87.0}/gea/tls.py +0 -0
  406. {gea_program-0.86.0 → gea_program-0.87.0}/gea/tool_catalog.py +0 -0
  407. {gea_program-0.86.0 → gea_program-0.87.0}/gea/tool_library.py +0 -0
  408. {gea_program-0.86.0 → gea_program-0.87.0}/gea/tool_taxonomy.py +0 -0
  409. {gea_program-0.86.0 → gea_program-0.87.0}/gea/torque_drag.py +0 -0
  410. {gea_program-0.86.0 → gea_program-0.87.0}/gea/transient.py +0 -0
  411. {gea_program-0.86.0 → gea_program-0.87.0}/gea/tray.py +0 -0
  412. {gea_program-0.86.0 → gea_program-0.87.0}/gea/tutorial.py +0 -0
  413. {gea_program-0.86.0 → gea_program-0.87.0}/gea/updates.py +0 -0
  414. {gea_program-0.86.0 → gea_program-0.87.0}/gea/vibration.py +0 -0
  415. {gea_program-0.86.0 → gea_program-0.87.0}/gea/vpn.py +0 -0
  416. {gea_program-0.86.0 → gea_program-0.87.0}/gea/web/reader.html +0 -0
  417. {gea_program-0.86.0 → gea_program-0.87.0}/gea/well3d.py +0 -0
  418. {gea_program-0.86.0 → gea_program-0.87.0}/gea/well_assembler.py +0 -0
  419. {gea_program-0.86.0 → gea_program-0.87.0}/gea/well_records.py +0 -0
  420. {gea_program-0.86.0 → gea_program-0.87.0}/gea/well_report.py +0 -0
  421. {gea_program-0.86.0 → gea_program-0.87.0}/gea/well_test_validation.py +0 -0
  422. {gea_program-0.86.0 → gea_program-0.87.0}/gea/wellplan.py +0 -0
  423. {gea_program-0.86.0 → gea_program-0.87.0}/gea/wellpos.py +0 -0
  424. {gea_program-0.86.0 → gea_program-0.87.0}/gea/winident.py +0 -0
  425. {gea_program-0.86.0 → gea_program-0.87.0}/gea/wits0.py +0 -0
  426. {gea_program-0.86.0 → gea_program-0.87.0}/gea/witsml.py +0 -0
  427. {gea_program-0.86.0 → gea_program-0.87.0}/gea/workspace.py +0 -0
  428. {gea_program-0.86.0 → gea_program-0.87.0}/gea/workspaces.py +0 -0
  429. {gea_program-0.86.0 → gea_program-0.87.0}/gea/x25519.py +0 -0
  430. {gea_program-0.86.0 → gea_program-0.87.0}/gea/xlsx_read.py +0 -0
  431. {gea_program-0.86.0 → gea_program-0.87.0}/gea_program.egg-info/dependency_links.txt +0 -0
  432. {gea_program-0.86.0 → gea_program-0.87.0}/gea_program.egg-info/entry_points.txt +0 -0
  433. {gea_program-0.86.0 → gea_program-0.87.0}/gea_program.egg-info/requires.txt +0 -0
  434. {gea_program-0.86.0 → gea_program-0.87.0}/gea_program.egg-info/top_level.txt +0 -0
  435. {gea_program-0.86.0 → gea_program-0.87.0}/setup.cfg +0 -0
  436. {gea_program-0.86.0 → gea_program-0.87.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.86.0
3
+ Version: 0.87.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.86.0.exe`: GEA
850
+ it installed, every release also carries `GEA-Reader-Setup-0.87.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`.
@@ -1000,6 +1000,28 @@ in plan, in section and, at its depths, in the 3D tab. Every figure a
1000
1000
  SIMULATION, said on every line. The **Fluid front** tab, `gea front`,
1001
1001
  `gea help front`.
1002
1002
 
1003
+ ### Calibration
1004
+
1005
+ The plume and the front, run many times over the numbers nobody knows
1006
+ exactly and ranked against what is measured. Each uncertain number - the
1007
+ permeability, the thickness, the porosity, the compressibility - gets a
1008
+ range, declared with its source or a default spread named as one; each
1009
+ fault layer is open in half the runs and sealing in the other half. Every
1010
+ run is scored against the pressures in the ledger (a gauge in an
1011
+ observation well, an injector's or a producer's own bottomhole pressure,
1012
+ each compared in its shape through time) and the producers' measured TDS;
1013
+ the runs the measurements do not contradict are kept, and when none comes
1014
+ close the page says NO RUN FITS and to look outside the ranges. Every
1015
+ forecast the other pages give as one number - the area of review, each
1016
+ fault's rise and the share of kept runs that take it past the friction
1017
+ line, the front's radius, each producer's share and arrival - is given as
1018
+ a range: what the declarations alone allow beside what the measurements
1019
+ leave. And what to measure next, ranked: a falloff test, a gauge at a
1020
+ neighbour, a water analysis, each with how much it would narrow the area
1021
+ of review and the front. Run by a person, kept with the hash of its inputs,
1022
+ marked stale when they change. Every figure a SIMULATION. The
1023
+ **Calibration** tab, `gea calibrate`, `gea help calibration`.
1024
+
1003
1025
  ### Plan vs actual and the survey tools
1004
1026
 
1005
1027
  Each well against its directional plan: at every survey station, how far
@@ -1664,7 +1686,7 @@ attaches the zips to the GitHub release of that tag.
1664
1686
 
1665
1687
  ### The Windows installer
1666
1688
 
1667
- Every release also carries `GEA-Program-Setup-0.86.0.exe` (for 0.86.0): the
1689
+ Every release also carries `GEA-Program-Setup-0.87.0.exe` (for 0.87.0): the
1668
1690
  same Windows kit installed like any Windows program, for the signed-in user
1669
1691
  alone and with no administrator rights (`%LOCALAPPDATA%\Programs\GEA-Program`).
1670
1692
  It asks for the site workspace (an existing one such as `C:\site` is used as
@@ -1683,7 +1705,7 @@ it, removes the program and leaves the workspace. Silent, for a site's
1683
1705
  software deployment:
1684
1706
 
1685
1707
  ```
1686
- GEA-Program-Setup-0.86.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
1708
+ GEA-Program-Setup-0.87.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
1687
1709
  ```
1688
1710
 
1689
1711
  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.86.0.exe`: GEA
811
+ it installed, every release also carries `GEA-Reader-Setup-0.87.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`.
@@ -961,6 +961,28 @@ in plan, in section and, at its depths, in the 3D tab. Every figure a
961
961
  SIMULATION, said on every line. The **Fluid front** tab, `gea front`,
962
962
  `gea help front`.
963
963
 
964
+ ### Calibration
965
+
966
+ The plume and the front, run many times over the numbers nobody knows
967
+ exactly and ranked against what is measured. Each uncertain number - the
968
+ permeability, the thickness, the porosity, the compressibility - gets a
969
+ range, declared with its source or a default spread named as one; each
970
+ fault layer is open in half the runs and sealing in the other half. Every
971
+ run is scored against the pressures in the ledger (a gauge in an
972
+ observation well, an injector's or a producer's own bottomhole pressure,
973
+ each compared in its shape through time) and the producers' measured TDS;
974
+ the runs the measurements do not contradict are kept, and when none comes
975
+ close the page says NO RUN FITS and to look outside the ranges. Every
976
+ forecast the other pages give as one number - the area of review, each
977
+ fault's rise and the share of kept runs that take it past the friction
978
+ line, the front's radius, each producer's share and arrival - is given as
979
+ a range: what the declarations alone allow beside what the measurements
980
+ leave. And what to measure next, ranked: a falloff test, a gauge at a
981
+ neighbour, a water analysis, each with how much it would narrow the area
982
+ of review and the front. Run by a person, kept with the hash of its inputs,
983
+ marked stale when they change. Every figure a SIMULATION. The
984
+ **Calibration** tab, `gea calibrate`, `gea help calibration`.
985
+
964
986
  ### Plan vs actual and the survey tools
965
987
 
966
988
  Each well against its directional plan: at every survey station, how far
@@ -1625,7 +1647,7 @@ attaches the zips to the GitHub release of that tag.
1625
1647
 
1626
1648
  ### The Windows installer
1627
1649
 
1628
- Every release also carries `GEA-Program-Setup-0.86.0.exe` (for 0.86.0): the
1650
+ Every release also carries `GEA-Program-Setup-0.87.0.exe` (for 0.87.0): the
1629
1651
  same Windows kit installed like any Windows program, for the signed-in user
1630
1652
  alone and with no administrator rights (`%LOCALAPPDATA%\Programs\GEA-Program`).
1631
1653
  It asks for the site workspace (an existing one such as `C:\site` is used as
@@ -1644,7 +1666,7 @@ it, removes the program and leaves the workspace. Silent, for a site's
1644
1666
  software deployment:
1645
1667
 
1646
1668
  ```
1647
- GEA-Program-Setup-0.86.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
1669
+ GEA-Program-Setup-0.87.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
1648
1670
  ```
1649
1671
 
1650
1672
  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.86.0"
126
+ __version__ = "0.87.0"
127
127
  __all__ = [
128
128
  "aging_rate", "rate_psi_yr", "accuracy_psi",
129
129
  "Sensor", "SimulatorConfig", "DownholeEngine",
@@ -565,7 +565,7 @@ def main(argv=None) -> int:
565
565
  p_fl.add_argument("--workspace", type=str, default=None, help="the workspace folder; without one the self-test runs on labelled scenes")
566
566
  p_fl.add_argument("--well", type=str, default=None, help="the well a declaration, a report or a removal is for")
567
567
  p_fl.add_argument("--declare", action="store_true", help="declare the well's role, formation or density (with --source)")
568
- p_fl.add_argument("--role", type=str, default=None, choices=("injection", "production"))
568
+ p_fl.add_argument("--role", type=str, default=None, choices=("injection", "production", "observation"), help="--declare: injection, production, or observation (a gauge or a water analysis, no flow)")
569
569
  p_fl.add_argument("--formation", type=str, default=None, help="--declare: the formation the well is completed in; alone with --porosity etc.: the formation to declare")
570
570
  p_fl.add_argument("--density-sg", type=float, default=None, help="--declare: the injected water's specific gravity")
571
571
  p_fl.add_argument("--density-ppg", type=float, default=None, help="--declare: the injected water's density in lb/gal")
@@ -611,6 +611,23 @@ def main(argv=None) -> int:
611
611
  p_ff.add_argument("--write", action="store_true", help="write reports/front/front.json and .md")
612
612
  p_ff.add_argument("--actor", type=str, default="cli")
613
613
  p_ff.add_argument("--json", action="store_true")
614
+ p_cb = sub.add_parser("calibrate", help="the calibration (SIMULATION): the plume and the front run many times over the uncertain numbers - permeability, thickness, porosity, compressibility, each fault open or sealing - ranked against the measured pressures and the producers' water; the ranges that leaves, and which measurement would narrow them most")
615
+ p_cb.add_argument("--workspace", type=str, default=None, help="the workspace folder; without one the self-test runs (a formation whose true numbers are not the declared ones, found from its measurements)")
616
+ p_cb.add_argument("--run", action="store_true", help="run the ensemble now and keep the result")
617
+ p_cb.add_argument("--formation", type=str, default=None, help="--run: one formation; --range: the formation the range is for")
618
+ p_cb.add_argument("--runs", type=int, default=None, help="settings: the runs, 8 to 200 (default 48)")
619
+ p_cb.add_argument("--sigma-psi", type=float, default=None, help="settings: the pressure measurements' error, psi (default 25)")
620
+ p_cb.add_argument("--sigma-share", type=float, default=None, help="settings: the error of a share of injected water read from a TDS (default 0.05)")
621
+ p_cb.add_argument("--well-radius-ft", type=float, default=None, help="settings: the wellbore radius for a flowing well's own draw (default 0.354)")
622
+ p_cb.add_argument("--sample-sealing", type=str, default=None, choices=("yes", "no"), help="settings: whether each fault layer is open in half the runs and sealing in the other half (default yes)")
623
+ p_cb.add_argument("--range", dest="range_param", type=str, default=None, choices=("k_md", "thickness_ft", "porosity", "c_t_per_psi"), help="declare an uncertain number's range for --formation: --low, --high, --source (or --clear)")
624
+ p_cb.add_argument("--low", type=float, default=None)
625
+ p_cb.add_argument("--high", type=float, default=None)
626
+ p_cb.add_argument("--clear", action="store_true", help="--range: back to the default spread")
627
+ p_cb.add_argument("--source", type=str, default="", help="where a declared range comes from")
628
+ p_cb.add_argument("--write", action="store_true", help="write reports/calibration/calibration.json and .md from the kept result")
629
+ p_cb.add_argument("--actor", type=str, default="cli")
630
+ p_cb.add_argument("--json", action="store_true")
614
631
  p_os = sub.add_parser("seismicity", help="operations and seismicity: each well's drilling, completion and disposal windows against the earthquake catalogue around it - the events during and after each, the levels a regulator's protocol would reach, and the rate during operations against the rest of the record; the Mahoning Valley worked example")
615
632
  p_os.add_argument("--workspace", type=str, default=None)
616
633
  p_os.add_argument("--scene", type=str, default=None, choices=("workspace", "mahoning"), help="your wells (the default with --workspace) or the public worked example")
@@ -2776,6 +2793,45 @@ def main(argv=None) -> int:
2776
2793
  raise SystemExit(f"front: {e.args[0] if e.args else e}")
2777
2794
  print(_json.dumps(p, default=str) if a.json else _FF.text(p))
2778
2795
  return 0
2796
+ elif a.cmd == "calibrate":
2797
+ import json as _json
2798
+ from . import calibration as _CB
2799
+ from .cli import _safe_stdout
2800
+ from .workspace import Workspace, WorkspaceError
2801
+ _safe_stdout()
2802
+ if not a.workspace:
2803
+ r = _CB.selftest()
2804
+ print(_json.dumps(r, default=str) if a.json else "\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']} ({r['runs']} runs)")
2805
+ return 0 if r["ok"] else 1
2806
+ try:
2807
+ ws = Workspace(a.workspace)
2808
+ except WorkspaceError as e:
2809
+ raise SystemExit(f"calibrate: {e}")
2810
+ try:
2811
+ if a.range_param:
2812
+ if not a.formation:
2813
+ raise SystemExit("calibrate: --range needs --formation")
2814
+ _CB.set_range(ws, a.actor, a.formation, a.range_param, None if a.clear else a.low, None if a.clear else a.high, a.source)
2815
+ rg_ = _CB.page(ws)["ranges"].get(a.formation, {}).get(a.range_param)
2816
+ print(f"{a.formation} {a.range_param}: " + (f"{rg_['low']:g} to {rg_['high']:g} ({rg_['kind']}: {rg_['source']})" if rg_ else "kept; the formation has no permeability, thickness and porosity declared yet"))
2817
+ return 0
2818
+ if any(v is not None for v in (a.runs, a.sigma_psi, a.sigma_share, a.well_radius_ft, a.sample_sealing)):
2819
+ st_ = _CB.set_settings(ws, a.actor, a.runs, a.sigma_psi, a.sigma_share, (None if a.sample_sealing is None else a.sample_sealing == "yes"), a.well_radius_ft)
2820
+ print("settings: " + ", ".join(f"{k} {v}" for k, v in st_.items() if k in ("runs", "sigma_psi", "sigma_share", "well_radius_ft", "sample_sealing")))
2821
+ if not a.run:
2822
+ return 0
2823
+ if a.run:
2824
+ r = _CB.run(ws, a.actor, a.formation)
2825
+ print(f"run: {r['seconds']} s; " + "; ".join(f"{f['formation']} {f['status']}" + (f" ({f['n_kept']} of {f['n_ok']} kept)" if f.get('n_kept') is not None else "") for f in r["formations"]))
2826
+ if a.write:
2827
+ from . import __version__ as _ver87
2828
+ r = _CB.write_report(ws, _ver87, a.actor)
2829
+ print(f"written: {', '.join(r['files'])} under {r['folder']}")
2830
+ p = _CB.page(ws)
2831
+ except (_CB.CalibrationError, WorkspaceError, ValueError, OSError) as e:
2832
+ raise SystemExit(f"calibrate: {e.args[0] if e.args else e}")
2833
+ print(_json.dumps(p, default=str) if a.json else _CB.text(p))
2834
+ return 0
2779
2835
  elif a.cmd == "seismicity":
2780
2836
  import json as _json
2781
2837
  from . import op_seismicity as _OS
@@ -18070,6 +18070,267 @@ def section_ed_front(tmp: str) -> None:
18070
18070
  "section, the help page, the README and lesson 14" + (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
18071
18071
 
18072
18072
 
18073
+ def section_ee_calibration(tmp: str) -> None:
18074
+ """Section EE - the calibration: the self-test (a formation whose true numbers are not the declared ones found from
18075
+ a gauge, the injector's pressure and a producer's water; nothing measured; a measurement no run can make); the ranges
18076
+ (default spreads named as such, a declared range with its source, the refusals), the sample (the declared case
18077
+ first, a Latin hypercube with a fixed seed, each fault layer sealing in half the runs); the ledger's observation
18078
+ well (a gauge and no flow, outside the balance); the workspace (not run, run and kept with the hash of its inputs,
18079
+ stale when they change; the kept runs, the declared case not among them, the transmissivity found, every forecast
18080
+ a range, the fault's rise against its pressure to slip, the earthquake beside it, what to measure next; a workspace
18081
+ with nothing measured; the report, the dossier, the audit); the routes, the tab, the command, the help, the README
18082
+ and the lesson."""
18083
+ import http.cookiejar
18084
+ import math
18085
+ import subprocess as _sp
18086
+ import urllib.error
18087
+ import urllib.request
18088
+ import zipfile as _zf
18089
+ from . import __version__ as _ver
18090
+ from . import calibration as CB
18091
+ from . import client_reports as CR
18092
+ from . import dossier as DZ
18093
+ from . import fluid as FL
18094
+ from . import front as FR
18095
+ from . import helplib as H
18096
+ from . import op_seismicity as OS
18097
+ from . import shapefile as SF
18098
+ from .service import Service, Users
18099
+ from .workspace import Workspace
18100
+ pkg = Path(__file__).parent
18101
+ d = Path(tmp, "ee"); d.mkdir()
18102
+ fm = {"k_md": 50.0, "thickness_ft": 100.0, "porosity": 0.12, "mu_cp": 0.6, "water_tds_mgl": 60000.0, "water_sg": 1.0414}
18103
+ truth = {"k_md": 110.0, "thickness_ft": 80.0, "porosity": 0.10, "c_t_per_psi": 7e-6}
18104
+ # -- EE1 the arithmetic ---------------------------------------------------------------------------------------------------
18105
+ st = CB.selftest()
18106
+ rg = CB.parameter_ranges(fm)
18107
+ rg2 = CB.parameter_ranges(fm, {"k_md": {"low": 15.0, "high": 200.0, "source": "core report"}})
18108
+ smp = CB.sample(rg, ["A", "B"], ["B"], 21, 3, True); smp_n = CB.sample(rg, ["A", "B"], ["B"], 21, 3, False)
18109
+ a_ = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
18110
+ errs = {}
18111
+ for name, fn in (("no_injector", lambda: CB.make_scene("F", fm, [w_ for w_ in CB.synthetic_wells(30) if w_["role"] != "injection"], [])),
18112
+ ("no_k", lambda: CB.make_scene("F", {"thickness_ft": 100.0, "porosity": 0.1}, CB.synthetic_wells(30), []))):
18113
+ try:
18114
+ fn(); errs[name] = False
18115
+ except CB.CalibrationError:
18116
+ errs[name] = True
18117
+ c1 = {
18118
+ "selftest": st["ok"] and st["label"] == "SIMULATION" and len(st["checks"]) == 10,
18119
+ "ranges": rg["k_md"]["kind"] == "default" and abs(rg["k_md"]["low"] - 50.0 / 3) < 1e-9 and rg["k_md"]["high"] == 150.0 and rg["thickness_ft"]["low"] == 70.0 and abs(rg["porosity"]["high"] - 0.156) < 1e-9
18120
+ and abs(rg["c_t_per_psi"]["centre"] - 7e-6) < 1e-12 and "default" in rg["k_md"]["source"] and rg2["k_md"]["kind"] == "declared" and rg2["k_md"]["low"] == 15.0 and rg2["k_md"]["source"] == "core report"
18121
+ and rg2["thickness_ft"]["kind"] == "default",
18122
+ "sample": len(smp) == 21 and smp[0]["declared_case"] and smp[0]["sealing"] == ["B"] and smp[0]["k_md"] == 50.0 and sum(1 for s_ in smp[1:] if "A" in s_["sealing"]) == 10
18123
+ and sum(1 for s_ in smp[1:] if "B" in s_["sealing"]) == 10 and all(s_["sealing"] == ["B"] for s_ in smp_n) and len({round(s_["k_md"], 6) for s_ in smp}) == 21
18124
+ and CB.sample(rg, ["A", "B"], ["B"], 21, 3, True) == smp and CB.sample(rg, ["A", "B"], ["B"], 21, 4, True) != smp,
18125
+ "misfit": CB._nrms(a_ + 100.0, a_, 2.0, demean=True) < 1e-12 and abs(CB._nrms(a_ + 4.0, a_, 2.0, demean=False) - 2.0) < 1e-12 and abs(CB._spearman(a_, a_ ** 3) - 1.0) < 1e-12
18126
+ and abs(CB._spearman(a_, -a_) + 1.0) < 1e-12 and CB._spearman(a_[:3], a_[:3]) == 0.0,
18127
+ "scene": all(errs.values()),
18128
+ }
18129
+ failed1 = [k_ for k_, v in c1.items() if not v]
18130
+ ok(not failed1,
18131
+ "EE1 the arithmetic: the self-test's ten checks (the sample, nothing measured, three measurements read, CALIBRATED with the declared case not kept, the transmissivity "
18132
+ "and the pore thickness found with the truth inside the kept runs, the truth's forecasts inside them, NO RUN FITS for a gauge falling while the well injects, the "
18133
+ "narrowing estimate); the default spreads by their rule and named as defaults, a declared range with its source beside them; the sample of 21 with the declared "
18134
+ "case first, each fault layer sealing in ten of the twenty, as declared when the sampling is off, the same seed the same runs and another seed others; the misfit "
18135
+ "blind to a level when the mean is taken off and two errors for an offset of two errors when not; the rank correlation; a scene without an injector or a "
18136
+ "permeability declined" + (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
18137
+ # -- EE2 the workspace --------------------------------------------------------------------------------------------------
18138
+ def site(name: str, measured: bool):
18139
+ wsp_ = str(d / name); ws_ = Workspace.create(wsp_, "Pad 3", actor="tester")
18140
+ wl = CB.synthetic_wells(days=180)
18141
+ tr_ = CB.measure_truth(wl, fm, truth) if measured else None
18142
+ ids_ = {}
18143
+ for w_ in wl:
18144
+ rec_ = ws_.add_well_records(w_["display"], actor="tester"); ids_[w_["well"]] = rec_["id"]
18145
+ ws_.set_well(rec_["id"], surface={"lat": w_["surface"]["lat"], "lon": w_["surface"]["lon"], "datum": "WGS84", "elevation": {"ft": 2900.0, "datum": "KB", "source": "test plat"}}, actor="tester")
18146
+ ws_.set_well(ids_["SWD-1"], disposal={"top_interval_ft": 8700.0, "base_interval_ft": 9300.0, "depth_reference": "TVD", "depth_tier": "deep"}, actor="tester")
18147
+ ws_.set_stress({"sv_psi_ft": 1.05, "shmin_psi_ft": 0.65, "shmax_psi_ft": 0.95, "pp_psi_ft": 0.45, "gradients_source": "the gate", "shmax_azimuth_deg": 80.0, "azimuth_source": "the gate"}, actor="tester")
18148
+ return wsp_, ws_, {w_["well"]: w_ for w_ in wl}, ids_, tr_
18149
+ wsp, ws, by, ids, tr = site("ws", True)
18150
+ kmlat = 1 / 111.195
18151
+ feats = [([[(-102.27, 31.96 + 2 * kmlat), (-102.21, 31.96 + 2 * kmlat)]], {"name": "North fault"})] # 2 km north, east-west
18152
+ wkt = 'GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]]'
18153
+ SF.write(str(d / "faults"), "PolyLine", feats, [("name", "C", 20, 0)], wkt)
18154
+ with _zf.ZipFile(str(d / "faults.zip"), "w") as z:
18155
+ for ext in (".shp", ".shx", ".dbf", ".prj"):
18156
+ z.write(str(d / ("faults" + ext)), "faults" + ext)
18157
+ lay = ws.add_layer(str(d / "faults.zip"), "Gate faults", actor="tester", feature_kind="fault", citation="the gate's own layer")
18158
+ cat = ("#EventID|Time|Latitude|Longitude|Depth/km|Author|Catalog|Contributor|ContributorID|MagType|Magnitude|MagAuthor|EventLocationName\n"
18159
+ "tx2026q|2026-05-10T04:11:00|31.979|-102.24|5.0|TexNet|TX|TexNet|a|ML|2.3|TexNet|gate\n" # 100 m from the fault, day 130
18160
+ "tx2026r|2026-04-02T10:00:00|32.40|-102.24|5.0|TexNet|TX|TexNet|b|ML|2.9|TexNet|gate\n" # 47 km north: near no mapped fault
18161
+ "tx2025z|2025-11-02T10:00:00|31.979|-102.24|5.0|TexNet|TX|TexNet|c|ML|2.0|TexNet|gate\n") # before the record
18162
+ OS.attach_catalog(ws, "tester", "cat.txt", cat.encode(), "2025-10-01", "2026-07-01", 1.0, 31.96, -102.24, 60.0, "TexNet (gate)")
18163
+ empty = CB.page(ws)
18164
+ fv = lambda v: "" if v is None else f"{v:.1f}"
18165
+ FL.declare_well(ws, "tester", ids["SWD-1"], role="injection", formation="Ellenburger", tds_mgl=120000.0, source="W-2; water analysis")
18166
+ FL.declare_well(ws, "tester", ids["P-7H"], role="production", formation="Ellenburger", source="permit")
18167
+ gauge_csv = ("date,bhp_psi\n" + "\n".join(f"{x['date']},{fv(x['bhp_psi'])}" for x in by["OBS-1"]["days"]) + "\n").encode()
18168
+ try:
18169
+ FL.attach_report(ws, "tester", ids["OBS-1"], "gauge.csv", gauge_csv, "gauge export"); gauge_needs_role = False
18170
+ except FL.FluidError:
18171
+ gauge_needs_role = True # a report without a volume is an observation well's alone
18172
+ FL.declare_well(ws, "tester", ids["OBS-1"], role="observation", formation="Ellenburger", source="permit")
18173
+ FL.attach_report(ws, "tester", ids["OBS-1"], "gauge.csv", gauge_csv, "gauge export")
18174
+ try:
18175
+ FL.attach_report(ws, "tester", ids["OBS-1"], "empty.csv", b"date,note\n2026-01-01,x\n", "x"); obs_empty = False
18176
+ except FL.FluidError:
18177
+ obs_empty = True
18178
+ FL.attach_report(ws, "tester", ids["SWD-1"], "h10.csv", ("date,injection_volume_bbl,bhp_psi\n" + "\n".join(f"{x['date']},{x['volume_bbl']:.1f},{fv(x['bhp_psi'])}" for x in by["SWD-1"]["days"]) + "\n").encode(), "H-10 (gate)")
18179
+ FL.attach_report(ws, "tester", ids["P-7H"], "prod.csv", ("date,water_bbl,tds_mgl\n" + "\n".join(f"{x['date']},{-x['volume_bbl']:.1f},{fv(x['tds_mgl'])}" for x in by["P-7H"]["days"]) + "\n").encode(), "production report (gate)")
18180
+ FL.declare_formation(ws, "tester", "Ellenburger", "petrophysics (gate)", porosity=0.12, thickness_ft=100.0, area_acres=11000.0, k_md=50.0, mu_cp=0.6, p_initial_psi=3000.0, water_tds_mgl=60000.0)
18181
+ fpg = FL.page(ws); fwl = {w_["well"]: w_ for w_ in fpg["wells"]}; fbal = next(f_ for f_ in fpg["formations"] if f_["formation"] == "Ellenburger")
18182
+ FR.set_settings(ws, "tester", projection_days=365)
18183
+ refused = {}
18184
+ for name, fn in (("runs", lambda: CB.set_settings(ws, "tester", runs=4)), ("sigma", lambda: CB.set_settings(ws, "tester", sigma_psi=0.0)), ("share", lambda: CB.set_settings(ws, "tester", sigma_share=0.9)),
18185
+ ("radius", lambda: CB.set_settings(ws, "tester", well_radius_ft=9.0)), ("param", lambda: CB.set_range(ws, "tester", "Ellenburger", "skin", 1, 2, "x")),
18186
+ ("order", lambda: CB.set_range(ws, "tester", "Ellenburger", "k_md", 200, 15, "x")), ("source", lambda: CB.set_range(ws, "tester", "Ellenburger", "k_md", 15, 200)),
18187
+ ("clear_none", lambda: CB.set_range(ws, "tester", "Ellenburger", "k_md", None, None)), ("formation", lambda: CB.run(ws, "tester", "Nowhere")),
18188
+ ("write_unrun", lambda: CB.write_report(ws, _ver, "tester"))):
18189
+ try:
18190
+ fn(); refused[name] = False
18191
+ except CB.CalibrationError:
18192
+ refused[name] = True
18193
+ CB.set_settings(ws, "tester", runs=24)
18194
+ not_run = CB.page(ws)
18195
+ res = CB.run(ws, "tester")
18196
+ pg = CB.page(ws); f = pg["result"]["formations"][0]
18197
+ par = {p_["parameter"]: p_ for p_ in f["parameters"]}; fc = f["forecasts"]
18198
+ CB.set_range(ws, "tester", "Ellenburger", "k_md", 60.0, 200.0, "core report 2024 (gate)")
18199
+ stale = CB.page(ws)
18200
+ res2 = CB.run(ws, "tester"); f2 = res2["formations"][0]
18201
+ cur = CB.page(ws)
18202
+ wr = CB.write_report(ws, _ver, "tester")
18203
+ txt = (Path(wr["folder"]) / "calibration.md").read_text(encoding="utf-8").lower()
18204
+ FL.write_report(ws, _ver, "tester")
18205
+ dz = DZ.build(ws, "tester", _ver, None)
18206
+ names = _zf.ZipFile(Path(ws.reports_dir, dz["path"])).namelist()
18207
+ audit = Path(ws.audit_path).read_text(encoding="utf-8")
18208
+ # nothing measured: another site, the same wells, no gauge, no pressure, no TDS
18209
+ wsp0, ws0, by0, ids0, _ = site("ws0", False)
18210
+ FL.declare_well(ws0, "tester", ids0["SWD-1"], role="injection", formation="Ellenburger", tds_mgl=120000.0, source="W-2")
18211
+ FL.declare_well(ws0, "tester", ids0["P-7H"], role="production", formation="Ellenburger", source="permit")
18212
+ FL.attach_report(ws0, "tester", ids0["SWD-1"], "h10.csv", ("date,injection_volume_bbl\n" + "\n".join(f"{x['date']},{x['volume_bbl']:.1f}" for x in by0["SWD-1"]["days"]) + "\n").encode(), "H-10 (gate)")
18213
+ FL.attach_report(ws0, "tester", ids0["P-7H"], "prod.csv", ("date,water_bbl\n" + "\n".join(f"{x['date']},{-x['volume_bbl']:.1f}" for x in by0["P-7H"]["days"]) + "\n").encode(), "report (gate)")
18214
+ FL.declare_formation(ws0, "tester", "Ellenburger", "petrophysics (gate)", porosity=0.12, thickness_ft=100.0, area_acres=11000.0, k_md=50.0, mu_cp=0.6, water_tds_mgl=60000.0)
18215
+ FR.set_settings(ws0, "tester", projection_days=365); CB.set_settings(ws0, "tester", runs=12)
18216
+ f0 = CB.run(ws0, "tester")["formations"][0]
18217
+ c2 = {
18218
+ "empty": empty["status"] == "EMPTY" and "Nothing to calibrate" in empty["lines"][0] and empty["result"] is None,
18219
+ "observation": gauge_needs_role and obs_empty and fwl[ids["OBS-1"]]["role"] == "observation" and fwl[ids["OBS-1"]]["n_bhp"] == 180 and fwl[ids["OBS-1"]]["n_with_volume"] == 0
18220
+ and "no flow" in fwl[ids["OBS-1"]]["record"] and ids["OBS-1"] not in fbal["wells"] and "observation" in FL.ROLES,
18221
+ "refusals": all(refused.values()),
18222
+ "not_run": not_run["status"] == "NOT RUN" and not_run["formations"] == ["Ellenburger"] and not_run["ranges"]["Ellenburger"]["k_md"]["kind"] == "default" and "24 runs" in not_run["lines"][0],
18223
+ "kept": pg["status"] == "OK" and res["key"] == pg["result"]["key"] and f["status"] == "CALIBRATED" and f["label"] == "SIMULATION" and f["n_runs"] == 24 and 1 <= f["n_kept"] <= 10
18224
+ and f["best_misfit"] < 1.5 and f["declared_misfit"] > 2.0 and not f["declared_kept"] and f["runs"][0]["kept"] and f["runs"][0]["misfit"] == f["best_misfit"]
18225
+ and {m_["key"] for m_ in f["measurements"]} == {"p:" + ids["SWD-1"], "p:" + ids["OBS-1"], "w:" + ids["P-7H"]}
18226
+ and all(len(m_["days"]) == len(m_["measured"]) == len(m_["best"]) == len(m_["all_lo"]) == len(m_["kept_hi"]) for m_ in f["measurements"]),
18227
+ "found": par["k_h"]["kept"]["lo"] * 0.8 <= tr["k_h"] <= par["k_h"]["kept"]["hi"] * 1.2 and par["k_h"]["narrowed"] > 0.3 and par["k_h"]["declared"] == 5000.0
18228
+ and par["h_phi"]["kept"]["lo"] * 0.8 <= tr["h_phi"] <= par["h_phi"]["kept"]["hi"] * 1.2 and par["k_md"]["range_kind"] == "default" and par["k_md"]["all"]["p10"] < par["k_md"]["kept"]["p50"],
18229
+ "forecasts": fc["aor_1y_acres"]["kept"]["lo"] * 0.75 <= tr["aor1_acres"] <= fc["aor_1y_acres"]["kept"]["hi"] * 1.25 and fc["aor_1y_acres"]["all"]["p90"] > fc["aor_1y_acres"]["all"]["p10"]
18230
+ and fc["front_half_end_ft"]["kept"]["lo"] * 0.85 <= tr["half_end_ft"] <= fc["front_half_end_ft"]["kept"]["hi"] * 1.15 and fc["aor_acres"]["declared_case"] is not None
18231
+ and any(w_["well"] == ids["P-7H"] and w_["arrives_share_of_kept"] == 1.0 and w_["arrival_day"]["p50"] < 120 for w_ in fc["wells"]),
18232
+ "fault": len(fc["faults"]) == 1 and fc["faults"][0]["name"] == "North fault" and 100.0 < fc["faults"][0]["pressure_to_slip_psi"] < 200.0 and 0.0 <= fc["faults"][0]["past_line_1y_share"] <= 1.0
18233
+ and fc["faults"][0]["rise_1y_psi"]["all"]["p90"] > fc["faults"][0]["rise_1y_psi"]["all"]["p10"] > 0 and f["sealing"][0]["layer"] == lay["id"]
18234
+ and abs(f["sealing"][0]["sealing_share_all"] - 0.5) < 0.05,
18235
+ "earthquake": len(f["earthquakes"]) == 1 and f["earthquakes"][0]["event_id"] == "tx2026q" and f["earthquakes"][0]["fault"] == "North fault" and f["earthquakes"][0]["distance_km"] < 0.5
18236
+ and f["earthquakes"][0]["day"] == 130 and f["earthquakes"][0]["rise_psi"]["p90"] >= f["earthquakes"][0]["rise_psi"]["p10"] > 0,
18237
+ "next": f["next"][0]["what"].startswith("a falloff test on SWD 1") and not any("gauge at OBS 1" in c_["what"] or "bottomhole pressure of SWD 1" in c_["what"] for c_ in f["next"])
18238
+ and all(0.0 <= c_["narrows_aor"] <= 1.0 for c_ in f["next"]) and "next_basis" in f,
18239
+ "stale": stale["status"] == "STALE" and stale["lines"][0].startswith("STALE") and stale["ranges"]["Ellenburger"]["k_md"]["kind"] == "declared" and cur["status"] == "OK"
18240
+ and f2["ranges"]["k_md"]["low"] == 60.0 and all(r_["k_md"] >= 60.0 - 1e-9 for r_ in f2["runs"] if not r_["declared_case"]) and f2["runs"] != f["runs"]
18241
+ and any(p_["parameter"] == "k_md" and "core report 2024" in p_["source"] for p_ in f2["parameters"]),
18242
+ "unmeasured": f0["status"] == "NO MEASUREMENT" and f0["n_kept"] == f0["n_ok"] == 12 and f0["measurements"] == [] and f0["best_misfit"] is None and f0["forecasts"]["faults"] == []
18243
+ and {c_["what"] for c_ in f0["next"]} >= {"a falloff test on SWD 1", "the bottomhole pressure of SWD 1 through the record", "a gauge at P 7H for a year", "a water analysis at P 7H in a year"}
18244
+ and any("NO MEASUREMENT" in l_ for l_ in f0["lines"]) and f0["forecasts"]["aor_1y_acres"]["narrowed"] is None,
18245
+ "written": set(wr["files"]) == {"calibration.json", "calibration.md"} and "simulation" in txt and "what to measure next" in txt and not [t for t in CR.FORBIDDEN_TERMS if t in txt]
18246
+ and Path(wsp, "records", "calibration_result.json").is_file(),
18247
+ "dossier": "results/calibration.json" in names and "reports/calibration/calibration.md" in names and "declarations/records/calibration.json" in names
18248
+ and all(x in audit for x in ("calibration.settings", "calibration.range", "calibration.run", "calibration.report")),
18249
+ }
18250
+ failed2 = [k_ for k_, v in c2.items() if not v]
18251
+ ok(not failed2,
18252
+ "EE2 the workspace: nothing to calibrate until the ledger has an injection well; a report with dates and a pressure and no volume declined for a well not declared an "
18253
+ "observation well and taken for one that is, one with neither a pressure nor a TDS declined, the observation well in the ledger with its 180 pressures and no "
18254
+ "flow and outside the balance; runs under eight, an error of nothing, a share error of ninety points, a nine-foot wellbore, an unknown number, a range upside "
18255
+ "down or without its source, a default cleared, a formation not in the ledger and a report before any run - each declined; NOT RUN with the default ranges "
18256
+ "shown; then 24 runs on a site whose true formation is not the declared one - CALIBRATED, the result kept with the hash of its inputs, the three measurements "
18257
+ "each with its envelopes, the best run kept and first, the declared case not kept; the true transmissivity and pore thickness inside the kept runs and the "
18258
+ "transmissivity narrowed by a third; the truth's area of review and front inside the kept ranges, the producer reached in every kept run; the mapped fault's "
18259
+ "rise as a range against its pressure to slip with the share of kept runs past it, its layer sealing in half the runs; the one earthquake beside that fault "
18260
+ "within the record listed with the rise on it that month, the far one and the earlier one not; a falloff test first among what to measure next and no gauge "
18261
+ "proposed where one is; a range declared with its source making the result STALE, the next run inside it and CURRENT; a site with nothing measured NO "
18262
+ "MEASUREMENT with every run kept and a gauge, a pressure, a water analysis and a falloff test to choose from; the report free of the client-report terms; the "
18263
+ "dossier's results/calibration.json, the report and the declared ranges; the audit" + (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
18264
+ # -- EE3 the routes, the tab, the command, the help, the README and the lesson -----------------------------------------------
18265
+ CB.set_settings(ws, "tester", runs=8)
18266
+ Users(str(Path(wsp, "users.json"))).add("v", "viewer-pass-1", "viewer"); Users(str(Path(wsp, "users.json"))).add("op", "op-pass-123", "operator")
18267
+ svc = Service(wsp, port=0, scheduler=False).start()
18268
+ base_url = svc.url.rstrip("/")
18269
+
18270
+ def opener(name, pw_):
18271
+ o = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
18272
+ rq = urllib.request.Request(base_url + "/api/login", method="POST", data=json.dumps({"name": name, "password": pw_}).encode())
18273
+ rq.add_header("Content-Type", "application/json"); rq.add_header("X-GEA-Action", "1"); o.open(rq, timeout=30)
18274
+ return o
18275
+
18276
+ def call(o, method, path, body=None):
18277
+ rq = urllib.request.Request(base_url + path, method=method, data=(json.dumps(body).encode() if body is not None else None))
18278
+ if method == "POST":
18279
+ rq.add_header("Content-Type", "application/json"); rq.add_header("X-GEA-Action", "1")
18280
+ try:
18281
+ with o.open(rq, timeout=300) as rr_:
18282
+ return rr_.status, json.loads(rr_.read())
18283
+ except urllib.error.HTTPError as e:
18284
+ return e.code, json.loads(e.read())
18285
+ try:
18286
+ V, O = opener("v", "viewer-pass-1"), opener("op", "op-pass-123")
18287
+ s_vg, vg = call(V, "GET", "/api/calibration")
18288
+ s_vr, _ = call(V, "POST", "/api/calibration/run", {})
18289
+ s_or, or_ = call(O, "POST", "/api/calibration/run", {})
18290
+ s_g2, g2 = call(V, "GET", "/api/calibration")
18291
+ s_os, os_ = call(O, "POST", "/api/calibration/settings", {"runs": "10", "sigma_psi": "20", "sample_sealing": "no"})
18292
+ s_bs, _ = call(O, "POST", "/api/calibration/settings", {"runs": "3"})
18293
+ s_rg, rg_ = call(O, "POST", "/api/calibration/range", {"formation": "Ellenburger", "parameter": "porosity", "low": "0.07", "high": "0.14", "source": "log analysis (api)"})
18294
+ s_br, _ = call(O, "POST", "/api/calibration/range", {"formation": "Ellenburger", "parameter": "porosity", "low": "0.2", "high": "0.1", "source": "x"})
18295
+ s_cl, _ = call(O, "POST", "/api/calibration/range", {"formation": "Ellenburger", "parameter": "porosity"})
18296
+ s_g3, g3 = call(V, "GET", "/api/calibration")
18297
+ s_ow, ow = call(O, "POST", "/api/calibration/write", {})
18298
+ s_vw, _ = call(V, "POST", "/api/calibration/write", {})
18299
+ s_na, _ = call(O, "POST", "/api/calibration/nothing", {})
18300
+ finally:
18301
+ svc.stop()
18302
+ cli_w = _sp.run([sys.executable, "-m", "gea", "calibrate", "--workspace", wsp], capture_output=True, text=True, cwd=str(pkg.parent))
18303
+ cli_r = _sp.run([sys.executable, "-m", "gea", "calibrate", "--workspace", wsp, "--runs", "8", "--sample-sealing", "yes", "--run"], capture_output=True, text=True, cwd=str(pkg.parent))
18304
+ cli_g = _sp.run([sys.executable, "-m", "gea", "calibrate", "--workspace", wsp, "--range", "thickness_ft", "--formation", "Ellenburger", "--low", "60", "--high", "120", "--source", "logs (cli)"], capture_output=True, text=True, cwd=str(pkg.parent))
18305
+ cli_b = _sp.run([sys.executable, "-m", "gea", "calibrate", "--workspace", wsp, "--range", "thickness_ft", "--formation", "Ellenburger", "--low", "60", "--high", "120"], capture_output=True, text=True, cwd=str(pkg.parent))
18306
+ cli_j = _sp.run([sys.executable, "-m", "gea", "calibrate", "--workspace", wsp, "--json"], capture_output=True, text=True, cwd=str(pkg.parent))
18307
+ cli_o = _sp.run([sys.executable, "-m", "gea", "calibrate", "--workspace", wsp, "--write"], capture_output=True, text=True, cwd=str(pkg.parent))
18308
+ cli_h = _sp.run([sys.executable, "-m", "gea", "fluid", "--help"], capture_output=True, text=True, cwd=str(pkg.parent))
18309
+ page_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
18310
+ readme = (pkg.parent / "README.md").read_text(encoding="utf-8") if (pkg.parent / "README.md").is_file() else ""
18311
+ lesson = (pkg / "help" / "tutorial" / "14-production-pages.md").read_text(encoding="utf-8")
18312
+ c3 = {
18313
+ "api": s_vg == 200 and vg["status"] == "STALE" and vg["label"] == "SIMULATION" and s_vr == 403 and s_or == 200 and or_["formations"][0]["status"] in ("CALIBRATED", "NO RUN FITS") and s_g2 == 200
18314
+ and g2["status"] == "OK" and g2["result"]["formations"][0]["n_runs"] == 8 and s_os == 200 and os_["runs"] == 10 and os_["sigma_psi"] == 20.0 and os_["sample_sealing"] is False and s_bs == 400
18315
+ and s_rg == 200 and rg_["ranges"]["Ellenburger"]["porosity"]["low"] == 0.07 and s_br == 400 and s_cl == 200 and s_g3 == 200 and g3["status"] == "STALE"
18316
+ and g3["ranges"]["Ellenburger"]["porosity"]["kind"] == "default" and s_ow == 200 and "calibration.md" in ow["files"] and s_vw == 403 and s_na == 404,
18317
+ "cli": cli_w.returncode == 0 and "STALE" in cli_w.stdout and "the uncertain numbers" in cli_w.stdout and cli_r.returncode == 0 and "runs 8" in cli_r.stdout and "run: " in cli_r.stdout
18318
+ and "of 8 kept" in cli_r.stdout and cli_g.returncode == 0 and "60 to 120 (declared: logs (cli))" in cli_g.stdout and cli_b.returncode != 0 and "source" in cli_b.stderr
18319
+ and cli_j.returncode == 0 and json.loads(cli_j.stdout)["status"] == "STALE" and cli_o.returncode == 0 and "calibration.md" in cli_o.stdout and "observation" in cli_h.stdout,
18320
+ "page": all(x in page_src for x in ("VIEWS.calibration", "['#/calibration', 'Calibration']", "/api/calibration/run", "/api/calibration/range", "cbPlot", "cbBar", "help('calibration')",
18321
+ "observation (a gauge, no flow)")),
18322
+ "help": not H.check("calibration") and H.VIEW_TOPIC.get("calibration") == "calibration" and any(t == "calibration" for t, _, _ in H.INDEX)
18323
+ and all(x in (H.page("calibration") or "") for x in ("Latin hypercube", "Peaceman", "NO RUN FITS", "SIMULATION", "gea calibrate --workspace C:\\site --run")) and "observation" in (H.page("fluid") or ""),
18324
+ "readme_lesson": (not readme or ("### Calibration" in readme and "`gea calibrate`" in readme)) and "**Calibration**" in lesson and "calibration" in lesson.split("Help:")[-1],
18325
+ }
18326
+ failed3 = [k_ for k_, v in c3.items() if not v]
18327
+ ok(not failed3,
18328
+ "EE3 on the API (anyone reads the kept result and whether it is stale; only an operator runs, keeps settings, declares or clears a range, or writes; too few runs and a "
18329
+ "range upside down are 400; an unknown action 404), the command (the kept result, settings and a run in one line, a range declared and one without its source "
18330
+ "stopped, the page as JSON, the report; the fluid command's observation role), the tab with its envelopes and range bars, the help pages, the README and lesson 14"
18331
+ + (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
18332
+
18333
+
18073
18334
  def main() -> int:
18074
18335
  print("GEA-Program - ACCEPTANCE SUITE (the product gate)")
18075
18336
  # a handle a job subprocess still holds at the end must not turn a finished gate into a traceback on Windows:
@@ -18207,6 +18468,7 @@ def main() -> int:
18207
18468
  section_eb_fluid(tmp)
18208
18469
  section_ec_plume(tmp)
18209
18470
  section_ed_front(tmp)
18471
+ section_ee_calibration(tmp)
18210
18472
  if _FAILS:
18211
18473
  print(f"[ACCEPTANCE] {len(_FAILS)} FAILURES ({_PASS} passed):")
18212
18474
  for f in _FAILS: