gea-program 0.88.0__tar.gz → 0.89.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.
- {gea_program-0.88.0/gea_program.egg-info → gea_program-0.89.0}/PKG-INFO +24 -4
- {gea_program-0.88.0 → gea_program-0.89.0}/README.md +23 -3
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/__init__.py +1 -1
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/__main__.py +59 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/acceptance_tests.py +230 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/IT_SECURITY.md +14 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/driller.md +1 -1
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/install.md +2 -2
- gea_program-0.89.0/gea/help/mcp.md +15 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/reader.md +1 -1
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/recorder.md +1 -1
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/01-install.md +2 -2
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/19-dossier-reader.md +1 -1
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/20-admin.md +2 -1
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/22-updates.md +1 -1
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/23-vpn.md +1 -1
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/25-install-recorder.md +2 -2
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/29-driller-rig.md +1 -1
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial.md +2 -2
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/helplib.py +2 -1
- gea_program-0.89.0/gea/mcp_server.py +718 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/service.py +13 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/web/app.html +25 -1
- {gea_program-0.88.0 → gea_program-0.89.0/gea_program.egg-info}/PKG-INFO +24 -4
- {gea_program-0.88.0 → gea_program-0.89.0}/gea_program.egg-info/SOURCES.txt +2 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/pyproject.toml +1 -1
- {gea_program-0.88.0 → gea_program-0.89.0}/LICENSE +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/accuracy_statement.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/alarm_engine.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/alerts.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/backup.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/bench.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/bit_seismic.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/blind_harness.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/calibration.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/casing_design.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/med_160_sapropels.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog_map.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/catalog_register.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/certificates.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/cli.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/client_reports.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/collision.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/config_versioning.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/conformance.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/control_room.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/correlation.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/dashboard.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/declarations.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/decline.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/deviation.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/dlis.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/dnp3.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/doctor.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/dossier.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/dossier_verify.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/downhole_engine.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/drift_monitor.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/drill_string.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/driller_link.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/dysfunction.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/earth_model.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/economics.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/ed25519.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/edr.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/elevation.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/etp.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/etp12_schemas.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/example_register_map.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/fat_sat.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/field_pull.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/files.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/fixtures/README.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/fixtures/comcat_delaware_basin_2026-09.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/fixtures/comcat_mahoning_1990-2026.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/fixtures/comcat_youngstown_2011-2012.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/fixtures/ne_110m_coastline.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/fluid.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/follower.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/forward_model.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/frac_hits.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/friction_priors.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/front.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/gamma.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/gauge_aging.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/gauge_specs.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/geodesy.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/geomag.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/gravity_reference.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/hartip.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/TESTER_GUIDE.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/alarms.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/alerts.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/audit-update.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/backup.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/bit-image.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/calibration.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/casing.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/catalog.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/charts.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/collision.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/company-sign-in.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/conformance.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/control-room.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/data-in.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/declare.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/decline.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/dlis.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/doctor.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/dossier.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/drift.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/drillstring.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/dysfunction.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/economics.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/edr.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/etp.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/field-ports.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/files.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/fluid.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/frac-hits.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/front.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/historian.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/https.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/hydraulics.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/instruments.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/interval.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/invoice-check.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/map.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/month-end.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/notifications.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/opseis.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/osdu.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/pad-summary.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/patches.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/penetrator.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/plan.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/plume.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/pore-pressure.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/ppdm.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/quakeml.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/quality.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/records.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/report-history.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/rig-time.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/roadmap.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/rocks.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/seedlink.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/seismic.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/setup.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/simulation.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/site.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/sites.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/slip.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/soak.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/sra.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/start.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/structure.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tools.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/torque-drag.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/transients.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/02-sign-in.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/03-site.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/04-add-well.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/05-records.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/06-well-page.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/07-declare.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/08-patches.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/09-alarms.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/10-control-room.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/11-summary-month.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/12-where-the-well-is.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/13-drilling-pages.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/14-production-pages.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/15-seismic.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/16-seismicity.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/17-recorder-office.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/18-reports.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/21-upkeep.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/24-the-box.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/26-monitor.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/27-mirror-vpn.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/tutorial/28-driller-office.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/upkeep.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/vibration.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/vpn.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/well-report.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/well-tests.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/help/well3d.md +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/housekeeping.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/hydraulics.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/icon.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/interval.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/inverse_engine.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/invoice_check.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/jobs.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/launcher.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/live_ports.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/loadtest.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/matplotlib_demo.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/modbus.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/modbus_rtu.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/model_card.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/month_end.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/mqtt_port.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/notify.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/oidc.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/oidc_mock.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/op_seismicity.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/opcua_port.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/operator_app.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/osdu.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/pad_summary.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/patches.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/pdf_report.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/penetrator.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/permits.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/piwebapi.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/plume.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/pore_pressure.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/ports.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/ppdm.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/profile_catalog.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/project.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/qt6_downhole_app.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/quakeml.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reader.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reader_app.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reconciler.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/recorder_link.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/WMM2025.COF +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/eia_henry_hub_daily.csv.gz +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/eia_prices.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/eia_wti_daily.csv.gz +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/iscwsa_rev4_example.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/iscwsa_rev5_example.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/l0701_sonic_gr.las.gz +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/l0701_sonic_gr.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/libmseed_steim.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/mahoning_example.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/mud_motor_specs.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/owsg_tool_models.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/penetrator_ratings.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/seismicity_protocols.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/tool_sources.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/us_outline.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/us_outline.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/volve_3d.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/volve_f4_interpretation.las.gz +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/volve_f4_logs.provenance.json +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/volve_f4_lwd.las.gz +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/volve_surfaces.json.gz +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/volve_traj_F-10.xml.gz +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/volve_traj_F-4.xml.gz +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/volve_traj_F-5_12.25in.xml.gz +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/volve_traj_F-5_17.5in.xml.gz +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/volve_traj_F-5_36in.xml.gz +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/volve_traj_F-5_8.5in.xml.gz +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/reference/volve_well_picks.csv.gz +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/report_history.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/rig_state.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/roadmap.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/rock_inventory.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/sample_record.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/sample_well_profile.csv +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/sbom.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/seedlink.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/segy.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/seismic.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/seismic_array.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/seismic_assoc.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/seismic_detect.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/seismic_film.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/seismic_harmonic.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/seismic_qc.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/seismic_response.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/seismic_signature.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/seismic_track.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/seismic_uncertainty.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/seismic_unlisted.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/seismic_watch.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/sensor_swap.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/series_cache.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/service_life.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/setup_checklist.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/shapefile.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/shell.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/shut_in.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/simulation.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/site_map.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/sla_report.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/slip.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/soak.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/sra.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/store_forward.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/strata_join.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/structure.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/supervisor.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/survey_cmd.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/survey_view.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/telemetry.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/timestamp.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/tls.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/tool_catalog.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/tool_library.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/tool_taxonomy.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/torque_drag.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/transient.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/tray.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/tutorial.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/updates.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/vibration.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/vpn.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/web/reader.html +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/well3d.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/well_assembler.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/well_records.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/well_report.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/well_test_validation.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/wellplan.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/wellpos.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/winident.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/wits0.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/witsml.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/workspace.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/workspaces.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/x25519.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea/xlsx_read.py +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea_program.egg-info/dependency_links.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea_program.egg-info/entry_points.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea_program.egg-info/requires.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/gea_program.egg-info/top_level.txt +0 -0
- {gea_program-0.88.0 → gea_program-0.89.0}/setup.cfg +0 -0
- {gea_program-0.88.0 → gea_program-0.89.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.
|
|
3
|
+
Version: 0.89.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.
|
|
850
|
+
it installed, every release also carries `GEA-Reader-Setup-0.89.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`.
|
|
@@ -1053,6 +1053,26 @@ followed. The thresholds are settings, each changed with its source. On a
|
|
|
1053
1053
|
record still being written an event raises an alert once. The **Drilling
|
|
1054
1054
|
alerts** tab, `gea dysfunction`, `gea help dysfunction`.
|
|
1055
1055
|
|
|
1056
|
+
### Assistant access (MCP)
|
|
1057
|
+
|
|
1058
|
+
The site, readable by an assistant. `gea mcp` is a Model Context Protocol
|
|
1059
|
+
server: a chat program that speaks MCP - Claude Desktop, or any other
|
|
1060
|
+
client - starts it as its own child process and is given the program's
|
|
1061
|
+
pages as tools: the site and its wells, the rig time, the roadmap, the
|
|
1062
|
+
drilling alerts, torque and drag, hydraulics, the fluid balance, the plume,
|
|
1063
|
+
the front and their calibration, frac hits, the alerts, the audit log, the
|
|
1064
|
+
help. Each tool returns what the program itself computes, with its own
|
|
1065
|
+
labels - SIMULATION where it is one, "nothing declared" where nothing is -
|
|
1066
|
+
so the assistant's account of the site is the program's. It is local: no
|
|
1067
|
+
port is opened, the conversation is the child process's standard input and
|
|
1068
|
+
output. It is read-only: no tool declares, attaches, removes, writes a
|
|
1069
|
+
report or changes a setting. It is logged: every call is a line in the
|
|
1070
|
+
workspace. And the site chooses which pages are offered, because what a
|
|
1071
|
+
tool returns goes to whoever runs the model behind the assistant. Both
|
|
1072
|
+
eras of the protocol are spoken: the stateless revision 2026-07-28 and the
|
|
1073
|
+
`initialize` handshake of 2025-11-25 and earlier. The **Assistant access**
|
|
1074
|
+
tab (one button adds it to Claude Desktop), `gea mcp`, `gea help mcp`.
|
|
1075
|
+
|
|
1056
1076
|
### Plan vs actual and the survey tools
|
|
1057
1077
|
|
|
1058
1078
|
Each well against its directional plan: at every survey station, how far
|
|
@@ -1717,7 +1737,7 @@ attaches the zips to the GitHub release of that tag.
|
|
|
1717
1737
|
|
|
1718
1738
|
### The Windows installer
|
|
1719
1739
|
|
|
1720
|
-
Every release also carries `GEA-Program-Setup-0.
|
|
1740
|
+
Every release also carries `GEA-Program-Setup-0.89.0.exe` (for 0.89.0): the
|
|
1721
1741
|
same Windows kit installed like any Windows program, for the signed-in user
|
|
1722
1742
|
alone and with no administrator rights (`%LOCALAPPDATA%\Programs\GEA-Program`).
|
|
1723
1743
|
It asks for the site workspace (an existing one such as `C:\site` is used as
|
|
@@ -1736,7 +1756,7 @@ it, removes the program and leaves the workspace. Silent, for a site's
|
|
|
1736
1756
|
software deployment:
|
|
1737
1757
|
|
|
1738
1758
|
```
|
|
1739
|
-
GEA-Program-Setup-0.
|
|
1759
|
+
GEA-Program-Setup-0.89.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
|
|
1740
1760
|
```
|
|
1741
1761
|
|
|
1742
1762
|
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.
|
|
811
|
+
it installed, every release also carries `GEA-Reader-Setup-0.89.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`.
|
|
@@ -1014,6 +1014,26 @@ followed. The thresholds are settings, each changed with its source. On a
|
|
|
1014
1014
|
record still being written an event raises an alert once. The **Drilling
|
|
1015
1015
|
alerts** tab, `gea dysfunction`, `gea help dysfunction`.
|
|
1016
1016
|
|
|
1017
|
+
### Assistant access (MCP)
|
|
1018
|
+
|
|
1019
|
+
The site, readable by an assistant. `gea mcp` is a Model Context Protocol
|
|
1020
|
+
server: a chat program that speaks MCP - Claude Desktop, or any other
|
|
1021
|
+
client - starts it as its own child process and is given the program's
|
|
1022
|
+
pages as tools: the site and its wells, the rig time, the roadmap, the
|
|
1023
|
+
drilling alerts, torque and drag, hydraulics, the fluid balance, the plume,
|
|
1024
|
+
the front and their calibration, frac hits, the alerts, the audit log, the
|
|
1025
|
+
help. Each tool returns what the program itself computes, with its own
|
|
1026
|
+
labels - SIMULATION where it is one, "nothing declared" where nothing is -
|
|
1027
|
+
so the assistant's account of the site is the program's. It is local: no
|
|
1028
|
+
port is opened, the conversation is the child process's standard input and
|
|
1029
|
+
output. It is read-only: no tool declares, attaches, removes, writes a
|
|
1030
|
+
report or changes a setting. It is logged: every call is a line in the
|
|
1031
|
+
workspace. And the site chooses which pages are offered, because what a
|
|
1032
|
+
tool returns goes to whoever runs the model behind the assistant. Both
|
|
1033
|
+
eras of the protocol are spoken: the stateless revision 2026-07-28 and the
|
|
1034
|
+
`initialize` handshake of 2025-11-25 and earlier. The **Assistant access**
|
|
1035
|
+
tab (one button adds it to Claude Desktop), `gea mcp`, `gea help mcp`.
|
|
1036
|
+
|
|
1017
1037
|
### Plan vs actual and the survey tools
|
|
1018
1038
|
|
|
1019
1039
|
Each well against its directional plan: at every survey station, how far
|
|
@@ -1678,7 +1698,7 @@ attaches the zips to the GitHub release of that tag.
|
|
|
1678
1698
|
|
|
1679
1699
|
### The Windows installer
|
|
1680
1700
|
|
|
1681
|
-
Every release also carries `GEA-Program-Setup-0.
|
|
1701
|
+
Every release also carries `GEA-Program-Setup-0.89.0.exe` (for 0.89.0): the
|
|
1682
1702
|
same Windows kit installed like any Windows program, for the signed-in user
|
|
1683
1703
|
alone and with no administrator rights (`%LOCALAPPDATA%\Programs\GEA-Program`).
|
|
1684
1704
|
It asks for the site workspace (an existing one such as `C:\site` is used as
|
|
@@ -1697,7 +1717,7 @@ it, removes the program and leaves the workspace. Silent, for a site's
|
|
|
1697
1717
|
software deployment:
|
|
1698
1718
|
|
|
1699
1719
|
```
|
|
1700
|
-
GEA-Program-Setup-0.
|
|
1720
|
+
GEA-Program-Setup-0.89.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
|
|
1701
1721
|
```
|
|
1702
1722
|
|
|
1703
1723
|
The setup is built by Inno Setup 6 from `tools/installer.iss` in the same
|
|
@@ -677,6 +677,21 @@ 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_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
|
+
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
|
+
p_mc.add_argument("--allow", type=str, default=None, help="serve only these tools this run, comma-separated (never more than the site offers)")
|
|
683
|
+
p_mc.add_argument("--status", action="store_true", help="print the tools offered, how to start the server and the last calls, and exit")
|
|
684
|
+
p_mc.add_argument("--config", action="store_true", help="print the entry an MCP client's configuration needs to start this site's server, and exit")
|
|
685
|
+
p_mc.add_argument("--call", type=str, default=None, help="call one tool and print its answer, as an assistant would get it")
|
|
686
|
+
p_mc.add_argument("--well", type=str, default=None, help="--call: the well, by name or id")
|
|
687
|
+
p_mc.add_argument("--topic", type=str, default=None, help="--call help: the topic")
|
|
688
|
+
p_mc.add_argument("--json", action="store_true", help="--call: the page as JSON instead of its text")
|
|
689
|
+
p_mc.add_argument("--offer", type=str, default=None, help="settings: the tools the site offers, comma-separated (all: every tool)")
|
|
690
|
+
p_mc.add_argument("--max-chars", type=int, default=None, help="settings: the most characters one answer carries (default 40000)")
|
|
691
|
+
p_mc.add_argument("--source", type=str, default="", help="settings: who decided, and on what grounds")
|
|
692
|
+
p_mc.add_argument("--add-to-claude-desktop", action="store_true", help="add this site's server to Claude Desktop's configuration on this computer, keeping every other entry and a dated copy of the file")
|
|
693
|
+
p_mc.add_argument("--remove-from-claude-desktop", action="store_true", help="take it out again")
|
|
694
|
+
p_mc.add_argument("--actor", type=str, default="cli")
|
|
680
695
|
p_al = sub.add_parser("alerts", help="the program's alerts: earthquakes near operating wells and the protocol levels they reach, the earthquake watch going quiet, components due for service, penetrator checks outside their ratings, dossiers the workspace no longer matches")
|
|
681
696
|
p_al.add_argument("--workspace", type=str, required=True)
|
|
682
697
|
p_al.add_argument("--check", action="store_true", help="check the motors, penetrators and dossiers now, sending what began or cleared through the notification rules")
|
|
@@ -3560,6 +3575,50 @@ def main(argv=None) -> int:
|
|
|
3560
3575
|
for v in f_["versions"][: (50 if a.family else 3)]:
|
|
3561
3576
|
print(f" {v['utc']} {v.get('report_id') or ''} reports/{v['dir']}")
|
|
3562
3577
|
return 0
|
|
3578
|
+
elif a.cmd == "mcp":
|
|
3579
|
+
import json as _json
|
|
3580
|
+
from . import mcp_server as _MC
|
|
3581
|
+
from .workspace import Workspace, WorkspaceError
|
|
3582
|
+
allow_ = [t_.strip() for t_ in a.allow.split(",") if t_.strip()] if a.allow else None
|
|
3583
|
+
if not a.workspace:
|
|
3584
|
+
r = _MC.selftest()
|
|
3585
|
+
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']}")
|
|
3586
|
+
return 0 if r["ok"] else 1
|
|
3587
|
+
try:
|
|
3588
|
+
ws = Workspace(a.workspace)
|
|
3589
|
+
except WorkspaceError as e:
|
|
3590
|
+
print(f"mcp: {e}", file=sys.stderr) # the error stream: standard output is the protocol's
|
|
3591
|
+
return 2
|
|
3592
|
+
if not (a.status or a.config or a.call or a.offer or a.max_chars is not None or a.add_to_claude_desktop or a.remove_from_claude_desktop):
|
|
3593
|
+
return _MC.serve(ws, allow=allow_) # the server: nothing but protocol messages on standard output
|
|
3594
|
+
from .cli import _safe_stdout
|
|
3595
|
+
_safe_stdout()
|
|
3596
|
+
try:
|
|
3597
|
+
if a.offer or a.max_chars is not None:
|
|
3598
|
+
st_ = _MC.set_settings(ws, a.actor, (list(_MC.NAMES) if a.offer and a.offer.strip().lower() == "all" else a.offer), a.max_chars, a.source)
|
|
3599
|
+
print(f"offered: {', '.join(_MC.offered(ws))}; an answer carries {st_['max_chars']:,} characters at most")
|
|
3600
|
+
if a.add_to_claude_desktop or a.remove_from_claude_desktop:
|
|
3601
|
+
r = _MC.install_claude_desktop(ws, a.actor, remove=a.remove_from_claude_desktop)
|
|
3602
|
+
for d_ in r["done"]:
|
|
3603
|
+
print(f"{'taken out of' if r['removed'] else 'added to'} {d_['path']}" + (f" (as it was: {d_['backup']})" if d_["backup"] else "") + " - quit Claude Desktop and start it again")
|
|
3604
|
+
for d_ in r["skipped"]:
|
|
3605
|
+
print(f"not changed: {d_['path']} - {d_['why']}")
|
|
3606
|
+
if a.config:
|
|
3607
|
+
print(_json.dumps(_MC.client_config(ws.path, allow_), indent=2))
|
|
3608
|
+
if a.call:
|
|
3609
|
+
if a.call not in _MC.offered(ws, allow_):
|
|
3610
|
+
raise SystemExit(f"mcp: no tool {a.call!r} is offered; offered: {', '.join(_MC.offered(ws, allow_))}")
|
|
3611
|
+
args_ = {k: v for k, v in (("well", a.well), ("topic", a.topic)) if v is not None}
|
|
3612
|
+
if a.json:
|
|
3613
|
+
args_["json"] = True
|
|
3614
|
+
r = _MC.call_tool(ws, a.call, args_, _MC.settings(ws)["max_chars"])
|
|
3615
|
+
print(r["text"])
|
|
3616
|
+
return 1 if r["is_error"] else 0
|
|
3617
|
+
if a.status:
|
|
3618
|
+
print(_MC.text(_MC.page(ws)))
|
|
3619
|
+
except (_MC.ToolError, WorkspaceError, OSError) as e:
|
|
3620
|
+
raise SystemExit(f"mcp: {e.args[0] if e.args else e}")
|
|
3621
|
+
return 0
|
|
3563
3622
|
elif a.cmd == "alerts":
|
|
3564
3623
|
import json as _json
|
|
3565
3624
|
from . import alerts as _AL
|
|
@@ -18725,6 +18725,235 @@ def section_eg_dysfunction(tmp: str) -> None:
|
|
|
18725
18725
|
"with its charts and the three alert names on the Alarms tab, the help pages, the README and lesson 13" + (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
|
|
18726
18726
|
|
|
18727
18727
|
|
|
18728
|
+
def section_eh_mcp(tmp: str) -> None:
|
|
18729
|
+
"""Section EH - assistant access: the MCP server's self-test (a client of each era of the protocol against a
|
|
18730
|
+
labelled site); the tool definitions; a workspace read through every tool with every file hashed before and after
|
|
18731
|
+
and the network refused (read-only, local, and the same text as the page's own); the server as a real child process
|
|
18732
|
+
on its standard streams in both eras, with a withheld tool, a run started with fewer tools, the access log; the
|
|
18733
|
+
configuration entry and an assistant's configuration file; the routes, the tab, the command, the help, the IT
|
|
18734
|
+
statement, the README and the lesson."""
|
|
18735
|
+
import hashlib
|
|
18736
|
+
import http.cookiejar
|
|
18737
|
+
import socket as _socket
|
|
18738
|
+
import subprocess as _sp
|
|
18739
|
+
import urllib.error
|
|
18740
|
+
import urllib.request
|
|
18741
|
+
from . import __version__ as _ver
|
|
18742
|
+
from . import dysfunction as DY
|
|
18743
|
+
from . import helplib as H
|
|
18744
|
+
from . import mcp_server as MC
|
|
18745
|
+
from . import rig_state as RS
|
|
18746
|
+
from . import roadmap as RM
|
|
18747
|
+
from . import tutorial as TU
|
|
18748
|
+
from .service import Service, Users
|
|
18749
|
+
from .workspace import Workspace
|
|
18750
|
+
pkg = Path(__file__).parent
|
|
18751
|
+
d = Path(tmp, "eh"); d.mkdir()
|
|
18752
|
+
env = {**os.environ, "PYTHONPATH": str(pkg.parent) + os.pathsep + os.environ.get("PYTHONPATH", "")}
|
|
18753
|
+
# -- EH1 the protocol and the tools -----------------------------------------------------------------------------------
|
|
18754
|
+
st = MC.selftest()
|
|
18755
|
+
defs = [MC.tool_definition(n_) for n_ in MC.NAMES]
|
|
18756
|
+
fake = d / "py"; fake.mkdir(); (fake / "pythonw.exe").write_text(""); (fake / "python.exe").write_text("")
|
|
18757
|
+
real_exe = sys.executable
|
|
18758
|
+
try:
|
|
18759
|
+
sys.executable = str(fake / "pythonw.exe")
|
|
18760
|
+
lc = MC.launch_command(str(d / "site"), ["site", "help"])
|
|
18761
|
+
finally:
|
|
18762
|
+
sys.executable = real_exe
|
|
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
|
+
c1 = {
|
|
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
|
|
18767
|
+
and d_["inputSchema"]["type"] == "object" and d_["inputSchema"]["additionalProperties"] is False and d_["title"] for d_ in defs)
|
|
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
|
+
and not [n_ for n_ in MC.NAMES if any(w_ in n_ for w_ in ("write", "set", "declare", "attach", "remove", "delete", "run"))],
|
|
18770
|
+
"versions": MC.SUPPORTED[0] == "2026-07-28" and set(MC.LEGACY) == {"2025-11-25", "2025-06-18", "2025-03-26", "2024-11-05"} and MC.E_VERSION == -32022,
|
|
18771
|
+
"launch": lc["command"] == str(fake / "python.exe") and lc["args"][:4] == ["-m", "gea", "mcp", "--workspace"] and lc["args"][-2:] == ["--allow", "site,help"]
|
|
18772
|
+
and MC.launch_command(str(d / "site"))["command"] == sys.executable and isinstance(MC.claude_desktop_paths(), list) and MC.claude_desktop_paths()[0].endswith("claude_desktop_config.json"),
|
|
18773
|
+
"plain": plain == {"a": 1.5, "b": [3, None], "c": "(an array of 4 values, left out)", "d": [1, "x"]},
|
|
18774
|
+
}
|
|
18775
|
+
failed1 = [k_ for k_, v in c1.items() if not v]
|
|
18776
|
+
ok(not failed1,
|
|
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, "
|
|
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
|
+
"one; a page as plain JSON with the working arrays left out" + (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
|
|
18781
|
+
|
|
18782
|
+
# -- EH2 a workspace read through every tool: read-only, local, the page's own text ------------------------------------
|
|
18783
|
+
wsp = str(d / "ws"); ws = Workspace.create(wsp, "Pad EH", actor="tester")
|
|
18784
|
+
DY.write_edr(DY.synthetic_record(True, stands=16), str(d / "rig.csv"))
|
|
18785
|
+
wid = ws.add_well_file(str(d / "rig.csv"), display="RIG-1", actor="tester")["id"]
|
|
18786
|
+
DY.write_edr(DY.synthetic_record(False, seed=5, stands=16), str(d / "rig2.csv"))
|
|
18787
|
+
ws.add_well_file(str(d / "rig2.csv"), display="RIG-2", actor="tester")
|
|
18788
|
+
MC.call_tool(ws, "rig_time", {}) # the chart caches, as opening the tab would build them
|
|
18789
|
+
|
|
18790
|
+
def snapshot():
|
|
18791
|
+
out = {}
|
|
18792
|
+
for r_, _, fs in os.walk(wsp):
|
|
18793
|
+
for f_ in fs:
|
|
18794
|
+
p_ = os.path.join(r_, f_)
|
|
18795
|
+
with open(p_, "rb") as fh:
|
|
18796
|
+
out[os.path.relpath(p_, wsp)] = hashlib.sha256(fh.read()).hexdigest()
|
|
18797
|
+
return out
|
|
18798
|
+
before = snapshot()
|
|
18799
|
+
tried = []
|
|
18800
|
+
real_connect = _socket.socket.connect
|
|
18801
|
+
|
|
18802
|
+
def no_network(self, *a_, **k_):
|
|
18803
|
+
tried.append(a_)
|
|
18804
|
+
raise OSError("no network in this check")
|
|
18805
|
+
_socket.socket.connect = no_network
|
|
18806
|
+
try:
|
|
18807
|
+
answers = {n_: MC.call_tool(ws, n_, {}) for n_ in MC.NAMES}
|
|
18808
|
+
as_json = {n_: MC.call_tool(ws, n_, {"json": True}, 400000) for n_ in MC.NAMES if n_ != "help"}
|
|
18809
|
+
one = MC.call_tool(ws, "well", {"well": "rig-1"})
|
|
18810
|
+
named = MC.call_tool(ws, "roadmap", {"well": "RIG-2"})
|
|
18811
|
+
finally:
|
|
18812
|
+
_socket.socket.connect = real_connect
|
|
18813
|
+
after = snapshot()
|
|
18814
|
+
changed = sorted(k_ for k_ in set(before) | set(after) if before.get(k_) != after.get(k_))
|
|
18815
|
+
parsed = {}
|
|
18816
|
+
for n_, r_ in as_json.items():
|
|
18817
|
+
try:
|
|
18818
|
+
parsed[n_] = json.loads(r_["text"])
|
|
18819
|
+
except ValueError:
|
|
18820
|
+
parsed[n_] = None
|
|
18821
|
+
# the server as a child process, on its standard streams
|
|
18822
|
+
def child(lines, extra=()):
|
|
18823
|
+
pr = _sp.run([sys.executable, "-m", "gea", "mcp", "--workspace", wsp, *extra], input=b"".join(json.dumps(m_).encode() + b"\n" for m_ in lines), capture_output=True, env=env, cwd=str(d), timeout=300)
|
|
18824
|
+
return pr.returncode, [json.loads(l_) for l_ in pr.stdout.split(b"\n") if l_], pr.stderr.decode("utf-8", "replace")
|
|
18825
|
+
meta = {MC.K_VERSION: "2026-07-28", MC.K_CLIENT: {"name": "gate-modern", "version": "1"}, "io.modelcontextprotocol/clientCapabilities": {}}
|
|
18826
|
+
rc_o, out_o, err_o = child([{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2025-11-25", "capabilities": {}, "clientInfo": {"name": "gate-legacy", "version": "1"}}},
|
|
18827
|
+
{"jsonrpc": "2.0", "method": "notifications/initialized"}, {"jsonrpc": "2.0", "id": 2, "method": "tools/list"},
|
|
18828
|
+
{"jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": {"name": "rig_time", "arguments": {}}},
|
|
18829
|
+
{"jsonrpc": "2.0", "id": 4, "method": "tools/call", "params": {"name": "drilling_alerts", "arguments": {}}}])
|
|
18830
|
+
rc_m, out_m, err_m = child([{"jsonrpc": "2.0", "id": "p", "method": "server/discover", "params": {"_meta": meta}}, {"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {"_meta": meta}},
|
|
18831
|
+
{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "site", "arguments": {}, "_meta": meta}},
|
|
18832
|
+
{"jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": {"name": "site", "arguments": {}, "_meta": {**meta, MC.K_VERSION: "2099-01-01"}}}])
|
|
18833
|
+
kept = MC.set_settings(ws, "tester", tools=[n_ for n_ in MC.NAMES if n_ != "audit"], max_chars=3000, source="site manager (gate): no audit log to assistants")
|
|
18834
|
+
rc_w, out_w, _ = child([{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}, {"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "audit"}},
|
|
18835
|
+
{"jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": {"name": "help", "arguments": {"topic": "mcp"}}}])
|
|
18836
|
+
rc_a, out_a, _ = child([{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}, {"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "rig_time"}}], ("--allow", "site,audit"))
|
|
18837
|
+
rc_x = _sp.run([sys.executable, "-m", "gea", "mcp", "--workspace", str(d / "nowhere")], input=b"", capture_output=True, env=env, cwd=str(d), timeout=120)
|
|
18838
|
+
log = MC.access_log(ws, 100)
|
|
18839
|
+
errs = {}
|
|
18840
|
+
for name, kw in (("tool", {"tools": ["site", "wipe"]}), ("chars", {"max_chars": 10}), ("number", {"max_chars": "lots"})):
|
|
18841
|
+
try:
|
|
18842
|
+
MC.set_settings(ws, "tester", **kw); errs[name] = ""
|
|
18843
|
+
except MC.ToolError as e:
|
|
18844
|
+
errs[name] = str(e)
|
|
18845
|
+
MC.set_settings(ws, "tester", tools=list(MC.NAMES), max_chars=40000)
|
|
18846
|
+
audit = Path(ws.audit_path).read_text(encoding="utf-8")
|
|
18847
|
+
c2 = {
|
|
18848
|
+
"read_only": changed == [] and len(before) > 20,
|
|
18849
|
+
"local": tried == [],
|
|
18850
|
+
"answers": all(not r_["is_error"] for n_, r_ in answers.items() if n_ != "well") and answers["well"]["is_error"] and "name the well" in answers["well"]["text"]
|
|
18851
|
+
and not one["is_error"] and json.loads(one["text"])["id"] == wid and not named["is_error"] and "RIG-2 at" in named["text"],
|
|
18852
|
+
"same_text": answers["rig_time"]["text"] == RS.text(RS.page(ws)) and answers["roadmap"]["text"] == RM.text(RM.page(ws)) and answers["drilling_alerts"]["text"] == DY.text(DY.page(ws))
|
|
18853
|
+
and "SIMULATION" in answers["pressure_plume"]["text"].splitlines()[0] and "RIG-1" in answers["site"]["text"] and _ver in answers["site"]["text"],
|
|
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
|
+
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"]
|
|
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
|
+
"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
|
+
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
|
+
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
|
|
18862
|
+
and out_w[1]["error"]["code"] == -32602 and "[cut at 3,000 of" in out_w[2]["result"]["content"][0]["text"],
|
|
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
|
+
"no_workspace": rc_x.returncode == 2 and rc_x.stdout == b"" and b"not a workspace" in rc_x.stderr,
|
|
18865
|
+
"log": [r_["tool"] for r_ in reversed(log)] == ["rig_time", "drilling_alerts", "site", "audit", "help", "rig_time"]
|
|
18866
|
+
and sum(1 for r_ in log if r_.get("turned_away") == "withheld") == 2 and any((r_.get("client") or {}).get("name") == "gate-legacy" for r_ in log)
|
|
18867
|
+
and any((r_.get("client") or {}).get("name") == "gate-modern" for r_ in log) and any(r_.get("truncated") for r_ in log) and all("utc" in r_ and "chars" in r_ for r_ in log),
|
|
18868
|
+
"settings": "no tool named wipe" in errs["tool"] and "between" in errs["chars"] and "number" in errs["number"] and "mcp.settings" in audit and "no audit log to assistants" in audit
|
|
18869
|
+
and MC.settings(ws)["tools"] is None,
|
|
18870
|
+
}
|
|
18871
|
+
failed2 = [k_ for k_, v in c2.items() if not v]
|
|
18872
|
+
ok(not failed2,
|
|
18873
|
+
"EH2 a site read through every tool with every file in the workspace hashed before and after and the network refused: no file changed, nothing tried to connect; every tool answers (the one "
|
|
18874
|
+
"that needs a well says so, and reads it by name in any case); the rig time, the roadmap and the drilling alerts return the very text their own pages print, the plume says SIMULATION in its "
|
|
18875
|
+
"first line; every page also as JSON without the working arrays. The server as a child process on its standard streams: a client of 2025-11-25 through its handshake and a client of "
|
|
18876
|
+
"2026-07-28 statelessly, nothing on standard output but one message a line, a clean exit when the input closes; a withheld tool not listed and not callable, a long answer cut and saying so; "
|
|
18877
|
+
"a run started with fewer tools offering fewer and never one the site withholds; a folder that is no workspace an error on the error stream and nothing on the output; six lines in the "
|
|
18878
|
+
"access log with who asked; the choice of tools in the audit log" + (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
|
|
18879
|
+
|
|
18880
|
+
# -- EH3 the routes, the command, the tab, the help ---------------------------------------------------------------------
|
|
18881
|
+
Users(str(Path(wsp, "users.json"))).add("v", "viewer-pass-1", "viewer"); Users(str(Path(wsp, "users.json"))).add("op", "op-pass-123", "operator"); Users(str(Path(wsp, "users.json"))).add("ad", "admin-pass-12", "admin")
|
|
18882
|
+
cfgp = d / "Claude" / "claude_desktop_config.json"; cfgp.parent.mkdir()
|
|
18883
|
+
cfgp.write_text(json.dumps({"mcpServers": {"files": {"command": "npx", "args": ["-y", "x"]}}, "globalShortcut": "Ctrl+Space"}), encoding="utf-8")
|
|
18884
|
+
real_paths = MC.claude_desktop_paths
|
|
18885
|
+
MC.claude_desktop_paths = lambda: [str(cfgp)] # never the real one: this check must not touch an assistant installed on the computer that runs it
|
|
18886
|
+
svc = Service(wsp, port=0, scheduler=False).start()
|
|
18887
|
+
base_url = svc.url.rstrip("/")
|
|
18888
|
+
|
|
18889
|
+
def opener(name, pw_):
|
|
18890
|
+
o = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
|
|
18891
|
+
rq = urllib.request.Request(base_url + "/api/login", method="POST", data=json.dumps({"name": name, "password": pw_}).encode())
|
|
18892
|
+
rq.add_header("Content-Type", "application/json"); rq.add_header("X-GEA-Action", "1"); o.open(rq, timeout=30)
|
|
18893
|
+
return o
|
|
18894
|
+
|
|
18895
|
+
def call(o, method, path, body=None):
|
|
18896
|
+
rq = urllib.request.Request(base_url + path, method=method, data=(json.dumps(body).encode() if body is not None else None))
|
|
18897
|
+
if method == "POST":
|
|
18898
|
+
rq.add_header("Content-Type", "application/json"); rq.add_header("X-GEA-Action", "1")
|
|
18899
|
+
try:
|
|
18900
|
+
with o.open(rq, timeout=300) as rr_:
|
|
18901
|
+
return rr_.status, json.loads(rr_.read())
|
|
18902
|
+
except urllib.error.HTTPError as e:
|
|
18903
|
+
return e.code, json.loads(e.read())
|
|
18904
|
+
try:
|
|
18905
|
+
V, O, A = opener("v", "viewer-pass-1"), opener("op", "op-pass-123"), opener("ad", "admin-pass-12")
|
|
18906
|
+
s_vg, vg = call(V, "GET", "/api/mcp")
|
|
18907
|
+
s_vs, _ = call(V, "POST", "/api/mcp/settings", {"tools": ["site"]})
|
|
18908
|
+
s_os, os_ = call(O, "POST", "/api/mcp/settings", {"tools": ["site", "roadmap", "help"], "max_chars": "20000", "source": "operator (api)"})
|
|
18909
|
+
s_bs, _ = call(O, "POST", "/api/mcp/settings", {"tools": ["site", "format_disk"]})
|
|
18910
|
+
s_oc, _ = call(O, "POST", "/api/mcp/claude-desktop", {})
|
|
18911
|
+
s_ac, ac = call(A, "POST", "/api/mcp/claude-desktop", {})
|
|
18912
|
+
cfg_added = json.loads(cfgp.read_text(encoding="utf-8"))
|
|
18913
|
+
s_g2, g2 = call(V, "GET", "/api/mcp")
|
|
18914
|
+
s_ar, ar = call(A, "POST", "/api/mcp/claude-desktop", {"remove": True})
|
|
18915
|
+
cfg_removed = json.loads(cfgp.read_text(encoding="utf-8"))
|
|
18916
|
+
s_oa, _ = call(O, "POST", "/api/mcp/settings", {"tools": list(MC.NAMES), "max_chars": "40000"})
|
|
18917
|
+
finally:
|
|
18918
|
+
svc.stop()
|
|
18919
|
+
MC.claude_desktop_paths = real_paths
|
|
18920
|
+
run = lambda *a_: _sp.run([sys.executable, "-m", "gea", "mcp", "--workspace", wsp, *a_], capture_output=True, text=True, env=env, cwd=str(d), timeout=300)
|
|
18921
|
+
cli_s, cli_c, cli_k, cli_j = run("--status"), run("--config"), run("--call", "roadmap", "--well", "RIG-2"), run("--call", "site", "--json")
|
|
18922
|
+
cli_u, cli_o, cli_b, cli_a = run("--call", "format_disk"), run("--offer", "site,rig_time,help", "--source", "cli (gate)"), run("--offer", "site,format_disk"), run("--offer", "all")
|
|
18923
|
+
page_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
|
|
18924
|
+
readme = (pkg.parent / "README.md").read_text(encoding="utf-8") if (pkg.parent / "README.md").is_file() else ""
|
|
18925
|
+
lesson = (pkg / "help" / "tutorial" / "20-admin.md").read_text(encoding="utf-8")
|
|
18926
|
+
its = (pkg / "help" / "IT_SECURITY.md").read_text(encoding="utf-8")
|
|
18927
|
+
backups = sorted(p_.name for p_ in cfgp.parent.iterdir() if ".before-gea-" in p_.name)
|
|
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
|
|
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
|
+
and s_bs == 400 and s_oa == 200,
|
|
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"]}
|
|
18933
|
+
and cfg_added["mcpServers"]["gea"]["args"] == ["-m", "gea", "mcp", "--workspace", os.path.abspath(wsp)] and s_g2 == 200 and g2["claude_desktop"]["installed"]
|
|
18934
|
+
and s_ar == 200 and ar["removed"] and "gea" not in cfg_removed["mcpServers"] and "files" in cfg_removed["mcpServers"] and len(backups) >= 1 and "mcp.claude_desktop" in Path(ws.audit_path).read_text(encoding="utf-8"),
|
|
18935
|
+
"cli": cli_s.returncode == 0 and "Assistant access (MCP)" in cli_s.stdout and "offered site" in cli_s.stdout and cli_c.returncode == 0
|
|
18936
|
+
and json.loads(cli_c.stdout)["mcpServers"]["gea"]["command"] == sys.executable and cli_k.returncode == 0 and "Drilling roadmap" in cli_k.stdout and "RIG-2 at" in cli_k.stdout
|
|
18937
|
+
and cli_j.returncode == 0 and json.loads(cli_j.stdout)["site"] == "Pad EH" and cli_u.returncode != 0 and "no tool" in cli_u.stderr and cli_o.returncode == 0
|
|
18938
|
+
and "offered: site, rig_time, help" in cli_o.stdout and cli_b.returncode != 0 and "no tool named format_disk" in cli_b.stderr and cli_a.returncode == 0 and "audit" in cli_a.stdout,
|
|
18939
|
+
"page": all(x in page_src for x in ("VIEWS.mcp", "['#/mcp', 'Assistant access']", "/api/mcp/settings", "/api/mcp/claude-desktop", "help('mcp')", "Add to Claude Desktop",
|
|
18940
|
+
"The server is on this computer; the assistant usually is not.")),
|
|
18941
|
+
"help": not H.check("mcp") and H.VIEW_TOPIC.get("mcp") == "mcp" and any(t_ == "mcp" for t_, _, _ in H.INDEX)
|
|
18942
|
+
and all(x in (H.page("mcp") or "") for x in ("gea mcp --workspace C:\\site --status", "2026-07-28", "server/discover", "records/mcp_access.jsonl", "may leave the site", "not verified"))
|
|
18943
|
+
and all(f"`{n_}`" in (H.page("mcp") or "") for n_ in MC.NAMES),
|
|
18944
|
+
"it_readme_lesson": "Assistant access (MCP)" in its and "opens no port" in its and "leaves the computer" in its
|
|
18945
|
+
and its == ((pkg.parent / "docs" / "IT_SECURITY.md").read_text(encoding="utf-8") if (pkg.parent / "docs" / "IT_SECURITY.md").is_file() else its)
|
|
18946
|
+
and (not readme or ("### Assistant access (MCP)" in readme and "`gea mcp`" in readme)) and "**Assistant access**" in lesson and "mcp" in lesson.split("Help:")[-1] and not TU.check("admin"),
|
|
18947
|
+
}
|
|
18948
|
+
failed3 = [k_ for k_, v in c3.items() if not v]
|
|
18949
|
+
ok(not failed3,
|
|
18950
|
+
"EH3 on the API (anyone reads what is offered, the entry and the log; only an operator changes the choice, and a tool that does not exist is 400), adding the site to an assistant's "
|
|
18951
|
+
"configuration file - a stand-in for Claude Desktop's, never the real one - is an administrator's (an operator is 403): its other server and its own settings kept, a dated copy left, "
|
|
18952
|
+
"the page then showing it set, and taken out again; the command (the status, the entry, one tool's answer for a named well and as JSON, a tool that does not exist stopped, the choice kept "
|
|
18953
|
+
"and put back); the Assistant access tab with its warning; the help page naming every tool; the IT statement in both copies, the README and lesson 20"
|
|
18954
|
+
+ (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
|
|
18955
|
+
|
|
18956
|
+
|
|
18728
18957
|
def main() -> int:
|
|
18729
18958
|
print("GEA-Program - ACCEPTANCE SUITE (the product gate)")
|
|
18730
18959
|
# a handle a job subprocess still holds at the end must not turn a finished gate into a traceback on Windows:
|
|
@@ -18865,6 +19094,7 @@ def main() -> int:
|
|
|
18865
19094
|
section_ee_calibration(tmp)
|
|
18866
19095
|
section_ef_roadmap(tmp)
|
|
18867
19096
|
section_eg_dysfunction(tmp)
|
|
19097
|
+
section_eh_mcp(tmp)
|
|
18868
19098
|
if _FAILS:
|
|
18869
19099
|
print(f"[ACCEPTANCE] {len(_FAILS)} FAILURES ({_PASS} passed):")
|
|
18870
19100
|
for f in _FAILS:
|
|
@@ -199,6 +199,20 @@ declared extras.
|
|
|
199
199
|
give them - a position, not a coordinate: the plan's azimuth and the
|
|
200
200
|
heel are in the rig PC's config, no surface location is.
|
|
201
201
|
|
|
202
|
+
- **Assistant access (MCP)**: off until a person turns it on, and then it
|
|
203
|
+
opens no port. `gea mcp` is a child process of the assistant program
|
|
204
|
+
that starts it, speaking JSON on its standard input and output; it has
|
|
205
|
+
the rights of the Windows user who runs that program and of nobody
|
|
206
|
+
else. Its tools read pages; none writes a record, a declaration, a
|
|
207
|
+
report or a setting, and each declares itself read-only. Which tools are
|
|
208
|
+
offered is the site's choice (`records\mcp.json`, changed by an operator,
|
|
209
|
+
in the audit log); a withheld tool is not listed and cannot be called.
|
|
210
|
+
Every call is a line in `records\mcp_access.jsonl`. **What a tool returns
|
|
211
|
+
leaves the computer**: it becomes part of the assistant's conversation
|
|
212
|
+
and goes to whoever runs the model. Adding the server to Claude Desktop
|
|
213
|
+
is an administrator's action; it writes one entry into that program's
|
|
214
|
+
configuration file and keeps a copy of the file as it was.
|
|
215
|
+
|
|
202
216
|
## What it records
|
|
203
217
|
|
|
204
218
|
Every action - by a person through the page, by a scheduled job, by the
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> A program on the rig PC that reads the rig's own feed and the pre-drill model, places the bit in the layer with a position filter, and, every 30 ft, recommends in the driller's units what to do next - a policy trained by reinforcement learning in a physics twin of the lateral - with the driller's answer, every command, and the records pulled into GEA.
|
|
4
4
|
|
|
5
|
-
**The command**: on the rig PC, `GEA-Driller-0.
|
|
5
|
+
**The command**: on the rig PC, `GEA-Driller-0.89.0.tar.gz` from the release (or the kit's `installers` folder, fetched on the Audit / Update tab): unpack it and run `sudo sh install.sh` on Linux or `install.cmd` on Windows, once; edit its config - the EDR's WITS0 feed (`tcp`, the host and port; `serial`, the COM port), the pre-drill model (the target layer's top TVD at the heel, its thickness and dip, the gamma in, above and below, the deep-resistivity tool, the heel's MD and TVD), the tool's cap, the limits - and restart it. The driller's screen is at port 8790 of the rig PC: `http://192.168.1.60:8790/live`. It shows the section with the model's layer window, the hole drilled through it and - since 0.78.0 - the **position filter**'s band: where the layer is from the readings, as a geosteerer places it (a particle filter over the layer's offset from the model, its dip error and its thickness, moved every decision and kept to the guesses that explain the gamma and the deep-resistivity distance), with the probability the bit is in the layer, above or below it and the distance to the top and the base with its spread, sixty feet ahead; the agent reads the same estimate, and so does the textbook driller it is judged against. Then the recommendation in words - *Build +1.5°/100 ft (toolface up, 25% steering); 25 klb WOB, 120 rpm, 500 gpm* - with its reasons (what the deep-resistivity tool says, the gamma against the model's values, the model's bracket, the limits) and the confidence of each choice, the rig's numbers against the limits, and **Accept**, **Reject** or **Did something else…** with the operator's name. In GEA: the **Drill string** tab's card **GEA Driller** - the rig PC's address and the well, **Pull**: the records come in checked against their hashes, and the table says how many decisions, accepted, rejected, done otherwise, the hole under advice, the armed sections and the commands. **Open the driller's screen** opens the rig PC's screen from its address. Before there is a rig PC: **Start the twin as the rig** runs the driller's program on this computer with a scene drilling itself under the agent - **Open its screen** is the driller's screen with the twin behind it, labelled SIMULATION - and **Pull from it** brings its records in; **Stop it** closes them. **Shadow a drilled well** (since 0.79.0): a well of this workspace with a drilling-recorder export is replayed through the advisor - every 30 ft the agent sees what the rig had shown to that point and nothing past it, and its recommendation is set beside what the record did next: the build actually made over the following 90 ft, the weight, speed and flow used, and at each stretch the gamma marks as out of the layer, whether the advisor called the way back at the first reading. The report, **SHADOW MODE**, is under the well's reports with a drawing of the lateral against the layer; the layer model is read off the well's own gamma in hindsight and says so - and grades how well it fits the well (good, fair, poor: a well steered to a rock that is not the low gamma reads poor, and the agent's calls against a poor model mean little) - unless the site's pre-drill model is given: a file `wells\Well-30636033\driller\model.json` with the config's `model` block (the target layer's top TVD at the heel, its thickness and dip, the gamma in, above and below, the heel's MD and TVD) is used whenever it is there (`gea workspace --path C:\site --action driller-shadow --well Well-30636033`). The export is read on this computer and nothing of it leaves it. Agreement with the driller says the two would have done alike, not that either was right. **The third dimension** (since 0.80.0): the lateral has an azimuth. The config's model carries the plan's azimuth (`plan_azimuth_deg`; empty, the first survey's at the heel is taken), the layer's dip across the plan line (`cross_dip_deg`, positive deepening to the right), the corridor the hole may run in to the right and left of the plan line (`corridor_ft`, the lease line and the offset wells) and where the heel sits across it (`heel_offset_ft`); the feed's surveys and the continuous azimuth (WITS item 0832, or the config's mapping) place the bit by minimum curvature along the plan, right of its line and in depth, and the screen draws the plan view - the corridor as a band, the hole against the plan line - under the section. The recommendation gains the aim - where to point the azimuth, along the plan or 4° left or right of it, and the turn that asks from where the hole points: *Build +1.5°/100 ft and aim 4° right of the plan (azimuth 44.0°), turning right 2.0°/100 ft (toolface 53°, 42% steering)* - with the build and the turn held together inside the DLS limit, and **Did something else…** takes the aim, or the turn made instead; the position filter carries the cross dip and reads it only when the hole moves across the plan line, leaving the model's value standing until then. In the twin the layer is a surface, the faults have a strike, the tool walks, and a hole that leaves the corridor by 150 ft is lost; the agent is judged on the hole in the corridor as well as in the layer (`gea-driller evaluate` prints both). Shadow mode reads the record's `azimuth_deg` column when it has one and sets the turn the advisor would have asked beside the turn the record made; without it the record's turns are not judged, and the report says so. **The vibration index from the feed** (since 0.81.0): a rig without a downhole vibration tool left the agent blind to the stick-slip and the whirl it was trained to ease, and the closed loop's vibration limit could never trip. Now the rig PC reads an index off the surface channels every EDR sends: over the last minute (`rig.vibration_window_s`), the surface torque's RMS about its mean as a fraction of the mean - the measure the Drill string page calls the oscillation index - times root two for the amplitude, and the same of the weight on bit and the hook load; stick-slip is the torque amplitude over 0.4, lateral vibration the weight amplitude over 0.2 (the twin's scale, where 1.2 is the limit), and the index is the larger. The downhole tool's item (WITS 0830) is taken instead whenever it comes, and every decision records which it read: the tile on the screen says *downhole tool* or *from surface data, stick-slip*, the reasons say *vibration 1.35 derived from the surface data (stick-slip, the surface torque swinging ±54%) over the limit 1.2*, and the limit disarms the loop on either. A surface proxy, labelled; on the twin as the rig it tracks the twin's own index within a few hundredths. The lateral file GEA writes for shadow mode carries, per foot, the surface channels' mean and RMS over the seconds of that foot (`torque_mean`, `torque_rms`, `wob_mean`, `wob_rms`, `hkld_mean`, `hkld_rms`, `rpm_mean`, `rpm_rms`, `spp_mean`, `spp_rms`), the replay reads the index off them for every decision, and the report says how often it stood over the limit and how often the advisor asked for less weight or more speed there than the record used; a record without torque or weight statistics says so and the advisor sees none. **The bar and the ceiling** (since 0.82.0): the agent is judged between two drillers on the same held-out scenes. The textbook driller is the bar - what a careful directional driller and geosteerer do by the book from the same observation the agent gets and nothing more: aim at the middle of the layer as the filter places it, steer back hard when the filter says the bit is out, lean away from a boundary the gamma's trend is running at, the rated weight in a calm hole in the layer and not while the hole fills, over the vibration limit lighter and faster first and heavier and slower when that did not quiet it, circulate at 40% of a bed, ream a balled bit, hold the plan line; it has a driller's memory of its own last decisions and none of the twin's secret. The oracle is the ceiling - the same driller told the twin's own layer at the bit and 120 ft ahead of it, which no policy can beat because it sees what no tool measures. `gea-driller evaluate` prints the three rows and how far the agent stands from the bar toward the ceiling; the self-test refuses a policy that does not beat the textbook, and the gate holds it under the oracle. The figures are a simulation's, labelled; a stronger textbook lowers the agent's standing without changing the agent, and that is the point of it. Over a cellular modem the rig PC joins GEA-VPN as a member of kind `driller` and GEA pulls from `http://10.77.0.4:8790`. The closed loop: `closed_loop.allowed` in the rig PC's config puts the switch on its screen; an operator arms it by name for one section of at most 500 ft (**Arm for this section**), every decision then goes to the downlink as a command, and the loop disarms itself on a stale feed, a crossed limit, the section's end or **Disarm now** - and this version's only downlink is the null one, which keeps every command on record and sends none, because no vendor's downlink protocol ships with it. From a terminal: `gea workspace --path C:\site --action driller-pull --box http://192.168.1.60:8790 --well SWD-1`; on the rig PC `gea-driller sim --seed 7 --pace 3 --port 8790`, `gea-driller evaluate --scenes 20`, `gea-driller train --seconds 600 --out policy.json`, `gea-driller selftest`.
|
|
6
6
|
|
|
7
7
|
**What it writes**: on the rig PC, `decisions.jsonl` (every observation, recommendation, confidence, reasons and answer), `commands.jsonl` (every arming, command and disarming with its reason) and `surveys.csv`, each with a `.sha256` beside it, and `manifest.json`. In GEA, `wells\SWD-1\driller\` holds the same files as pulled, `manifest.json` and `last_pull.json` with the summary; the audit lines `driller.pull`, `driller.sim_start`, `driller.sim_stop`. The twin as the rig writes under `field\sim-driller\data`.
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> GEA-Program-Setup: the program installed for you like any Windows program - a window of its own, an icon in the notification area, Start-menu and desktop shortcuts, an Add/Remove Programs entry, upgrades in place - with no administrator rights and the site's data left where it is.
|
|
4
4
|
|
|
5
|
-
**The command**: download the setup from the release on GitHub (`GEA-Program-Setup-0.
|
|
5
|
+
**The command**: download the setup from the release on GitHub (`GEA-Program-Setup-0.89.0.exe` for this version) and run it. It installs for you alone, under `%LOCALAPPDATA%\Programs\GEA-Program`, and asks for the site workspace - the folder that holds the wells, reports, records, accounts and keys. An existing one such as `C:\site` is used exactly as it is, its name included; for a new one (by default `%LOCALAPPDATA%\GEA-Program\site`) it also asks the site's name, which heads every report, and makes the workspace with it (left empty, the workspace is named after its folder; an administrator renames the site in Administration's site settings). Then the Start menu's **GEA-Program** (and the desktop shortcut) starts the control panel when it is not running and opens it in a window of its own. A newer setup installs over the older one: it stops the control panel, replaces the program, keeps the workspace and the choices made before. For a site's software deployment: `GEA-Program-Setup-0.89.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"` (`/SITENAME` names a workspace the setup makes; one that exists keeps its own name). From a terminal: `gea launch` does what the shortcut does, `gea launch --selftest` says what it would do, `gea tray --selftest` checks the icon.
|
|
6
6
|
|
|
7
7
|
**The window**: Microsoft Edge's app window (`msedge --app=`: the control panel with no tabs and no address bar, its own button on the taskbar, which shows the program's derrick and pins as GEA-Program, not as Edge), with a browser profile of its own (`%LOCALAPPDATA%\GEA-Program\window`, no extensions; the first time, Edge may say it signed that profile in to your Microsoft account - Got it), else Google Chrome's, else a tab in the default browser. Where the browser keeps no cookies (its settings or a policy block them), the sign-in page says so and the control panel holds the sign-in itself, in the window's address, until the window is closed. The control panel itself runs with no window of its own: `gea supervise` keeps it running in the background, starts it again when it asks for a restart, and writes everything it would have shown in a console - the start, the sign-ins, the jobs, a stop and why - to `records\console.log` in the workspace. No PowerShell or console window opens. The kit's `start-dashboard.cmd` still runs it in a console window, for a site that wants to watch it there.
|
|
8
8
|
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
**The number to check**: Add/Remove Programs lists GEA-Program with the version you installed; `gea doctor --workspace C:\site` ends with `nothing blocks serving`; the Start menu's **Verify GEA-Program** runs the acceptance gate from the installation and ends with `[ACCEPTANCE] OK - N checks passed`. The release's build installs, upgrades and uninstalls the setup silently before it is published, with the control panel running, and checks the workspace untouched afterwards.
|
|
20
20
|
|
|
21
|
-
**Signed**: when the publisher's code-signing certificate is configured for the build, the setup is signed with it (Authenticode, timestamped) and Windows names the publisher; until then it ships unsigned and Windows SmartScreen says "unknown publisher" (More info, then Run anyway). The build's provenance holds either way: `gh attestation verify GEA-Program-Setup-0.
|
|
21
|
+
**Signed**: when the publisher's code-signing certificate is configured for the build, the setup is signed with it (Authenticode, timestamped) and Windows names the publisher; until then it ships unsigned and Windows SmartScreen says "unknown publisher" (More info, then Run anyway). The build's provenance holds either way: `gh attestation verify GEA-Program-Setup-0.89.0.exe -R Daniel8Murphy0007/GEA-Program`. The uninstaller the setup leaves behind is Inno Setup's own and is not signed separately.
|
|
22
22
|
|
|
23
23
|
**What this page will not call a measurement**: the icon's running or stopped is whether the control panel's port answers on this computer, read every three seconds - not whether every patch, job or report behind it is healthy (Home and the Verification page say that).
|
|
24
24
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Assistant access (MCP)
|
|
2
|
+
|
|
3
|
+
> The site, readable by an assistant. A chat program that speaks the Model Context Protocol can be given this program as a tool box: it starts `gea mcp` as its own child process, asks what tools there are, and calls them. Each tool is one of this program's pages - the rig time, the roadmap, the drilling alerts, the fluid balance - read out as the text the command line prints, so what the assistant says about the site is what the program says. It is local (it listens on no port), read-only (no tool declares, attaches, removes, writes or sets anything) and logged (every call is a line in the workspace). What a tool returns goes into the assistant's conversation, and so to whoever runs the model behind it: offering a tool is deciding that its page may leave the site.
|
|
4
|
+
|
|
5
|
+
**The command**: the **Assistant access** tab. **Add to Claude Desktop** (an administrator) writes one entry, `gea`, into Claude Desktop's own configuration file on this computer, keeps every other entry and leaves a dated copy of the file as it was; then quit Claude Desktop completely and start it again, and the tools are under its connectors. **Take it out of Claude Desktop** removes the entry the same way. For any other MCP client, **Copy** the entry shown and paste it into that client's configuration. **The tools** table is the choice of what an assistant may read: untick a page that must not leave the site and **Keep** (an operator), with who decided and on what grounds; a tool not offered is not listed to the assistant and cannot be called. **The access log** shows the last calls. From a terminal: `gea mcp --workspace C:\site` is the server itself - it waits on its standard input and is what the assistant runs, not something to start by hand; `gea mcp --workspace C:\site --status` prints the tools offered, how to start it and the last calls; `gea mcp --workspace C:\site --config` prints the entry for a client's configuration; `gea mcp --workspace C:\site --call roadmap` prints one tool's answer as an assistant would get it (`--well` names a well, `--json` asks for the page as JSON); `gea mcp --workspace C:\site --offer site,rig_time,roadmap,drilling_alerts,help --source "site manager, 2026-11-13: drilling pages only"` keeps the choice (`--offer all` offers every tool again); `gea mcp --workspace C:\site --add-to-claude-desktop` and `--remove-from-claude-desktop` do what the buttons do; `gea mcp` alone runs the self-test.
|
|
6
|
+
|
|
7
|
+
**What it writes**: `records/mcp_access.jsonl` - a line a call: the time, the tool, its arguments, the client as it names itself, whether it answered, how many characters and how long, and a call for a tool that is withheld or does not exist as turned away (the file is set aside as `.1` when it passes 5 MB). `records/mcp.json` when the choice of tools or the limit is changed (audit line `mcp.settings`). Claude Desktop's `claude_desktop_config.json` and a copy `claude_desktop_config.json.before-gea-<time>` beside it, only when the button or the command is used (audit line `mcp.claude_desktop`). Nothing else: no tool writes a record, a declaration, a report or a setting. Reading a page for the first time may build that well's chart cache, as opening its tab would.
|
|
8
|
+
|
|
9
|
+
**The tools**: `site` (the wells), `well` (one well as declared), `rig_time`, `drill_string`, `roadmap`, `drilling_alerts`, `torque_drag`, `hydraulics`, `pore_pressure`, `casing`, `collision`, `plan_vs_actual`, `frac_hits`, `fluid_balance`, `pressure_plume`, `fluid_front`, `calibration` (the kept result; it runs nothing), `decline`, `invoice_check`, `seismicity`, `alerts`, `audit` and `help`. Those that read a well take `well`, by name or id; `alerts` and `audit` take `n`; `help` takes `topic`; every tool but `help` takes `json` for the page as the program's own structure instead of its text. An answer longer than the limit (40,000 characters unless changed) is cut and says so. Each tool declares itself read-only to the client, which is the client's cue not to ask for confirmation on every call - and is true.
|
|
10
|
+
|
|
11
|
+
**The protocol**: JSON-RPC 2.0, one message a line, on the standard input and output of the process the client starts; anything the program would otherwise print goes to the error stream. Two eras are spoken, chosen by how the client opens. A client of revision 2026-07-28 sends each request with its protocol version in `_meta` and is answered statelessly, every result carrying `resultType`, with `server/discover` for the versions and capabilities; a version it does not speak is answered with error -32022 and the versions it does. A client of 2025-11-25, 2025-06-18, 2025-03-26 or 2024-11-05 opens with `initialize` and is answered with the handshake of the revision it names. Tools only: no resources, no prompts, and nothing is ever asked of the client. An unknown or withheld tool is error -32602; a well that does not exist or a page that cannot be computed is an ordinary answer marked as an error, with what to do about it.
|
|
12
|
+
|
|
13
|
+
**The number to check**: one tool's answer against its tab - `gea mcp --workspace C:\site --call rig_time` beside the Rig time tab: the same figures, because it is the same function; and the access log's count of calls against what was asked of the assistant. On the self-test `gea mcp` runs, a client of each era opens against a labelled site, lists the tools and calls them; a line that is not JSON, a tool that does not exist, a well that does not and an argument a tool does not take are each answered as what they are; a withheld tool is not listed and cannot be called; and the entry is added to a configuration file with its other entries kept, and taken out again.
|
|
14
|
+
|
|
15
|
+
**What this page will not call a measurement**: privacy - the server is local, the assistant is not, and nothing here controls what the assistant's maker does with what it is given; the assistant's answer - a tool returns the program's page, and what the assistant then writes about it is the assistant's, to be checked against the page; who is asking - a client names itself, and that name is logged as given, not verified; a SIMULATION - the plume, the front and the calibration are projections here exactly as they are on their tabs, and say so in their first line; silence - a page that says nothing is declared has no figures, and an assistant that supplies some did not get them from here.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
**The command**: Reports tab -> Signed dossiers -> **Download GEA Reader for your clients**, or `gea reader --workspace C:\site --out C:\site\GEA-Reader.html`. Send the file once, by any channel (email, a USB stick, the client's portal); send the site's key fingerprint separately - by phone, email or in the contract - as for any dossier. The client opens GEA-Reader.html, drops a dossier on it (or chooses it), and reads the verdict: **Valid** (signed with the site's key, or with a newer key the site's key handed over to), **Valid, but signed by a key you were not given**, or **Not valid** with the reason. Below the verdict: each check, the signer's fingerprint, the key hand-overs, and every file the dossier holds - a report opens in the page as it was signed, a PDF in the browser's own viewer, a table or a log as text, and any file can be saved. A dossier that lists source records by hash without carrying them lets the client choose their copies and checks each against its hash.
|
|
6
6
|
|
|
7
|
-
**The program**: for a client who wants it installed, **GEA-Reader-Setup-0.
|
|
7
|
+
**The program**: for a client who wants it installed, **GEA-Reader-Setup-0.89.0.exe** on the release page installs GEA Reader as a Windows program of its own, for the signed-in user, with no administrator rights and nothing of GEA-Program: GEA Reader in the Start menu and on the desktop with its own icon (a white page with a green seal, on blue) and its own taskbar button, and **Check with GEA Reader** on the right-click menu of .zip files (on Windows 11, under Show more options), which opens the dossier at once. It opens the same page in Microsoft Edge's app window with a browser profile of its own (`%LOCALAPPDATA%\GEA-Reader\window`), so a fingerprint the client saves - **Remember this fingerprint**, with whose it is - stays on that computer, and every later dossier signed with that key reads **Valid** with the name the client gave it. `GEA-Reader-portable-0.89.0.zip` is the same program to unzip and run (`GEA-Reader.cmd`). `python\python.exe -m gea_reader --selftest`, in the installed folder, checks the page, the icon, the taskbar identity and the hand-over of a dossier without opening a window.
|
|
8
8
|
|
|
9
9
|
**What it writes**: the one file, GEA-Reader.html (about 40 KB): the checks, written in the page's own script - Ed25519 (RFC 8032) in its own arithmetic, SHA-256 from the browser - and, when made from a workspace, the site's name and the fingerprints of every key it has signed with (the current one and each retired one from the key history: public halves only; the signing key never leaves `keys\`). The audit log records each download (`reader.download`) and each `gea reader` (`reader.write`) with the fingerprints the reader carried. The reader page writes nothing on the client's computer but the fingerprints a client saves (in the browser's storage for the page): it reads the zip it is given, in memory, and a saved copy goes where the client's browser saves downloads. The installed program also writes the page it opens to `%LOCALAPPDATA%\GEA-Reader\page` (with the dossier inside it when one was right-clicked; removed ten minutes later) and its right-click entry under the user's own registry keys, removed with the program.
|
|
10
10
|
|