gea-program 0.2.0__tar.gz → 0.3.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.2.0/gea_program.egg-info → gea_program-0.3.0}/PKG-INFO +111 -29
- gea_program-0.3.0/README.md +232 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/__init__.py +1 -1
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/__main__.py +181 -4
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/acceptance_tests.py +403 -3
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/alarm_engine.py +43 -1
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/client_reports.py +4 -3
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/dashboard.py +8 -3
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/fat_sat.py +2 -0
- gea_program-0.3.0/gea/jobs.py +297 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/live_ports.py +56 -4
- gea_program-0.3.0/gea/patches.py +462 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/sbom.py +1 -1
- gea_program-0.3.0/gea/service.py +992 -0
- gea_program-0.3.0/gea/web/app.html +388 -0
- gea_program-0.3.0/gea/wits0.py +397 -0
- gea_program-0.3.0/gea/witsml.py +402 -0
- gea_program-0.3.0/gea/workspace.py +358 -0
- {gea_program-0.2.0 → gea_program-0.3.0/gea_program.egg-info}/PKG-INFO +111 -29
- {gea_program-0.2.0 → gea_program-0.3.0}/gea_program.egg-info/SOURCES.txt +7 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea_program.egg-info/requires.txt +4 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/pyproject.toml +4 -3
- gea_program-0.2.0/README.md +0 -153
- {gea_program-0.2.0 → gea_program-0.3.0}/LICENSE +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/accuracy_statement.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/bench.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/blind_harness.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/case_study.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/med_160_sapropels.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/cli.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/config_versioning.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/correlation.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/deviation.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/downhole_engine.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/drift_monitor.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/earth_model.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/example_register_map.json +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/follower.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/forward_model.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/gamma.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/gauge_specs.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/gravity_reference.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/inverse_engine.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/matplotlib_demo.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/modbus.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/model_card.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/mqtt_port.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/opcua_port.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/operator_app.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/ports.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/profile_catalog.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/project.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/qt6_downhole_app.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/quartz_hpht_extension.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/reconciler.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/rock_inventory.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/sample_record.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/sample_well_profile.csv +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/segy.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/service_life.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/shell.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/sla_report.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/store_forward.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/strata_join.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/survey_cmd.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/survey_view.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/telemetry.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/tool_library.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/well_assembler.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea/well_test_validation.py +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea_program.egg-info/dependency_links.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea_program.egg-info/entry_points.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/gea_program.egg-info/top_level.txt +0 -0
- {gea_program-0.2.0 → gea_program-0.3.0}/setup.cfg +0 -0
- {gea_program-0.2.0 → gea_program-0.3.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.3.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
|
|
@@ -26,10 +26,13 @@ Provides-Extra: opcua
|
|
|
26
26
|
Requires-Dist: asyncua>=1.0; extra == "opcua"
|
|
27
27
|
Provides-Extra: mqtt
|
|
28
28
|
Requires-Dist: paho-mqtt>=2.0; extra == "mqtt"
|
|
29
|
+
Provides-Extra: serial
|
|
30
|
+
Requires-Dist: pyserial>=3.5; extra == "serial"
|
|
29
31
|
Provides-Extra: live
|
|
30
32
|
Requires-Dist: asyncua>=1.0; extra == "live"
|
|
31
33
|
Requires-Dist: paho-mqtt>=2.0; extra == "live"
|
|
32
34
|
Requires-Dist: pymodbus>=3.0; extra == "live"
|
|
35
|
+
Requires-Dist: pyserial>=3.5; extra == "live"
|
|
33
36
|
Provides-Extra: xls
|
|
34
37
|
Requires-Dist: xlrd>=2.0; extra == "xls"
|
|
35
38
|
Dynamic: license-file
|
|
@@ -69,14 +72,23 @@ reaches a client document. Nothing unmeasured is ever reported as met.
|
|
|
69
72
|
rate-controlled replay, duplicate suppression, per-record latency.
|
|
70
73
|
- **Configuration versioning, SBOM, monthly SLA, FAT/SAT**
|
|
71
74
|
(`config_versioning.py`, `sbom.py`, `sla_report.py`, `fat_sat.py`).
|
|
72
|
-
- **Live protocol ports** (`live_ports.py`, `
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
timestamp, ingest timestamp and quality
|
|
77
|
-
|
|
75
|
+
- **Live protocol ports** (`live_ports.py`, `wits0.py`, `witsml.py`, `opcua_port.py`,
|
|
76
|
+
`mqtt_port.py`, `modbus.py`): WITS Level 0 from the drill floor (TCP connect,
|
|
77
|
+
TCP listen, serial), WITSML 1.4.1 stores (read-only, polled), OPC UA (read and
|
|
78
|
+
subscribe), MQTT (number, JSON, Sparkplug B), Modbus TCP; every message becomes
|
|
79
|
+
a measurement record with its source timestamp, ingest timestamp and quality
|
|
80
|
+
flag; units declared on the map are converted; every session can be recorded
|
|
81
|
+
and replayed; in-package simulators for WITS0 and WITSML. See *Live data*.
|
|
82
|
+
- **The patch panel** (`patches.py`): supervised connections that stay up -
|
|
83
|
+
reconnect with backoff, heartbeat, latency, per-tag last values, records to
|
|
84
|
+
disk as they arrive, several sources folded into one stream by priority.
|
|
78
85
|
- **Dashboard** (`dashboard.py`): tiles, well ranking, alarm wall, drill-down to
|
|
79
86
|
every report; light and dark; status is always an icon with a label.
|
|
87
|
+
- **The dashboard as the door** (`workspace.py`, `jobs.py`, `service.py`,
|
|
88
|
+
`web/app.html`): one folder per site that the client owns; a standard-library
|
|
89
|
+
HTTP service that serves the page, the reports and a JSON API; every action
|
|
90
|
+
a job running the program's own command with its log kept; accounts with
|
|
91
|
+
roles; an audit log with the hash of every input. See *Serving the dashboard*.
|
|
80
92
|
- **Survey track** (`earth_model.py`, `strata_join.py`, `inverse_engine.py`,
|
|
81
93
|
`blind_harness.py`, `rock_inventory.py`, `forward_model.py`, ...): strata
|
|
82
94
|
property estimation over a public co-located library, blind-scored on every run.
|
|
@@ -91,9 +103,11 @@ gea dashboard --catalog-well volve_f12_f14_production_excerpt:15/9-F-12:10000 --
|
|
|
91
103
|
gea client-report --report accuracy --out client_report
|
|
92
104
|
gea model-cards --out model_cards
|
|
93
105
|
gea sbom --out sbom
|
|
94
|
-
gea accept # the product gate (
|
|
106
|
+
gea accept # the product gate (199 checks)
|
|
95
107
|
gea guide # the click-by-click tester guide (docs/TESTER_GUIDE.md)
|
|
96
108
|
gea gui # the desktop window (pip install "gea-program[desktop]")
|
|
109
|
+
gea workspace --path C:\site --action init --name "Pad 3" # a site folder
|
|
110
|
+
gea serve --workspace C:\site # the dashboard as the door: http://127.0.0.1:8765/
|
|
97
111
|
```
|
|
98
112
|
|
|
99
113
|
`gea` is the front door (`gea/cli.py`); every other subcommand passes through to
|
|
@@ -101,40 +115,108 @@ gea gui # the desktop window (pip install "gea-program[de
|
|
|
101
115
|
|
|
102
116
|
## Live data
|
|
103
117
|
|
|
104
|
-
The engine reads live data through
|
|
105
|
-
|
|
106
|
-
is declined), and
|
|
118
|
+
The engine reads live data through five protocol ports. All are **read-only**,
|
|
119
|
+
all map only what the site declares (a tag map the client owns; an empty map
|
|
120
|
+
is declined), and all write every received message to a JSON-lines recording
|
|
107
121
|
that `--replay` turns back into records without a connection - which is how a
|
|
108
122
|
site session is reproduced offline and how the mapping logic is tested.
|
|
109
123
|
|
|
110
124
|
```
|
|
111
|
-
pip install "gea-program[live]" # asyncua
|
|
112
|
-
gea
|
|
113
|
-
gea
|
|
114
|
-
gea
|
|
115
|
-
gea
|
|
116
|
-
gea
|
|
117
|
-
gea
|
|
118
|
-
gea
|
|
125
|
+
pip install "gea-program[live]" # asyncua, paho-mqtt, pymodbus, pyserial (or one extra at a time)
|
|
126
|
+
gea wits0 --write-example-config wits0.json # drill floor: transport tcp | listen | serial; item codes -> tags, units
|
|
127
|
+
gea wits0-sim --port 5001 # a WITS0 sender to rehearse with (no rig needed)
|
|
128
|
+
gea wits0 --config wits0.json --seconds 60 --record floor/session.jsonl --out floor --stream-csv floor/stream.csv
|
|
129
|
+
gea witsml --write-example-config witsml.json # a WITSML 1.4.1 store: url, uids, mnemonics -> tags; credentials by env name
|
|
130
|
+
gea witsml --config witsml.json --seconds 60 --out store
|
|
131
|
+
gea opcua --write-example-config opcua.json # edit: endpoint, security, credential env names, nodes
|
|
132
|
+
gea opcua --config opcua.json --seconds 60 --record opc/session.jsonl --out opc --stream-csv opc/stream.csv
|
|
133
|
+
gea mqtt --write-example-config mqtt.json # edit: broker, TLS, credential env names, topics
|
|
134
|
+
gea mqtt --config mqtt.json --replay mq/session.jsonl --out mq_replay # no broker needed
|
|
135
|
+
gea ingest --file floor/stream.csv # a stream CSV feeds the historian port like any other
|
|
119
136
|
```
|
|
120
137
|
|
|
121
138
|
| port | transport | quality | timestamps |
|
|
122
139
|
|---|---|---|---|
|
|
123
|
-
| `
|
|
124
|
-
| `
|
|
140
|
+
| `wits0` | WITS Level 0 frames (`&&` ... `!!`, four-digit item codes) over TCP connect, TCP listen or serial; record-01 dictionary built in | numeric GOOD; sentinels (-9999, -999.25) and non-numeric -> GAP with the reason | items 0105/0106 (date, time) when present, else arrival; ingest at arrival |
|
|
141
|
+
| `witsml` | WITSML 1.4.1 SOAP store: GetVersion, GetCap, GetFromStore on one log object, rows newer than the last seen at each poll | numeric GOOD; the store's nullValue and empty fields -> GAP | the index curve of a time log; arrival for a depth log |
|
|
142
|
+
| `opcua` | opc.tcp, read + subscribe; Basic256Sha256 SignAndEncrypt when a certificate and key are given | StatusCode severity bits: Good -> GOOD, Uncertain -> STALE, Bad -> GAP (value withheld) | source timestamp, else server timestamp, else arrival |
|
|
143
|
+
| `mqtt` | MQTT v5 / v3.1.1, TLS optional, QoS per topic; `+`/`#` wildcards | number: GOOD or GAP; JSON: value/time/quality paths; Sparkplug B: `is_null` -> GAP, `Quality` != 192 -> STALE | JSON time path, Sparkplug metric timestamp, else arrival |
|
|
144
|
+
| `modbus_g6` | Modbus TCP, user-supplied register map with a citation | read failures -> GAP | arrival |
|
|
125
145
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
146
|
+
Units: a mapping may declare `unit_in` (what the wire carries) beside `unit`
|
|
147
|
+
(what the tag catalogue uses); known pairs (pressure, temperature, length,
|
|
148
|
+
force, flow, density, torque, volume) are converted before scale and offset,
|
|
149
|
+
and a pair the program cannot convert is declined when the map loads.
|
|
150
|
+
Credentials never sit in a map: the map names the environment variables that
|
|
151
|
+
hold them. The example maps are in `docs/examples/`.
|
|
152
|
+
|
|
153
|
+
**Patches** keep a source connected: a patch names a protocol, its map, the
|
|
154
|
+
well it feeds, a priority and a staleness limit; the service keeps every
|
|
155
|
+
enabled patch up, reconnects with backoff (2 ... 60 s) when the source drops,
|
|
156
|
+
keeps a heartbeat (state, last sample, samples per minute, latency p50/p95,
|
|
157
|
+
reconnects, last error, the last value of every tag), and appends every record
|
|
158
|
+
to `wells/<id>/records/live/patch_<name>_<day>.records.csv`. The refresh folds
|
|
159
|
+
the record files of every patch on a well into one stream (higher priority
|
|
160
|
+
wins a tie) and reports it beside the well; a drill-floor stream with no
|
|
161
|
+
downhole gauge stations gets quality and alarms, and its drift report is
|
|
162
|
+
marked not applicable rather than invented. The Patch panel page adds,
|
|
163
|
+
starts, stops, enables and edits patches and shows their live values.
|
|
164
|
+
|
|
165
|
+
## Serving the dashboard
|
|
166
|
+
|
|
167
|
+
The command line is the engine; the dashboard is the door. A client site is one
|
|
168
|
+
folder, the **workspace**, which the client owns and backs up like any project
|
|
169
|
+
folder:
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
gea workspace --path C:\site --action init --name "Pad 3"
|
|
173
|
+
gea workspace --path C:\site --action add-catalog --entry volve_f12_f14_production_excerpt --well 15/9-F-12 --station-md 10000
|
|
174
|
+
gea workspace --path C:\site --action add-file --file exports\historian.csv --name "Well A"
|
|
175
|
+
gea workspace --path C:\site --action add-live --name "Pad 3 OPC" --port opcua --file opcua.json
|
|
176
|
+
gea workspace --path C:\site --action refresh --month 2026-09 # every report, into C:\site\reports
|
|
177
|
+
gea serve --workspace C:\site # http://127.0.0.1:8765/
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Open the address in a browser. The first visit asks for the first
|
|
181
|
+
administrator's name and password (once); everyone else is added under
|
|
182
|
+
Administration with a role: **viewer** reads everything; **operator** adds
|
|
183
|
+
wells, runs reports and the gate, starts and stops live taps, acknowledges
|
|
184
|
+
alarms and commits configuration; **approver** decides well tests and re-fits;
|
|
185
|
+
**admin** manages users, schedules and rollbacks. Pages: Home (tiles, well
|
|
186
|
+
ranking), Wells (add from a file, the catalogue or a live tag map; each well's
|
|
187
|
+
reports, quality, trends, tests and alarms), Patch panel (supervised sources,
|
|
188
|
+
their state and live values, their maps, live values), Alarms (the wall, acknowledge, definitions), Approvals (one queue),
|
|
189
|
+
Configuration (versioned JSON with history, diff and rollback), Reports
|
|
190
|
+
(generate and open every report), Verification (the acceptance suite, FAT/SAT,
|
|
191
|
+
SBOM and the standalone check from the page), Survey (a LAS file in, a strata
|
|
192
|
+
report out), Jobs (every run with its log), Administration (users, schedule,
|
|
193
|
+
audit log).
|
|
194
|
+
|
|
195
|
+
Every action the page takes is a job: `python -m gea <command>` run by the
|
|
196
|
+
service with its log kept under `jobs/`, so one code path serves the page, the
|
|
197
|
+
terminal and the acceptance gate, and a failed action shows its log instead of
|
|
198
|
+
disappearing. Every action is written to `records/audit.jsonl` with the
|
|
199
|
+
actor's name and the SHA-256 of the inputs it used. The service is written on
|
|
200
|
+
the standard library only (no new dependency, the standalone check still
|
|
201
|
+
passes), listens on the loopback interface by default (`--host 0.0.0.0` for a
|
|
202
|
+
site network, behind the site's TLS proxy), keeps sessions in HttpOnly
|
|
203
|
+
SameSite cookies, and requires the page's own header on every action so a
|
|
204
|
+
foreign form cannot act. Accounts live in `users.json` as salted PBKDF2-SHA256
|
|
205
|
+
hashes; `gea users --workspace C:\site --action add --name ... --role admin`
|
|
206
|
+
adds one from the terminal (the password comes from the `GEA_PASSWORD`
|
|
207
|
+
environment variable, never the command line).
|
|
208
|
+
|
|
209
|
+
The workspace layout: `wells/<id>/source` (the client's files, copied in
|
|
210
|
+
verbatim and hashed), `config/` (the version store), `monitor/` (drift
|
|
211
|
+
evaluations and change logs), `reports/` (the printed dashboard and every
|
|
212
|
+
report), `jobs/` (every run), `records/audit.jsonl`, `users.json`. All of it is
|
|
213
|
+
text: JSON, JSON lines, CSV, Markdown, HTML.
|
|
133
214
|
|
|
134
215
|
## Layout
|
|
135
216
|
|
|
136
217
|
```
|
|
137
|
-
gea/ the package: engines, record layer, reports, monitor, dashboard, cli, shell, acceptance suite
|
|
218
|
+
gea/ the package: engines, record layer, reports, monitor, dashboard, cli, shell, acceptance suite,
|
|
219
|
+
workspace, jobs, service, patches and web/app.html (the served dashboard)
|
|
138
220
|
gea/catalog/ 52 public archive entries, each with a provenance file
|
|
139
221
|
docs/ TESTER_GUIDE.md, REQUIREMENTS_MATRIX.md (the scope-of-work mirror that shaped the reports), examples/ (port configs),
|
|
140
222
|
SESSION_LOG.md (the working record, session by session),
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# GEA-Program
|
|
2
|
+
|
|
3
|
+
Downhole gauge monitoring for production operations: the program takes a well's
|
|
4
|
+
historian data and returns the reports a client engineer reads, in the outline
|
|
5
|
+
and language of a production-operations scope of work.
|
|
6
|
+
|
|
7
|
+
Every number in every report is recomputed from the source data at generation
|
|
8
|
+
time. Reports are gated for vocabulary: the program's internal register never
|
|
9
|
+
reaches a client document. Nothing unmeasured is ever reported as met.
|
|
10
|
+
|
|
11
|
+
## What it does
|
|
12
|
+
|
|
13
|
+
- **Canonical measurement record** (`gea/sample_record.py`): one record shape for
|
|
14
|
+
every sample - tag, UTC timestamp, value, unit, quality flag, the rule and limit
|
|
15
|
+
that fired, source layer, ingest timestamp. Quality rules: RANGE / ROC /
|
|
16
|
+
FLATLINE / SPIKE / STALE / GAP; ranges from the gauge datasheet, cited.
|
|
17
|
+
- **Gauge drift and reconciliation** (`reconciler.py`, `drift_monitor.py`): the
|
|
18
|
+
live pressure series against the well baseline; classification with the
|
|
19
|
+
numbers beside it; scheduled evaluation log; CURRENT / STALE; re-fit change
|
|
20
|
+
log with before/after coefficients; approve -> apply -> re-evaluate; SLA clocks;
|
|
21
|
+
annual re-fit cap.
|
|
22
|
+
- **Accuracy statement** (`accuracy_statement.py`): MAPE with a seeded bootstrap
|
|
23
|
+
90 % CI; the band read at the conservative end of the interval.
|
|
24
|
+
- **Well-test validation** (`well_test_validation.py`): stable-period detection
|
|
25
|
+
with the client-agreed criteria in a file (hashed on every report), reason
|
|
26
|
+
codes naming the failing value, virtual rates, two-level approval trail.
|
|
27
|
+
- **Alarm management** (`alarm_engine.py`): setpoint / deadband / on-delay state
|
|
28
|
+
machine, event log, ISA-18.2-style KPIs printed against their targets.
|
|
29
|
+
- **Model cards** (`model_card.py`): one card per model - inputs with sources,
|
|
30
|
+
settings with basis, calibration data with provenance, recomputed evaluation,
|
|
31
|
+
limitations, re-fit history, component hashes.
|
|
32
|
+
- **Store-and-forward** (`store_forward.py`): 72 h edge buffer, chronological
|
|
33
|
+
rate-controlled replay, duplicate suppression, per-record latency.
|
|
34
|
+
- **Configuration versioning, SBOM, monthly SLA, FAT/SAT**
|
|
35
|
+
(`config_versioning.py`, `sbom.py`, `sla_report.py`, `fat_sat.py`).
|
|
36
|
+
- **Live protocol ports** (`live_ports.py`, `wits0.py`, `witsml.py`, `opcua_port.py`,
|
|
37
|
+
`mqtt_port.py`, `modbus.py`): WITS Level 0 from the drill floor (TCP connect,
|
|
38
|
+
TCP listen, serial), WITSML 1.4.1 stores (read-only, polled), OPC UA (read and
|
|
39
|
+
subscribe), MQTT (number, JSON, Sparkplug B), Modbus TCP; every message becomes
|
|
40
|
+
a measurement record with its source timestamp, ingest timestamp and quality
|
|
41
|
+
flag; units declared on the map are converted; every session can be recorded
|
|
42
|
+
and replayed; in-package simulators for WITS0 and WITSML. See *Live data*.
|
|
43
|
+
- **The patch panel** (`patches.py`): supervised connections that stay up -
|
|
44
|
+
reconnect with backoff, heartbeat, latency, per-tag last values, records to
|
|
45
|
+
disk as they arrive, several sources folded into one stream by priority.
|
|
46
|
+
- **Dashboard** (`dashboard.py`): tiles, well ranking, alarm wall, drill-down to
|
|
47
|
+
every report; light and dark; status is always an icon with a label.
|
|
48
|
+
- **The dashboard as the door** (`workspace.py`, `jobs.py`, `service.py`,
|
|
49
|
+
`web/app.html`): one folder per site that the client owns; a standard-library
|
|
50
|
+
HTTP service that serves the page, the reports and a JSON API; every action
|
|
51
|
+
a job running the program's own command with its log kept; accounts with
|
|
52
|
+
roles; an audit log with the hash of every input. See *Serving the dashboard*.
|
|
53
|
+
- **Survey track** (`earth_model.py`, `strata_join.py`, `inverse_engine.py`,
|
|
54
|
+
`blind_harness.py`, `rock_inventory.py`, `forward_model.py`, ...): strata
|
|
55
|
+
property estimation over a public co-located library, blind-scored on every run.
|
|
56
|
+
|
|
57
|
+
## Quick start
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
pip install -e .
|
|
61
|
+
gea quickstart # a real catalogue well -> its reports -> the dashboard; the KTB strata survey
|
|
62
|
+
gea survey mywell.las # a LAS file in, one strata report out
|
|
63
|
+
gea dashboard --catalog-well volve_f12_f14_production_excerpt:15/9-F-12:10000 --td 10500 --out dashboard
|
|
64
|
+
gea client-report --report accuracy --out client_report
|
|
65
|
+
gea model-cards --out model_cards
|
|
66
|
+
gea sbom --out sbom
|
|
67
|
+
gea accept # the product gate (199 checks)
|
|
68
|
+
gea guide # the click-by-click tester guide (docs/TESTER_GUIDE.md)
|
|
69
|
+
gea gui # the desktop window (pip install "gea-program[desktop]")
|
|
70
|
+
gea workspace --path C:\site --action init --name "Pad 3" # a site folder
|
|
71
|
+
gea serve --workspace C:\site # the dashboard as the door: http://127.0.0.1:8765/
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`gea` is the front door (`gea/cli.py`); every other subcommand passes through to
|
|
75
|
+
`python -m gea`. PATH-proof form: `python -m gea.cli ...`. Open `dashboard/index.html`.
|
|
76
|
+
|
|
77
|
+
## Live data
|
|
78
|
+
|
|
79
|
+
The engine reads live data through five protocol ports. All are **read-only**,
|
|
80
|
+
all map only what the site declares (a tag map the client owns; an empty map
|
|
81
|
+
is declined), and all write every received message to a JSON-lines recording
|
|
82
|
+
that `--replay` turns back into records without a connection - which is how a
|
|
83
|
+
site session is reproduced offline and how the mapping logic is tested.
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
pip install "gea-program[live]" # asyncua, paho-mqtt, pymodbus, pyserial (or one extra at a time)
|
|
87
|
+
gea wits0 --write-example-config wits0.json # drill floor: transport tcp | listen | serial; item codes -> tags, units
|
|
88
|
+
gea wits0-sim --port 5001 # a WITS0 sender to rehearse with (no rig needed)
|
|
89
|
+
gea wits0 --config wits0.json --seconds 60 --record floor/session.jsonl --out floor --stream-csv floor/stream.csv
|
|
90
|
+
gea witsml --write-example-config witsml.json # a WITSML 1.4.1 store: url, uids, mnemonics -> tags; credentials by env name
|
|
91
|
+
gea witsml --config witsml.json --seconds 60 --out store
|
|
92
|
+
gea opcua --write-example-config opcua.json # edit: endpoint, security, credential env names, nodes
|
|
93
|
+
gea opcua --config opcua.json --seconds 60 --record opc/session.jsonl --out opc --stream-csv opc/stream.csv
|
|
94
|
+
gea mqtt --write-example-config mqtt.json # edit: broker, TLS, credential env names, topics
|
|
95
|
+
gea mqtt --config mqtt.json --replay mq/session.jsonl --out mq_replay # no broker needed
|
|
96
|
+
gea ingest --file floor/stream.csv # a stream CSV feeds the historian port like any other
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
| port | transport | quality | timestamps |
|
|
100
|
+
|---|---|---|---|
|
|
101
|
+
| `wits0` | WITS Level 0 frames (`&&` ... `!!`, four-digit item codes) over TCP connect, TCP listen or serial; record-01 dictionary built in | numeric GOOD; sentinels (-9999, -999.25) and non-numeric -> GAP with the reason | items 0105/0106 (date, time) when present, else arrival; ingest at arrival |
|
|
102
|
+
| `witsml` | WITSML 1.4.1 SOAP store: GetVersion, GetCap, GetFromStore on one log object, rows newer than the last seen at each poll | numeric GOOD; the store's nullValue and empty fields -> GAP | the index curve of a time log; arrival for a depth log |
|
|
103
|
+
| `opcua` | opc.tcp, read + subscribe; Basic256Sha256 SignAndEncrypt when a certificate and key are given | StatusCode severity bits: Good -> GOOD, Uncertain -> STALE, Bad -> GAP (value withheld) | source timestamp, else server timestamp, else arrival |
|
|
104
|
+
| `mqtt` | MQTT v5 / v3.1.1, TLS optional, QoS per topic; `+`/`#` wildcards | number: GOOD or GAP; JSON: value/time/quality paths; Sparkplug B: `is_null` -> GAP, `Quality` != 192 -> STALE | JSON time path, Sparkplug metric timestamp, else arrival |
|
|
105
|
+
| `modbus_g6` | Modbus TCP, user-supplied register map with a citation | read failures -> GAP | arrival |
|
|
106
|
+
|
|
107
|
+
Units: a mapping may declare `unit_in` (what the wire carries) beside `unit`
|
|
108
|
+
(what the tag catalogue uses); known pairs (pressure, temperature, length,
|
|
109
|
+
force, flow, density, torque, volume) are converted before scale and offset,
|
|
110
|
+
and a pair the program cannot convert is declined when the map loads.
|
|
111
|
+
Credentials never sit in a map: the map names the environment variables that
|
|
112
|
+
hold them. The example maps are in `docs/examples/`.
|
|
113
|
+
|
|
114
|
+
**Patches** keep a source connected: a patch names a protocol, its map, the
|
|
115
|
+
well it feeds, a priority and a staleness limit; the service keeps every
|
|
116
|
+
enabled patch up, reconnects with backoff (2 ... 60 s) when the source drops,
|
|
117
|
+
keeps a heartbeat (state, last sample, samples per minute, latency p50/p95,
|
|
118
|
+
reconnects, last error, the last value of every tag), and appends every record
|
|
119
|
+
to `wells/<id>/records/live/patch_<name>_<day>.records.csv`. The refresh folds
|
|
120
|
+
the record files of every patch on a well into one stream (higher priority
|
|
121
|
+
wins a tie) and reports it beside the well; a drill-floor stream with no
|
|
122
|
+
downhole gauge stations gets quality and alarms, and its drift report is
|
|
123
|
+
marked not applicable rather than invented. The Patch panel page adds,
|
|
124
|
+
starts, stops, enables and edits patches and shows their live values.
|
|
125
|
+
|
|
126
|
+
## Serving the dashboard
|
|
127
|
+
|
|
128
|
+
The command line is the engine; the dashboard is the door. A client site is one
|
|
129
|
+
folder, the **workspace**, which the client owns and backs up like any project
|
|
130
|
+
folder:
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
gea workspace --path C:\site --action init --name "Pad 3"
|
|
134
|
+
gea workspace --path C:\site --action add-catalog --entry volve_f12_f14_production_excerpt --well 15/9-F-12 --station-md 10000
|
|
135
|
+
gea workspace --path C:\site --action add-file --file exports\historian.csv --name "Well A"
|
|
136
|
+
gea workspace --path C:\site --action add-live --name "Pad 3 OPC" --port opcua --file opcua.json
|
|
137
|
+
gea workspace --path C:\site --action refresh --month 2026-09 # every report, into C:\site\reports
|
|
138
|
+
gea serve --workspace C:\site # http://127.0.0.1:8765/
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Open the address in a browser. The first visit asks for the first
|
|
142
|
+
administrator's name and password (once); everyone else is added under
|
|
143
|
+
Administration with a role: **viewer** reads everything; **operator** adds
|
|
144
|
+
wells, runs reports and the gate, starts and stops live taps, acknowledges
|
|
145
|
+
alarms and commits configuration; **approver** decides well tests and re-fits;
|
|
146
|
+
**admin** manages users, schedules and rollbacks. Pages: Home (tiles, well
|
|
147
|
+
ranking), Wells (add from a file, the catalogue or a live tag map; each well's
|
|
148
|
+
reports, quality, trends, tests and alarms), Patch panel (supervised sources,
|
|
149
|
+
their state and live values, their maps, live values), Alarms (the wall, acknowledge, definitions), Approvals (one queue),
|
|
150
|
+
Configuration (versioned JSON with history, diff and rollback), Reports
|
|
151
|
+
(generate and open every report), Verification (the acceptance suite, FAT/SAT,
|
|
152
|
+
SBOM and the standalone check from the page), Survey (a LAS file in, a strata
|
|
153
|
+
report out), Jobs (every run with its log), Administration (users, schedule,
|
|
154
|
+
audit log).
|
|
155
|
+
|
|
156
|
+
Every action the page takes is a job: `python -m gea <command>` run by the
|
|
157
|
+
service with its log kept under `jobs/`, so one code path serves the page, the
|
|
158
|
+
terminal and the acceptance gate, and a failed action shows its log instead of
|
|
159
|
+
disappearing. Every action is written to `records/audit.jsonl` with the
|
|
160
|
+
actor's name and the SHA-256 of the inputs it used. The service is written on
|
|
161
|
+
the standard library only (no new dependency, the standalone check still
|
|
162
|
+
passes), listens on the loopback interface by default (`--host 0.0.0.0` for a
|
|
163
|
+
site network, behind the site's TLS proxy), keeps sessions in HttpOnly
|
|
164
|
+
SameSite cookies, and requires the page's own header on every action so a
|
|
165
|
+
foreign form cannot act. Accounts live in `users.json` as salted PBKDF2-SHA256
|
|
166
|
+
hashes; `gea users --workspace C:\site --action add --name ... --role admin`
|
|
167
|
+
adds one from the terminal (the password comes from the `GEA_PASSWORD`
|
|
168
|
+
environment variable, never the command line).
|
|
169
|
+
|
|
170
|
+
The workspace layout: `wells/<id>/source` (the client's files, copied in
|
|
171
|
+
verbatim and hashed), `config/` (the version store), `monitor/` (drift
|
|
172
|
+
evaluations and change logs), `reports/` (the printed dashboard and every
|
|
173
|
+
report), `jobs/` (every run), `records/audit.jsonl`, `users.json`. All of it is
|
|
174
|
+
text: JSON, JSON lines, CSV, Markdown, HTML.
|
|
175
|
+
|
|
176
|
+
## Layout
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
gea/ the package: engines, record layer, reports, monitor, dashboard, cli, shell, acceptance suite,
|
|
180
|
+
workspace, jobs, service, patches and web/app.html (the served dashboard)
|
|
181
|
+
gea/catalog/ 52 public archive entries, each with a provenance file
|
|
182
|
+
docs/ TESTER_GUIDE.md, REQUIREMENTS_MATRIX.md (the scope-of-work mirror that shaped the reports), examples/ (port configs),
|
|
183
|
+
SESSION_LOG.md (the working record, session by session),
|
|
184
|
+
commercial/ (pilot proposal, bench readiness, commercial use), HISTORY.md (the ship-by-ship record)
|
|
185
|
+
tools/ standalone_check.py (the self-contained guard: imports, text, metadata; run by ci and ship.ps1)
|
|
186
|
+
CHANGELOG.md per-release summary (a tag ships only with its section); SHIP_LOG.md is written by ship.ps1
|
|
187
|
+
tests/ pytest wrapper around the acceptance suite and the standalone check
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Basis
|
|
191
|
+
|
|
192
|
+
GEA-Program is a self-contained package: every module imports only the
|
|
193
|
+
standard library, numpy, the declared optional extras and the package itself,
|
|
194
|
+
and `tools/standalone_check.py` (run by CI and by `ship.ps1`) fails the build
|
|
195
|
+
if that ever changes or if a tracked file names another program. The physics
|
|
196
|
+
is on standard constants - CODATA 2018 G, standard gravity 9.80665 m/s2, the
|
|
197
|
+
IUGG mean Earth radius - and the rock inventory carries seventeen published
|
|
198
|
+
density anchors and Vp ranges with their citations (Telford, Geldart and
|
|
199
|
+
Sheriff; Schon). Every catalogue entry under `gea/catalog/` has a provenance
|
|
200
|
+
file naming its public source.
|
|
201
|
+
|
|
202
|
+
Two statements the product carries on its own model cards: the gauge aging
|
|
203
|
+
envelope's lower bound is an engineering model with no field validation on
|
|
204
|
+
record, and five of the fourteen back-tested strata quantities are NOT
|
|
205
|
+
ACCEPTABLE at the 95 % target. Both are printed, never claimed otherwise.
|
|
206
|
+
|
|
207
|
+
## Shipping
|
|
208
|
+
|
|
209
|
+
`.\ship.ps1` (PowerShell) gates, commits, tags and pushes in one screen: version in
|
|
210
|
+
`pyproject.toml` must equal `gea.__version__` (`-Bump x.y.z` sets both), the tag must
|
|
211
|
+
not exist anywhere, every version in `SHIP_LOG.md` must have its tag, `python -m gea
|
|
212
|
+
accept` must be green, `SHIP_MESSAGE.txt` must start with the tag; then commit, tag,
|
|
213
|
+
push, and the remote tag must be seen before SHIPPED is printed. `CHANGELOG.md` must carry a
|
|
214
|
+
section headed by the tag, and `tools/standalone_check.py` must report no findings. `-DryRun` runs every
|
|
215
|
+
check and changes nothing; `-NoPush` stops after the local tag.
|
|
216
|
+
|
|
217
|
+
## Publishing to PyPI
|
|
218
|
+
|
|
219
|
+
The name `gea-program` is free on PyPI as of 2026-09-29; a PyPI project is created by
|
|
220
|
+
its first upload, there is nothing to "start" beforehand except the trusted publisher.
|
|
221
|
+
One-time setup, before the first tag is pushed: sign in to PyPI -> your account ->
|
|
222
|
+
Publishing -> "Add a new pending publisher": project name `gea-program`, owner
|
|
223
|
+
`Daniel8Murphy0007`, repository `GEA-Program`, workflow `release-to-pypi.yml`,
|
|
224
|
+
environment `pypi`. Then in GitHub -> Settings -> Environments create `pypi`. From then
|
|
225
|
+
on `.\ship.ps1` pushes the tag and `.github/workflows/release-to-pypi.yml` gates, builds,
|
|
226
|
+
verifies the wheel and publishes; the package page is
|
|
227
|
+
https://pypi.org/project/gea-program/ after the first successful run.
|
|
228
|
+
|
|
229
|
+
## Licence
|
|
230
|
+
|
|
231
|
+
Mozilla Public License 2.0 (MPL-2.0); see `LICENSE`. Every source file carries the MPL-2.0
|
|
232
|
+
header (Exhibit A). Copyright (c) 2026 Daniel T. Murphy.
|