gea-program 0.34.0__tar.gz → 0.35.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.34.0/gea_program.egg-info → gea_program-0.35.0}/PKG-INFO +18 -1
- {gea_program-0.34.0 → gea_program-0.35.0}/README.md +17 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/__init__.py +1 -1
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/__main__.py +60 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/acceptance_tests.py +166 -0
- gea_program-0.35.0/gea/control_room.py +509 -0
- gea_program-0.35.0/gea/help/control-room.md +11 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/helplib.py +2 -1
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/service.py +97 -4
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/web/app.html +181 -5
- {gea_program-0.34.0 → gea_program-0.35.0/gea_program.egg-info}/PKG-INFO +18 -1
- {gea_program-0.34.0 → gea_program-0.35.0}/gea_program.egg-info/SOURCES.txt +2 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/pyproject.toml +1 -1
- {gea_program-0.34.0 → gea_program-0.35.0}/LICENSE +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/accuracy_statement.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/alarm_engine.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/backup.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/bench.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/blind_harness.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/med_160_sapropels.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog_map.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/catalog_register.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/certificates.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/cli.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/client_reports.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/config_versioning.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/conformance.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/correlation.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/dashboard.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/deviation.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/dlis.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/dnp3.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/doctor.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/downhole_engine.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/drift_monitor.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/earth_model.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/edr.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/elevation.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/etp.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/etp12_schemas.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/example_register_map.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/fat_sat.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/files.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/fixtures/README.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/fixtures/comcat_delaware_basin_2026-09.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/fixtures/comcat_youngstown_2011-2012.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/fixtures/ne_110m_coastline.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/follower.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/forward_model.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/friction_priors.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/gamma.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/gauge_aging.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/gauge_specs.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/geodesy.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/gravity_reference.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/hartip.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/TESTER_GUIDE.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/alarms.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/audit-update.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/backup.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/catalog.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/charts.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/conformance.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/data-in.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/dlis.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/doctor.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/drift.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/edr.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/etp.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/field-ports.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/files.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/historian.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/instruments.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/interval.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/map.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/month-end.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/notifications.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/osdu.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/patches.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/ppdm.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/quakeml.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/quality.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/seedlink.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/seismic.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/setup.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/site.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/sites.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/slip.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/soak.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/sra.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/start.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/structure.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/tools.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/transients.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/upkeep.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/vibration.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/help/well-tests.md +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/housekeeping.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/interval.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/inverse_engine.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/jobs.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/live_ports.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/loadtest.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/matplotlib_demo.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/modbus.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/modbus_rtu.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/model_card.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/month_end.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/mqtt_port.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/notify.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/opcua_port.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/operator_app.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/osdu.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/patches.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/permits.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/piwebapi.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/ports.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/ppdm.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/profile_catalog.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/project.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/qt6_downhole_app.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/quakeml.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/reconciler.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/reference/libmseed_steim.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/reference/tool_sources.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/reference/us_outline.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/reference/us_outline.provenance.json +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/rock_inventory.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/sample_record.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/sample_well_profile.csv +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/sbom.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/seedlink.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/segy.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/seismic.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/seismic_array.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/seismic_assoc.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/seismic_detect.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/seismic_film.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/seismic_harmonic.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/seismic_qc.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/seismic_response.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/seismic_signature.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/seismic_track.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/seismic_uncertainty.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/seismic_unlisted.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/sensor_swap.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/series_cache.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/service_life.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/setup_checklist.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/shapefile.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/shell.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/shut_in.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/site_map.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/sla_report.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/slip.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/soak.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/sra.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/store_forward.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/strata_join.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/structure.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/supervisor.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/survey_cmd.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/survey_view.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/telemetry.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/tool_catalog.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/tool_library.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/tool_taxonomy.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/transient.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/vibration.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/well_assembler.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/well_test_validation.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/wits0.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/witsml.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea/workspace.py +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea_program.egg-info/dependency_links.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea_program.egg-info/entry_points.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea_program.egg-info/requires.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/gea_program.egg-info/top_level.txt +0 -0
- {gea_program-0.34.0 → gea_program-0.35.0}/setup.cfg +0 -0
- {gea_program-0.34.0 → gea_program-0.35.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.35.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
|
|
@@ -648,6 +648,23 @@ against it; `gea seedlink --config ... --hello` prints what a server says of
|
|
|
648
648
|
itself; `gea help seedlink`. A TexNet station is served by EarthScope at
|
|
649
649
|
`rtserve.iris.washington.edu:18000`, network `TX`.
|
|
650
650
|
|
|
651
|
+
### The control room
|
|
652
|
+
|
|
653
|
+
The Control room tab opens the wall: a screen read from across the room, one
|
|
654
|
+
tile per well, worst first, each with its state in a shape and a word -
|
|
655
|
+
Serious, Watch, Good, No data - the reasons in plain words, the alarms, the
|
|
656
|
+
gauges, and for a drilling recorder the bottom, the bit, the rate of
|
|
657
|
+
penetration and the hours on bottom at the end of the record. It refreshes
|
|
658
|
+
itself every 30 seconds, says how old its last answer is, and puts a notice
|
|
659
|
+
across the screen when the service stops answering; a recorded well is
|
|
660
|
+
described at the end of its record and never called stale. F is full screen;
|
|
661
|
+
the screen is kept awake where the browser allows it; when the wells do not
|
|
662
|
+
fit, the pages turn, the worst first. The outgoing operator writes the shift
|
|
663
|
+
handover - what is open, what is being watched, what was done - and it stays
|
|
664
|
+
on the wall until the incoming operator acknowledges it; both go in the audit
|
|
665
|
+
log. A wall pass lets a screen show the wall and nothing else with no one's
|
|
666
|
+
account signed in. `gea wall`, `gea handover`, `gea help control-room`.
|
|
667
|
+
|
|
651
668
|
### The site map
|
|
652
669
|
|
|
653
670
|
The Map tab puts everything in the workspace that has a position in one
|
|
@@ -609,6 +609,23 @@ against it; `gea seedlink --config ... --hello` prints what a server says of
|
|
|
609
609
|
itself; `gea help seedlink`. A TexNet station is served by EarthScope at
|
|
610
610
|
`rtserve.iris.washington.edu:18000`, network `TX`.
|
|
611
611
|
|
|
612
|
+
### The control room
|
|
613
|
+
|
|
614
|
+
The Control room tab opens the wall: a screen read from across the room, one
|
|
615
|
+
tile per well, worst first, each with its state in a shape and a word -
|
|
616
|
+
Serious, Watch, Good, No data - the reasons in plain words, the alarms, the
|
|
617
|
+
gauges, and for a drilling recorder the bottom, the bit, the rate of
|
|
618
|
+
penetration and the hours on bottom at the end of the record. It refreshes
|
|
619
|
+
itself every 30 seconds, says how old its last answer is, and puts a notice
|
|
620
|
+
across the screen when the service stops answering; a recorded well is
|
|
621
|
+
described at the end of its record and never called stale. F is full screen;
|
|
622
|
+
the screen is kept awake where the browser allows it; when the wells do not
|
|
623
|
+
fit, the pages turn, the worst first. The outgoing operator writes the shift
|
|
624
|
+
handover - what is open, what is being watched, what was done - and it stays
|
|
625
|
+
on the wall until the incoming operator acknowledges it; both go in the audit
|
|
626
|
+
log. A wall pass lets a screen show the wall and nothing else with no one's
|
|
627
|
+
account signed in. `gea wall`, `gea handover`, `gea help control-room`.
|
|
628
|
+
|
|
612
629
|
### The site map
|
|
613
630
|
|
|
614
631
|
The Map tab puts everything in the workspace that has a position in one
|
|
@@ -475,6 +475,21 @@ def main(argv=None) -> int:
|
|
|
475
475
|
p_ck.add_argument("--note", type=str, default="", help="--confirm: what it was checked against (required)")
|
|
476
476
|
p_ck.add_argument("--actor", type=str, default="cli")
|
|
477
477
|
|
|
478
|
+
p_wl = sub.add_parser("wall", help="the control-room board as text: a line per well, worst first, its state and why (the same board the wall screen shows)")
|
|
479
|
+
p_wl.add_argument("--workspace", type=str, default=None, help="the workspace folder, e.g. C:\\site")
|
|
480
|
+
p_wl.add_argument("--json", action="store_true")
|
|
481
|
+
|
|
482
|
+
p_ho = sub.add_parser("handover", help="the shift handover: list the notes, sign one (--write) or acknowledge one (--ack)")
|
|
483
|
+
p_ho.add_argument("--workspace", type=str, default=None, help="the workspace folder, e.g. C:\\site")
|
|
484
|
+
p_ho.add_argument("--write", action="store_true", help="sign a note: give at least one of --open, --watching, --done")
|
|
485
|
+
p_ho.add_argument("--open", type=str, default="", help="--write: what the next shift must pick up")
|
|
486
|
+
p_ho.add_argument("--watching", type=str, default="", help="--write: what is being watched, and why")
|
|
487
|
+
p_ho.add_argument("--done", type=str, default="", help="--write: what this shift did")
|
|
488
|
+
p_ho.add_argument("--ack", type=str, default=None, help="acknowledge the note with this id (not your own)")
|
|
489
|
+
p_ho.add_argument("--comment", type=str, default="", help="--ack: an optional comment")
|
|
490
|
+
p_ho.add_argument("--actor", type=str, default=None, help="who signs or acknowledges (required with --write and --ack)")
|
|
491
|
+
p_ho.add_argument("--json", action="store_true")
|
|
492
|
+
|
|
478
493
|
p_sv = sub.add_parser("serve", help="serve the dashboard over a workspace: the page, the reports and the JSON API (standard library HTTP)")
|
|
479
494
|
p_sv.add_argument("--workspace", type=str, required=True, help="the workspace folder (gea workspace --action init)")
|
|
480
495
|
p_sv.add_argument("--host", type=str, default="127.0.0.1", help="bind address; 0.0.0.0 exposes it on the site network (put TLS in front)")
|
|
@@ -1922,6 +1937,51 @@ def main(argv=None) -> int:
|
|
|
1922
1937
|
else:
|
|
1923
1938
|
print(_SC.text(r))
|
|
1924
1939
|
return 0 if r["ready"] else 2
|
|
1940
|
+
elif a.cmd in ("wall", "handover"):
|
|
1941
|
+
import json as _json
|
|
1942
|
+
from . import control_room as _CR
|
|
1943
|
+
from .cli import _safe_stdout
|
|
1944
|
+
from .workspace import Workspace, WorkspaceError
|
|
1945
|
+
_safe_stdout()
|
|
1946
|
+
if not a.workspace:
|
|
1947
|
+
raise SystemExit(f"{a.cmd} needs --workspace, e.g. --workspace C:\\site")
|
|
1948
|
+
try:
|
|
1949
|
+
ws = Workspace(a.workspace)
|
|
1950
|
+
except WorkspaceError as e:
|
|
1951
|
+
raise SystemExit(f"{a.cmd}: {e}")
|
|
1952
|
+
if a.cmd == "wall":
|
|
1953
|
+
b = _CR.board(ws)
|
|
1954
|
+
print(_json.dumps(b, indent=1) if a.json else _CR.text(b))
|
|
1955
|
+
return 0
|
|
1956
|
+
try:
|
|
1957
|
+
if a.write:
|
|
1958
|
+
if not a.actor:
|
|
1959
|
+
raise SystemExit("handover --write needs --actor, the name the note is signed with")
|
|
1960
|
+
b = _CR.board(ws)
|
|
1961
|
+
counts = {**b["counts"], "alarms_unacked": sum(((t.get("alarms") or {}).get("unacked") or 0) for t in b["tiles"])}
|
|
1962
|
+
n = _CR.write_note(ws, a.actor, a.open, a.watching, a.done, counts)
|
|
1963
|
+
print(f"handover {n['id']} signed by {n['by']} at {n['utc']}")
|
|
1964
|
+
return 0
|
|
1965
|
+
if a.ack:
|
|
1966
|
+
if not a.actor:
|
|
1967
|
+
raise SystemExit("handover --ack needs --actor, the incoming operator's name")
|
|
1968
|
+
r = _CR.ack_note(ws, a.ack, a.actor, a.comment)
|
|
1969
|
+
print(f"handover {a.ack} acknowledged by {r['by']} at {r['utc']}")
|
|
1970
|
+
return 0
|
|
1971
|
+
except (ValueError, KeyError, PermissionError) as e:
|
|
1972
|
+
raise SystemExit(f"handover: {e.args[0] if e.args else e}")
|
|
1973
|
+
ns = _CR.notes(ws, 0)
|
|
1974
|
+
if a.json:
|
|
1975
|
+
print(_json.dumps(ns, indent=1))
|
|
1976
|
+
elif not ns:
|
|
1977
|
+
print("no handover notes yet")
|
|
1978
|
+
else:
|
|
1979
|
+
for n in ns:
|
|
1980
|
+
print(f"{n['id']} {n['utc']} by {n['by']} " + (f"acknowledged by {n['ack']['by']} at {n['ack']['utc']}" if n.get('ack') else "NOT YET ACKNOWLEDGED"))
|
|
1981
|
+
for k in _CR.NOTE_FIELDS:
|
|
1982
|
+
if n.get(k):
|
|
1983
|
+
print(f" {k}: {n[k]}")
|
|
1984
|
+
return 0
|
|
1925
1985
|
elif a.cmd == "serve":
|
|
1926
1986
|
from .service import Service
|
|
1927
1987
|
from .workspace import WorkspaceError
|
|
@@ -8448,6 +8448,171 @@ def section_cc_site_map(tmp: str) -> None:
|
|
|
8448
8448
|
"bar, the not-placed wells with the way to place them, what is at a click; the help page"
|
|
8449
8449
|
+ (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
|
|
8450
8450
|
|
|
8451
|
+
|
|
8452
|
+
def section_cd_control_room(tmp: str) -> None:
|
|
8453
|
+
"""Section CD - the control room: the wall board judged by its stated rule (a shape and a word for each state, worst
|
|
8454
|
+
first, a recorded well never called stale, a live feed's age measured), the shift handover signed by one operator and
|
|
8455
|
+
acknowledged by another with both in the audit log, wall passes that show the wall and nothing else, the page."""
|
|
8456
|
+
import http.cookiejar
|
|
8457
|
+
import urllib.request
|
|
8458
|
+
import urllib.error
|
|
8459
|
+
from datetime import datetime as _dt, timedelta as _td, timezone as _tz
|
|
8460
|
+
from . import control_room as CR
|
|
8461
|
+
from . import edr as E
|
|
8462
|
+
from . import helplib as H
|
|
8463
|
+
from .workspace import Workspace
|
|
8464
|
+
from .service import Service, Users
|
|
8465
|
+
pkg = Path(__file__).parent
|
|
8466
|
+
d = Path(tmp, "cd"); d.mkdir()
|
|
8467
|
+
|
|
8468
|
+
ev = E.selftest_events(str(d))
|
|
8469
|
+
wsp = str(d / "ws"); ws = Workspace.create(wsp, "Pad 3", actor="tester")
|
|
8470
|
+
wd = ws.add_well_file(ev["path"], display="Drilling well", actor="tester")
|
|
8471
|
+
wa = ws.add_well_file(ev["path"], display="Alarm well", actor="tester")
|
|
8472
|
+
wc = ws.add_well_catalog("volve_f12_f14_production_excerpt", "15/9-F-12", 10000.0, actor="tester")
|
|
8473
|
+
ws.refresh_dashboard(actor="tester")
|
|
8474
|
+
wn = ws.add_well_file(ev["path"], display="New well", actor="tester") # added after the refresh: no reports yet
|
|
8475
|
+
ra = Path(ws.reports_dir, "wells", wa["id"])
|
|
8476
|
+
(ra / "alarm_event_report.json").write_text(json.dumps({"active": [
|
|
8477
|
+
{"alarm_id": "SPP.HH_RANGE", "state": "ACTIVE_UNACKED", "priority": "P2", "tag_id": "SPP"},
|
|
8478
|
+
{"alarm_id": "HKLD.QUALITY", "state": "ACTIVE_ACKED", "priority": "P4", "tag_id": "HKLD"}], "shelved": []}), encoding="utf-8")
|
|
8479
|
+
now = _dt(2026, 10, 15, 12, 0, 0, tzinfo=_tz.utc)
|
|
8480
|
+
iso = lambda s: (now - _td(seconds=s)).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
8481
|
+
feed = lambda age, status="CONNECTED", wid=wn["id"]: [{"name": "p1", "well_id": wid, "status": status, "last_sample_utc": (iso(age) if age is not None else None), "patch": {"stale_after_s": 120.0}}]
|
|
8482
|
+
b0 = CR.board(ws, [], now=now)
|
|
8483
|
+
t0 = {t["well_id"]: t for t in b0["tiles"]}
|
|
8484
|
+
dr = t0[wd["id"]]["drilling"]
|
|
8485
|
+
live = {k: {t["well_id"]: t for t in CR.board(ws, feed(*a), now=now)["tiles"]}[wn["id"]] for k, a in
|
|
8486
|
+
{"fresh": (30,), "late": (400,), "silent": (1000,), "down": (60, "DOWN"), "none": (None,)}.items()}
|
|
8487
|
+
c1 = {
|
|
8488
|
+
"states": t0[wa["id"]]["state"] == "SERIOUS" and t0[wa["id"]]["reasons"][:2] == ["1 unacknowledged P2 alarm(s)", "1 other active alarm(s)"]
|
|
8489
|
+
and t0[wc["id"]]["state"] == "SERIOUS" and "no explanation" in t0[wc["id"]]["reasons"][0]
|
|
8490
|
+
and t0[wd["id"]]["state"] == "GOOD" and t0[wd["id"]]["reasons"] == ["nothing needs attention"]
|
|
8491
|
+
and t0[wn["id"]]["state"] == "NO_DATA",
|
|
8492
|
+
"shape_word": all(t["shape"] == CR.SHAPE[t["state"]] and t["word"] == CR.WORD[t["state"]] for t in b0["tiles"])
|
|
8493
|
+
and len(set(CR.SHAPE.values())) == 4 and len(set(CR.WORD.values())) == 4,
|
|
8494
|
+
"order": [t["state"] for t in b0["tiles"]] == sorted((t["state"] for t in b0["tiles"]), key=CR.STATES.index)
|
|
8495
|
+
and b0["counts"] == {"SERIOUS": 2, "WATCH": 0, "GOOD": 1, "NO_DATA": 1},
|
|
8496
|
+
"recorded": t0[wd["id"]]["live"] is None and t0[wd["id"]]["recorded"]["record_end_utc"] == dr["record_end_utc"]
|
|
8497
|
+
and "never called stale" in b0["rule"],
|
|
8498
|
+
"read_only": not Path(wsp, "handover").exists() and not Path(wsp, "wall").exists(),
|
|
8499
|
+
"drilling": dr["cache"] and dr["td_md_ft"] == 5750.0 and dr["bottom_ft"] == 5750.0 and dr["on_bottom_hours"] is not None
|
|
8500
|
+
and (dr["rop_ft_h"] is not None) == bool(dr["drilling_now"]),
|
|
8501
|
+
"live": live["fresh"]["state"] == "GOOD" and live["late"]["state"] == "WATCH" and "past the 2 min stale limit" in live["late"]["reasons"][0]
|
|
8502
|
+
and live["silent"]["state"] == "SERIOUS" and live["silent"]["reasons"][0].startswith("no live sample for 16 min")
|
|
8503
|
+
and live["down"]["state"] == "SERIOUS" and live["none"]["state"] == "WATCH" and abs(live["fresh"]["live"]["age_s"] - 30) < 1e-6,
|
|
8504
|
+
}
|
|
8505
|
+
failed1 = [k for k, v in c1.items() if not v]
|
|
8506
|
+
ok(not failed1,
|
|
8507
|
+
"CD1 the wall board by its stated rule, read without writing anything: an unacknowledged P2 alarm and a gauge off with no explanation SERIOUS, a well with reports and "
|
|
8508
|
+
"nothing else GOOD, a well with neither reports nor a live sample NO DATA, each state its own shape and word, worst first; a recorded well "
|
|
8509
|
+
"described at the end of its record and never called stale (bottom 5,750 ft, the ROP only while drilling at the end); a live feed's "
|
|
8510
|
+
"measured age against its stale limit - 30 s good, 400 s watch, 1,000 s serious, a patch down serious"
|
|
8511
|
+
+ (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
|
|
8512
|
+
|
|
8513
|
+
users = Users(str(Path(wsp, "users.json")))
|
|
8514
|
+
for n_, r_ in (("adm", "admin"), ("op1", "operator"), ("op2", "operator"), ("v", "viewer")):
|
|
8515
|
+
users.add(n_, f"{n_}-pass-123", r_)
|
|
8516
|
+
svc = Service(wsp, port=0, scheduler=False).start()
|
|
8517
|
+
base_url = svc.url.rstrip("/")
|
|
8518
|
+
|
|
8519
|
+
def opener():
|
|
8520
|
+
return urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
|
|
8521
|
+
|
|
8522
|
+
def call(op, method, path, body=None):
|
|
8523
|
+
req = urllib.request.Request(base_url + path, method=method, data=(json.dumps(body).encode() if body is not None else None))
|
|
8524
|
+
if method == "POST":
|
|
8525
|
+
req.add_header("Content-Type", "application/json"); req.add_header("X-GEA-Action", "1")
|
|
8526
|
+
try:
|
|
8527
|
+
with op.open(req, timeout=120) as rr_:
|
|
8528
|
+
return rr_.status, json.loads(rr_.read())
|
|
8529
|
+
except urllib.error.HTTPError as e:
|
|
8530
|
+
return e.code, json.loads(e.read())
|
|
8531
|
+
|
|
8532
|
+
def signin(name):
|
|
8533
|
+
op = opener(); call(op, "POST", "/api/login", {"name": name, "password": f"{name}-pass-123"}); return op
|
|
8534
|
+
try:
|
|
8535
|
+
anon = opener()
|
|
8536
|
+
st_anon, _ = call(anon, "GET", "/api/wall")
|
|
8537
|
+
V, O1, O2, A = signin("v"), signin("op1"), signin("op2"), signin("adm")
|
|
8538
|
+
st_v, bv = call(V, "GET", "/api/wall")
|
|
8539
|
+
st_vw, _ = call(V, "POST", "/api/handover", {"open": "x"})
|
|
8540
|
+
st_empty, _ = call(O1, "POST", "/api/handover", {"open": " ", "watching": "", "done": ""})
|
|
8541
|
+
st_long, _ = call(O1, "POST", "/api/handover", {"open": "x" * 2001})
|
|
8542
|
+
st_w, note = call(O1, "POST", "/api/handover", {"open": "Pump 2 liner swap not finished.", "watching": "SPP on the alarm well.", "done": "Reamed to bottom."})
|
|
8543
|
+
_, bdg1 = call(V, "GET", "/api/badges")
|
|
8544
|
+
_, wall1 = call(V, "GET", "/api/wall")
|
|
8545
|
+
st_self, self_ = call(O1, "POST", "/api/handover/ack", {"id": note.get("id")})
|
|
8546
|
+
st_ack, ack = call(O2, "POST", "/api/handover/ack", {"id": note.get("id"), "comment": "read at 06:05"})
|
|
8547
|
+
st_ack2, _ = call(O2, "POST", "/api/handover/ack", {"id": note.get("id")})
|
|
8548
|
+
st_nf, _ = call(O2, "POST", "/api/handover/ack", {"id": "H-none"})
|
|
8549
|
+
_, bdg2 = call(V, "GET", "/api/badges")
|
|
8550
|
+
_, hv = call(V, "GET", "/api/handover")
|
|
8551
|
+
# wall passes
|
|
8552
|
+
st_pv, _ = call(V, "POST", "/api/wall/pass", {"label": "doghouse"})
|
|
8553
|
+
st_pnl, _ = call(A, "POST", "/api/wall/pass", {"label": " "})
|
|
8554
|
+
st_pc, wp = call(A, "POST", "/api/wall/pass", {"label": "doghouse wall", "days": 30})
|
|
8555
|
+
_, plist = call(A, "GET", "/api/wall/passes")
|
|
8556
|
+
W = opener()
|
|
8557
|
+
st_bad, _ = call(W, "POST", "/api/wall/enter", {"code": wp["id"] + ".wrong"})
|
|
8558
|
+
st_in, _ = call(W, "POST", "/api/wall/enter", {"code": wp["code"]})
|
|
8559
|
+
st_ww, wwall = call(W, "GET", "/api/wall")
|
|
8560
|
+
_, wsess = call(W, "GET", "/api/session")
|
|
8561
|
+
st_wo, _ = call(W, "GET", "/api/overview")
|
|
8562
|
+
st_wh, _ = call(W, "GET", "/api/handover")
|
|
8563
|
+
st_wpost, _ = call(W, "POST", "/api/handover", {"open": "x"})
|
|
8564
|
+
st_rv, _ = call(A, "POST", "/api/wall/pass/revoke", {"id": wp["id"]})
|
|
8565
|
+
st_after, _ = call(W, "GET", "/api/wall")
|
|
8566
|
+
_, plist2 = call(A, "GET", "/api/wall/passes")
|
|
8567
|
+
L = opener()
|
|
8568
|
+
lock = [call(L, "POST", "/api/wall/enter", {"code": "W000000.nope"})[0] for _ in range(6)]
|
|
8569
|
+
finally:
|
|
8570
|
+
svc.stop()
|
|
8571
|
+
audit = [e["action"] for e in ws.audit_log(5000)]
|
|
8572
|
+
raw = (Path(wsp, "wall", "passes.json")).read_text(encoding="utf-8")
|
|
8573
|
+
lines = Path(wsp, "handover", "notes.jsonl").read_text(encoding="utf-8").splitlines()
|
|
8574
|
+
c2 = {
|
|
8575
|
+
"roles": st_anon == 401 and st_v == 200 and len(bv["tiles"]) == 4 and st_vw == 403,
|
|
8576
|
+
"note": st_empty == 400 and st_long == 400 and st_w == 200 and note["by"] == "op1" and note["ack"] is None
|
|
8577
|
+
and note["board"]["SERIOUS"] == 2 and note["board"]["alarms_unacked"] == 1
|
|
8578
|
+
and wall1["handover"]["id"] == note["id"] and wall1["handover"]["ack"] is None and bdg1["handover_unacked"] == 1,
|
|
8579
|
+
"ack": st_self == 403 and "author cannot acknowledge" in self_["error"] and st_ack == 200 and ack["by"] == "op2"
|
|
8580
|
+
and st_ack2 == 400 and st_nf == 404 and bdg2["handover_unacked"] == 0
|
|
8581
|
+
and hv["notes"][0]["ack"]["by"] == "op2" and hv["notes"][0]["ack"]["comment"] == "read at 06:05",
|
|
8582
|
+
"append_only": len(lines) == 2 and json.loads(lines[0])["kind"] == "note" and json.loads(lines[1])["kind"] == "ack",
|
|
8583
|
+
"audit": all(a_ in audit for a_ in ("handover.write", "handover.ack", "wall.pass.create", "wall.pass.failed", "wall.pass.enter", "wall.pass.revoke")),
|
|
8584
|
+
}
|
|
8585
|
+
failed2 = [k for k, v in c2.items() if not v]
|
|
8586
|
+
ok(not failed2,
|
|
8587
|
+
"CD2 the shift handover: a viewer reads the wall and cannot write; an empty or over-long note refused; a signed note keeps its author, its "
|
|
8588
|
+
"time and the board's counts (2 serious, 1 unacknowledged alarm), shows on the wall and badges the tab until acknowledged; the author "
|
|
8589
|
+
"cannot acknowledge it, the next operator can (once, with a comment); notes and acknowledgements appended, never rewritten; every step in "
|
|
8590
|
+
"the audit log"
|
|
8591
|
+
+ (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
|
|
8592
|
+
|
|
8593
|
+
page_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
|
|
8594
|
+
help_md = (pkg / "help" / "control-room.md").read_text(encoding="utf-8")
|
|
8595
|
+
c3 = {
|
|
8596
|
+
"pass": st_pv == 403 and st_pnl == 400 and st_pc == 200 and wp["code"].startswith(wp["id"] + ".") and wp["code"].split(".", 1)[1] not in raw
|
|
8597
|
+
and "hash" not in json.dumps(plist) and plist["passes"][0]["status"] == "ACTIVE",
|
|
8598
|
+
"wall_only": st_bad == 401 and st_in == 200 and st_ww == 200 and len(wwall["tiles"]) == 4 and wsess["user"] is None
|
|
8599
|
+
and wsess["wall_pass"]["label"] == "doghouse wall" and st_wo == 401 and st_wh == 401 and st_wpost == 401,
|
|
8600
|
+
"revoke": st_rv == 200 and st_after == 401 and plist2["passes"][0]["status"] == "REVOKED" and lock[-1] == 429,
|
|
8601
|
+
"page": all(x in page_src for x in ("VIEWS.wall", "VIEWS.control", "['#/control', 'Control room']", "/api/wall", "/api/handover/ack",
|
|
8602
|
+
"NOT UPDATING", "wakeLock", "requestFullscreen", "SIGNED OUT", "This is a wall screen",
|
|
8603
|
+
"crShape", "data-age0", "turns pages", "/api/wall/pass/revoke", "handover_unacked")),
|
|
8604
|
+
"help": any(t["topic"] == "control-room" for t in H.topics()) and not H.check("control-room") and H.VIEW_TOPIC.get("control") == "control-room"
|
|
8605
|
+
and "never called stale" in help_md.split("will not call a measurement")[1],
|
|
8606
|
+
}
|
|
8607
|
+
failed3 = [k for k, v in c3.items() if not v]
|
|
8608
|
+
ok(not failed3,
|
|
8609
|
+
"CD3 wall passes: issued by an administrator only and named for the screen, the code shown once and only its hash kept; a wrong pass "
|
|
8610
|
+
"refused and locked out after repeats; a pass shows the wall and nothing else - no other page, no handover list, no writing - until it is "
|
|
8611
|
+
"revoked; the page: the wall full screen with its shapes and words, the age of its last answer, NOT UPDATING across the screen when the "
|
|
8612
|
+
"service stops, the screen kept awake, pages turned when the wells do not fit, the handover written and acknowledged; the help page"
|
|
8613
|
+
+ (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
|
|
8614
|
+
|
|
8615
|
+
|
|
8451
8616
|
def main() -> int:
|
|
8452
8617
|
print("GEA-Program - ACCEPTANCE SUITE (the product gate)")
|
|
8453
8618
|
# a handle a job subprocess still holds at the end must not turn a finished gate into a traceback on Windows:
|
|
@@ -8532,6 +8697,7 @@ def main() -> int:
|
|
|
8532
8697
|
section_ca_setup_checklist(tmp)
|
|
8533
8698
|
section_cb_charts(tmp)
|
|
8534
8699
|
section_cc_site_map(tmp)
|
|
8700
|
+
section_cd_control_room(tmp)
|
|
8535
8701
|
if _FAILS:
|
|
8536
8702
|
print(f"[ACCEPTANCE] {len(_FAILS)} FAILURES ({_PASS} passed):")
|
|
8537
8703
|
for f in _FAILS:
|