africas2s 0.2.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.
- africas2s-0.2.0/.github/workflows/add-to-kanban.yml +14 -0
- africas2s-0.2.0/.github/workflows/publish-testpypi.yml +18 -0
- africas2s-0.2.0/.github/workflows/publish.yml +50 -0
- africas2s-0.2.0/.github/workflows/s2s_testbed.yml +341 -0
- africas2s-0.2.0/.github/workflows/test.yml +27 -0
- africas2s-0.2.0/.gitignore +54 -0
- africas2s-0.2.0/AGENTS.md +33 -0
- africas2s-0.2.0/LICENSE +21 -0
- africas2s-0.2.0/PKG-INFO +285 -0
- africas2s-0.2.0/README.md +237 -0
- africas2s-0.2.0/docs/specs/2026-07-09-analog-completion-design.md +98 -0
- africas2s-0.2.0/docs/specs/2026-07-09-index-generalization-design.md +79 -0
- africas2s-0.2.0/examples/README.md +54 -0
- africas2s-0.2.0/examples/demo_checkpoint_roundtrip.py +76 -0
- africas2s-0.2.0/examples/demo_chelsa.py +311 -0
- africas2s-0.2.0/examples/demo_corrdiff.py +307 -0
- africas2s-0.2.0/examples/demo_delta_scaling.py +56 -0
- africas2s-0.2.0/examples/demo_detrended_qm.py +61 -0
- africas2s-0.2.0/examples/demo_ensemble_regression.py +186 -0
- africas2s-0.2.0/examples/demo_forecast.py +355 -0
- africas2s-0.2.0/examples/demo_logistic_wvg.py +185 -0
- africas2s-0.2.0/examples/demo_probabilistic_method.py +102 -0
- africas2s-0.2.0/examples/demo_quantile_mapping.py +61 -0
- africas2s-0.2.0/examples/demo_realdata_comparison.py +142 -0
- africas2s-0.2.0/examples/demo_realdata_skill.py +117 -0
- africas2s-0.2.0/examples/demo_seasonal_mme.py +206 -0
- africas2s-0.2.0/examples/demo_seasonal_mme_multimodel.py +242 -0
- africas2s-0.2.0/examples/demo_smoothed_forecast.py +104 -0
- africas2s-0.2.0/examples/demo_train_inference.py +106 -0
- africas2s-0.2.0/examples/onset_gha_mam.py +82 -0
- africas2s-0.2.0/examples/seasonal_forecast_eastafrica_mam.py +360 -0
- africas2s-0.2.0/notebooks/experimentB1.ipynb +1061 -0
- africas2s-0.2.0/pyproject.toml +105 -0
- africas2s-0.2.0/scripts/DWN_CPT_SRC.sh +32 -0
- africas2s-0.2.0/scripts/benchmark_pycpt.py +544 -0
- africas2s-0.2.0/scripts/install_pycpt.sh +80 -0
- africas2s-0.2.0/scripts/nightly/__init__.py +5 -0
- africas2s-0.2.0/scripts/nightly/config.py +74 -0
- africas2s-0.2.0/scripts/nightly/nightly.yml +150 -0
- africas2s-0.2.0/scripts/nightly/output_writer.py +73 -0
- africas2s-0.2.0/scripts/nightly/publish.py +181 -0
- africas2s-0.2.0/scripts/nightly/run_country.py +230 -0
- africas2s-0.2.0/scripts/nightly/select_targets.py +56 -0
- africas2s-0.2.0/scripts/nightly/site/app.js +299 -0
- africas2s-0.2.0/scripts/nightly/site/index.html +74 -0
- africas2s-0.2.0/scripts/nightly/site/style.css +43 -0
- africas2s-0.2.0/scripts/reproduce.py +559 -0
- africas2s-0.2.0/scripts/reproduce_batch.py +657 -0
- africas2s-0.2.0/scripts/s2s/__init__.py +0 -0
- africas2s-0.2.0/scripts/s2s/config.py +72 -0
- africas2s-0.2.0/scripts/s2s/dekads.py +14 -0
- africas2s-0.2.0/scripts/s2s/detect_new_issuances.py +69 -0
- africas2s-0.2.0/scripts/s2s/init_issuance_store.md +50 -0
- africas2s-0.2.0/scripts/s2s/issuance_store.py +86 -0
- africas2s-0.2.0/scripts/s2s/plotting.py +232 -0
- africas2s-0.2.0/scripts/s2s/publish_pages.py +56 -0
- africas2s-0.2.0/scripts/s2s/render_dashboard.py +310 -0
- africas2s-0.2.0/scripts/s2s/run_issuance.py +269 -0
- africas2s-0.2.0/scripts/s2s/s2s.yml +47 -0
- africas2s-0.2.0/scripts/s2s/scoring.py +121 -0
- africas2s-0.2.0/scripts/s2s/verify.py +205 -0
- africas2s-0.2.0/site/index.html +29 -0
- africas2s-0.2.0/site/theme.css +55 -0
- africas2s-0.2.0/skills/africas2s/README.md +57 -0
- africas2s-0.2.0/skills/africas2s/SKILL.md +161 -0
- africas2s-0.2.0/skills/africas2s/examples/analog_completion.py +82 -0
- africas2s-0.2.0/skills/africas2s/examples/calibration.py +131 -0
- africas2s-0.2.0/skills/africas2s/examples/end_to_end_forecast.py +62 -0
- africas2s-0.2.0/skills/africas2s/examples/ensemble_and_reporting.py +58 -0
- africas2s-0.2.0/skills/africas2s/examples/seasonal_mme_pipeline.py +56 -0
- africas2s-0.2.0/skills/africas2s/examples/smoothed_calibration.py +72 -0
- africas2s-0.2.0/skills/africas2s/references/aggregations.md +281 -0
- africas2s-0.2.0/skills/africas2s/references/analog-completion.md +304 -0
- africas2s-0.2.0/skills/africas2s/references/api.md +267 -0
- africas2s-0.2.0/skills/africas2s/references/methods.md +141 -0
- africas2s-0.2.0/skills/africas2s/references/metrics-and-terciles.md +112 -0
- africas2s-0.2.0/skills/africas2s/references/plotting-reporting.md +184 -0
- africas2s-0.2.0/skills/africas2s/references/troubleshooting.md +53 -0
- africas2s-0.2.0/src/africas2s/__init__.py +100 -0
- africas2s-0.2.0/src/africas2s/_optional.py +10 -0
- africas2s-0.2.0/src/africas2s/_spatial.py +30 -0
- africas2s-0.2.0/src/africas2s/_warnings.py +30 -0
- africas2s-0.2.0/src/africas2s/aggregations/__init__.py +21 -0
- africas2s-0.2.0/src/africas2s/aggregations/_runs.py +73 -0
- africas2s-0.2.0/src/africas2s/aggregations/spells.py +93 -0
- africas2s-0.2.0/src/africas2s/aggregations/timing.py +446 -0
- africas2s-0.2.0/src/africas2s/analog.py +457 -0
- africas2s-0.2.0/src/africas2s/calibrate.py +1025 -0
- africas2s-0.2.0/src/africas2s/climate.py +440 -0
- africas2s-0.2.0/src/africas2s/combine.py +223 -0
- africas2s-0.2.0/src/africas2s/compare.py +162 -0
- africas2s-0.2.0/src/africas2s/completion.py +409 -0
- africas2s-0.2.0/src/africas2s/cv.py +145 -0
- africas2s-0.2.0/src/africas2s/downscale.py +85 -0
- africas2s-0.2.0/src/africas2s/ensemble.py +454 -0
- africas2s-0.2.0/src/africas2s/flex_forecast.py +129 -0
- africas2s-0.2.0/src/africas2s/indices.py +524 -0
- africas2s-0.2.0/src/africas2s/io.py +94 -0
- africas2s-0.2.0/src/africas2s/logistic.py +337 -0
- africas2s-0.2.0/src/africas2s/methods/__init__.py +6 -0
- africas2s-0.2.0/src/africas2s/methods/_qm_kernel.py +118 -0
- africas2s-0.2.0/src/africas2s/methods/base.py +84 -0
- africas2s-0.2.0/src/africas2s/methods/bcsd.py +70 -0
- africas2s-0.2.0/src/africas2s/methods/cca.py +525 -0
- africas2s-0.2.0/src/africas2s/methods/chelsa.py +337 -0
- africas2s-0.2.0/src/africas2s/methods/climatology.py +45 -0
- africas2s-0.2.0/src/africas2s/methods/corrdiff.py +367 -0
- africas2s-0.2.0/src/africas2s/methods/delta.py +39 -0
- africas2s-0.2.0/src/africas2s/methods/dqm.py +86 -0
- africas2s-0.2.0/src/africas2s/methods/ensemble_regression.py +255 -0
- africas2s-0.2.0/src/africas2s/methods/qm.py +101 -0
- africas2s-0.2.0/src/africas2s/methods/rank_analog.py +136 -0
- africas2s-0.2.0/src/africas2s/methods/smoothed_regression.py +170 -0
- africas2s-0.2.0/src/africas2s/metrics/__init__.py +12 -0
- africas2s-0.2.0/src/africas2s/metrics/base.py +6 -0
- africas2s-0.2.0/src/africas2s/metrics/cross_validation.py +71 -0
- africas2s-0.2.0/src/africas2s/metrics/crpss.py +45 -0
- africas2s-0.2.0/src/africas2s/metrics/generalized_roc.py +126 -0
- africas2s-0.2.0/src/africas2s/metrics/heidke.py +70 -0
- africas2s-0.2.0/src/africas2s/metrics/msss.py +30 -0
- africas2s-0.2.0/src/africas2s/metrics/pearson.py +27 -0
- africas2s-0.2.0/src/africas2s/metrics/reliability.py +71 -0
- africas2s-0.2.0/src/africas2s/metrics/rmse.py +23 -0
- africas2s-0.2.0/src/africas2s/metrics/roc.py +79 -0
- africas2s-0.2.0/src/africas2s/metrics/rpss.py +144 -0
- africas2s-0.2.0/src/africas2s/metrics/significance.py +107 -0
- africas2s-0.2.0/src/africas2s/metrics/spearman.py +64 -0
- africas2s-0.2.0/src/africas2s/metrics/spread_error.py +117 -0
- africas2s-0.2.0/src/africas2s/metrics/two_afc.py +61 -0
- africas2s-0.2.0/src/africas2s/optimize.py +103 -0
- africas2s-0.2.0/src/africas2s/pev.py +66 -0
- africas2s-0.2.0/src/africas2s/pipelines/__init__.py +3 -0
- africas2s-0.2.0/src/africas2s/pipelines/seasonal.py +798 -0
- africas2s-0.2.0/src/africas2s/plotting/__init__.py +47 -0
- africas2s-0.2.0/src/africas2s/plotting/domains.py +81 -0
- africas2s-0.2.0/src/africas2s/plotting/forecasts.py +733 -0
- africas2s-0.2.0/src/africas2s/plotting/maps.py +435 -0
- africas2s-0.2.0/src/africas2s/plotting/modes.py +229 -0
- africas2s-0.2.0/src/africas2s/plotting/reliability.py +73 -0
- africas2s-0.2.0/src/africas2s/plotting/scenarios.py +339 -0
- africas2s-0.2.0/src/africas2s/plotting/skill.py +83 -0
- africas2s-0.2.0/src/africas2s/plotting/style.py +41 -0
- africas2s-0.2.0/src/africas2s/registry.py +55 -0
- africas2s-0.2.0/src/africas2s/reporting/__init__.py +8 -0
- africas2s-0.2.0/src/africas2s/reporting/_pages.py +541 -0
- africas2s-0.2.0/src/africas2s/reporting/svslrf.py +57 -0
- africas2s-0.2.0/src/africas2s/series.py +202 -0
- africas2s-0.2.0/src/africas2s/skill.py +192 -0
- africas2s-0.2.0/src/africas2s/strategies/__init__.py +10 -0
- africas2s-0.2.0/src/africas2s/strategies/base.py +25 -0
- africas2s-0.2.0/src/africas2s/strategies/bma.py +132 -0
- africas2s-0.2.0/src/africas2s/strategies/drop_worst.py +103 -0
- africas2s-0.2.0/src/africas2s/strategies/skill_weighted.py +62 -0
- africas2s-0.2.0/src/africas2s/strategies/uniform.py +25 -0
- africas2s-0.2.0/src/africas2s/tercile.py +335 -0
- africas2s-0.2.0/src/africas2s/terrain.py +255 -0
- africas2s-0.2.0/src/africas2s/time.py +346 -0
- africas2s-0.2.0/src/africas2s/training/__init__.py +53 -0
- africas2s-0.2.0/tests/__init__.py +0 -0
- africas2s-0.2.0/tests/conftest.py +109 -0
- africas2s-0.2.0/tests/s2s/__init__.py +0 -0
- africas2s-0.2.0/tests/s2s/test_config.py +87 -0
- africas2s-0.2.0/tests/s2s/test_dekads.py +51 -0
- africas2s-0.2.0/tests/s2s/test_detect_new_issuances.py +32 -0
- africas2s-0.2.0/tests/s2s/test_issuance_store.py +56 -0
- africas2s-0.2.0/tests/s2s/test_obs_lookup.py +85 -0
- africas2s-0.2.0/tests/s2s/test_plotting.py +58 -0
- africas2s-0.2.0/tests/s2s/test_plotting_dark.py +39 -0
- africas2s-0.2.0/tests/s2s/test_publish_pages.py +85 -0
- africas2s-0.2.0/tests/s2s/test_render_dashboard.py +205 -0
- africas2s-0.2.0/tests/s2s/test_run_issuance_integration.py +258 -0
- africas2s-0.2.0/tests/s2s/test_scoring.py +90 -0
- africas2s-0.2.0/tests/s2s/test_verify_integration.py +225 -0
- africas2s-0.2.0/tests/test_aggregations_integration.py +65 -0
- africas2s-0.2.0/tests/test_aggregations_parity.py +102 -0
- africas2s-0.2.0/tests/test_aggregations_runs.py +52 -0
- africas2s-0.2.0/tests/test_aggregations_spells.py +80 -0
- africas2s-0.2.0/tests/test_aggregations_timing.py +414 -0
- africas2s-0.2.0/tests/test_agreement.py +90 -0
- africas2s-0.2.0/tests/test_analog.py +374 -0
- africas2s-0.2.0/tests/test_calibrate.py +377 -0
- africas2s-0.2.0/tests/test_calibrate_components.py +142 -0
- africas2s-0.2.0/tests/test_calibrate_deterministic.py +106 -0
- africas2s-0.2.0/tests/test_calibrate_ereg_native_years.py +111 -0
- africas2s-0.2.0/tests/test_calibrate_probabilistic.py +54 -0
- africas2s-0.2.0/tests/test_calibrate_smoothed_forecast.py +238 -0
- africas2s-0.2.0/tests/test_cca_cpt_args.py +265 -0
- africas2s-0.2.0/tests/test_cca_robustness.py +90 -0
- africas2s-0.2.0/tests/test_chelsa.py +210 -0
- africas2s-0.2.0/tests/test_climate.py +311 -0
- africas2s-0.2.0/tests/test_climatology_integration.py +54 -0
- africas2s-0.2.0/tests/test_combine_terciles.py +161 -0
- africas2s-0.2.0/tests/test_completion.py +501 -0
- africas2s-0.2.0/tests/test_corrdiff.py +383 -0
- africas2s-0.2.0/tests/test_corrdiff_integration.py +97 -0
- africas2s-0.2.0/tests/test_crpss.py +39 -0
- africas2s-0.2.0/tests/test_cv.py +285 -0
- africas2s-0.2.0/tests/test_delta.py +87 -0
- africas2s-0.2.0/tests/test_downscale.py +278 -0
- africas2s-0.2.0/tests/test_dqm.py +92 -0
- africas2s-0.2.0/tests/test_ensemble.py +692 -0
- africas2s-0.2.0/tests/test_ensemble_diagnostics.py +157 -0
- africas2s-0.2.0/tests/test_ensemble_regression.py +221 -0
- africas2s-0.2.0/tests/test_ensemble_safeguards_integration.py +121 -0
- africas2s-0.2.0/tests/test_example_chelsa.py +23 -0
- africas2s-0.2.0/tests/test_example_eastafrica_mam.py +42 -0
- africas2s-0.2.0/tests/test_example_logistic_ereg.py +37 -0
- africas2s-0.2.0/tests/test_flex_forecast.py +101 -0
- africas2s-0.2.0/tests/test_groc_integration.py +51 -0
- africas2s-0.2.0/tests/test_indices.py +143 -0
- africas2s-0.2.0/tests/test_indices_general.py +322 -0
- africas2s-0.2.0/tests/test_integration_reporting.py +96 -0
- africas2s-0.2.0/tests/test_load_terrain.py +273 -0
- africas2s-0.2.0/tests/test_logistic.py +199 -0
- africas2s-0.2.0/tests/test_mask_forecast.py +83 -0
- africas2s-0.2.0/tests/test_method_invariants.py +303 -0
- africas2s-0.2.0/tests/test_methods.py +853 -0
- africas2s-0.2.0/tests/test_metrics.py +958 -0
- africas2s-0.2.0/tests/test_mode_selection_north.py +115 -0
- africas2s-0.2.0/tests/test_msss.py +57 -0
- africas2s-0.2.0/tests/test_nightly.py +423 -0
- africas2s-0.2.0/tests/test_nightly_integration.py +66 -0
- africas2s-0.2.0/tests/test_percent_of_normal.py +57 -0
- africas2s-0.2.0/tests/test_pev.py +120 -0
- africas2s-0.2.0/tests/test_pev_integration.py +97 -0
- africas2s-0.2.0/tests/test_plotting.py +744 -0
- africas2s-0.2.0/tests/test_plotting_maps.py +212 -0
- africas2s-0.2.0/tests/test_plotting_scenarios.py +297 -0
- africas2s-0.2.0/tests/test_pool_ensembles.py +102 -0
- africas2s-0.2.0/tests/test_public_io_helpers.py +112 -0
- africas2s-0.2.0/tests/test_qm.py +116 -0
- africas2s-0.2.0/tests/test_rank_analog_integration.py +91 -0
- africas2s-0.2.0/tests/test_render_styled.py +36 -0
- africas2s-0.2.0/tests/test_reporting.py +564 -0
- africas2s-0.2.0/tests/test_seasonal_mme.py +314 -0
- africas2s-0.2.0/tests/test_seasonal_mme_integration.py +127 -0
- africas2s-0.2.0/tests/test_seasonal_native_years.py +166 -0
- africas2s-0.2.0/tests/test_seasonal_reduce.py +55 -0
- africas2s-0.2.0/tests/test_series.py +250 -0
- africas2s-0.2.0/tests/test_significance.py +122 -0
- africas2s-0.2.0/tests/test_smoothed_forecast_integration.py +94 -0
- africas2s-0.2.0/tests/test_smoothed_regression.py +76 -0
- africas2s-0.2.0/tests/test_smoothed_regression_prob.py +50 -0
- africas2s-0.2.0/tests/test_spatial.py +32 -0
- africas2s-0.2.0/tests/test_spec.md +353 -0
- africas2s-0.2.0/tests/test_spread_error_integration.py +59 -0
- africas2s-0.2.0/tests/test_tercile.py +102 -0
- africas2s-0.2.0/tests/test_tercile_cv.py +101 -0
- africas2s-0.2.0/tests/test_time.py +260 -0
- africas2s-0.2.0/tests/test_training.py +124 -0
- africas2s-0.2.0/uv.lock +3129 -0
- africas2s-0.2.0/validation/chelsa/saga_wind_effect.csv +9 -0
- africas2s-0.2.0/validation/chelsa/validate_saga_fixture.py +87 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
name: Add issues to Kanban
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
issues:
|
|
5
|
+
types: [opened, reopened]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
add-to-kanban:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/add-to-project@v1.0.2
|
|
12
|
+
with:
|
|
13
|
+
project-url: https://github.com/orgs/accord-research/projects/2
|
|
14
|
+
github-token: ${{ secrets.KANBAN_TOKEN }}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
name: publish-testpypi
|
|
2
|
+
on:
|
|
3
|
+
workflow_dispatch:
|
|
4
|
+
|
|
5
|
+
permissions:
|
|
6
|
+
id-token: write
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build-publish-test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
environment: testpypi
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: astral-sh/setup-uv@v6
|
|
15
|
+
- run: uv build
|
|
16
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
17
|
+
with:
|
|
18
|
+
repository-url: https://test.pypi.org/legacy/
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
|
|
3
|
+
# PyPI releases are cut MANUALLY, never on a push to main.
|
|
4
|
+
#
|
|
5
|
+
# To release:
|
|
6
|
+
# 1. Bump `version` in pyproject.toml (in a commit to main).
|
|
7
|
+
# 2. Actions tab -> "publish" -> "Run workflow".
|
|
8
|
+
#
|
|
9
|
+
# The job publishes only if that version isn't already on PyPI, so re-running
|
|
10
|
+
# without a version bump is a safe no-op (it fails fast with a clear message).
|
|
11
|
+
# pyproject.toml's `version` is the single source of truth. Publishing uses
|
|
12
|
+
# PyPI Trusted Publishing (no tokens).
|
|
13
|
+
|
|
14
|
+
on:
|
|
15
|
+
workflow_dispatch:
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
test:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
- uses: astral-sh/setup-uv@v6
|
|
23
|
+
- run: uv sync --extra dev
|
|
24
|
+
- run: |
|
|
25
|
+
uv run pytest tests/ \
|
|
26
|
+
--ignore=tests/test_agreement.py \
|
|
27
|
+
--ignore=tests/test_corrdiff.py \
|
|
28
|
+
--ignore=tests/test_corrdiff_integration.py \
|
|
29
|
+
-m "not gpu and not integration" -q
|
|
30
|
+
|
|
31
|
+
publish:
|
|
32
|
+
needs: test
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
environment: pypi
|
|
35
|
+
permissions:
|
|
36
|
+
id-token: write
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@v4
|
|
39
|
+
- uses: astral-sh/setup-uv@v6
|
|
40
|
+
- name: Refuse to republish an existing version
|
|
41
|
+
run: |
|
|
42
|
+
VERSION=$(grep -E '^version = ' pyproject.toml | head -1 | sed -E 's/version = "(.*)"/\1/')
|
|
43
|
+
echo "pyproject.toml version: $VERSION"
|
|
44
|
+
if curl -sf "https://pypi.org/pypi/africas2s/$VERSION/json" > /dev/null; then
|
|
45
|
+
echo "::error::africas2s $VERSION is already on PyPI — bump 'version' in pyproject.toml first."
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
echo "$VERSION is new on PyPI; proceeding to publish."
|
|
49
|
+
- run: uv build
|
|
50
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
name: s2s testbed
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
- cron: '0 2 * * *' # 02:00 UTC daily
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
lookback_days:
|
|
9
|
+
description: 'How many days back to scan for missed issuances'
|
|
10
|
+
required: false
|
|
11
|
+
default: '14'
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: write # We push to the issuance-store branch.
|
|
15
|
+
|
|
16
|
+
env:
|
|
17
|
+
CDSAPI_KEY: ${{ secrets.CDSAPI_KEY }}
|
|
18
|
+
MARS_API_KEY: ${{ secrets.MARS_API_KEY }}
|
|
19
|
+
MARS_API_EMAIL: ${{ secrets.MARS_API_EMAIL }}
|
|
20
|
+
COUNTRIES: '["kenya","ethiopia","nigeria"]'
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
|
|
24
|
+
detect_issuances:
|
|
25
|
+
name: detect new issuances per country
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
outputs:
|
|
28
|
+
matrix: ${{ steps.build.outputs.matrix }}
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v4
|
|
31
|
+
- uses: actions/checkout@v4
|
|
32
|
+
with:
|
|
33
|
+
ref: issuance-store
|
|
34
|
+
path: issuance-store-checkout
|
|
35
|
+
|
|
36
|
+
- uses: astral-sh/setup-uv@v6
|
|
37
|
+
with:
|
|
38
|
+
enable-cache: true
|
|
39
|
+
|
|
40
|
+
- name: Install africas2s (no extras)
|
|
41
|
+
run: uv sync
|
|
42
|
+
|
|
43
|
+
- name: Build (country, issuance) matrix
|
|
44
|
+
id: build
|
|
45
|
+
run: |
|
|
46
|
+
set -euo pipefail
|
|
47
|
+
LOOKBACK=${{ github.event.inputs.lookback_days || '14' }}
|
|
48
|
+
MATRIX='[]'
|
|
49
|
+
for COUNTRY in $(echo "$COUNTRIES" | jq -r '.[]'); do
|
|
50
|
+
ISSUANCES=$(uv run python -m scripts.s2s.detect_new_issuances \
|
|
51
|
+
--store-root issuance-store-checkout \
|
|
52
|
+
--country "$COUNTRY" \
|
|
53
|
+
--lookback-days "$LOOKBACK")
|
|
54
|
+
MATRIX=$(jq --argjson m "$MATRIX" --arg c "$COUNTRY" --argjson is "$ISSUANCES" \
|
|
55
|
+
-n '$m + [$is[] | {country: $c, issuance: .}]')
|
|
56
|
+
done
|
|
57
|
+
echo "matrix=$(echo "$MATRIX" | jq -c '{include: .}')" >> "$GITHUB_OUTPUT"
|
|
58
|
+
|
|
59
|
+
forecast:
|
|
60
|
+
name: forecast (${{ matrix.country }} @ ${{ matrix.issuance }})
|
|
61
|
+
needs: detect_issuances
|
|
62
|
+
if: ${{ needs.detect_issuances.outputs.matrix != '{"include":[]}' }}
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
strategy:
|
|
65
|
+
fail-fast: false
|
|
66
|
+
# ECDS allows multiple concurrent requests per user (the legacy MARS
|
|
67
|
+
# WEB-API's 1-queued-per-user limit is gone now that we're off it).
|
|
68
|
+
# Three parallel shards keeps total cron wall-clock down without
|
|
69
|
+
# hammering ECDS or running out of GitHub-hosted runner concurrency.
|
|
70
|
+
max-parallel: 3
|
|
71
|
+
matrix: ${{ fromJSON(needs.detect_issuances.outputs.matrix) }}
|
|
72
|
+
steps:
|
|
73
|
+
- uses: actions/checkout@v4
|
|
74
|
+
- uses: actions/checkout@v4
|
|
75
|
+
with:
|
|
76
|
+
ref: issuance-store
|
|
77
|
+
path: issuance-store-checkout
|
|
78
|
+
- uses: actions/checkout@v4
|
|
79
|
+
with:
|
|
80
|
+
repository: accord-research/rosetta
|
|
81
|
+
path: rosetta
|
|
82
|
+
|
|
83
|
+
- uses: astral-sh/setup-uv@v6
|
|
84
|
+
with:
|
|
85
|
+
enable-cache: true
|
|
86
|
+
|
|
87
|
+
- name: Install africas2s + rosetta
|
|
88
|
+
run: |
|
|
89
|
+
uv sync
|
|
90
|
+
uv pip install -e ./rosetta
|
|
91
|
+
|
|
92
|
+
- name: Configure nuthatch cache location
|
|
93
|
+
run: |
|
|
94
|
+
mkdir -p ~/.cache/nuthatch
|
|
95
|
+
cat > ~/.nuthatch.toml <<EOF
|
|
96
|
+
[tool.nuthatch]
|
|
97
|
+
filesystem = "~/.cache/nuthatch"
|
|
98
|
+
skipped_filesystems = ["gs://sheerwater-datalake/caches"]
|
|
99
|
+
EOF
|
|
100
|
+
|
|
101
|
+
- name: Restore nuthatch cache
|
|
102
|
+
uses: actions/cache@v4
|
|
103
|
+
with:
|
|
104
|
+
path: ~/.cache/nuthatch
|
|
105
|
+
# Per-(country, issuance) cache keyed on the rosetta files whose
|
|
106
|
+
# contents define cache semantics (catalog units, normalization
|
|
107
|
+
# logic, _CACHE_VERSION). When those change, the cache invalidates.
|
|
108
|
+
key: nuthatch-${{ matrix.country }}-${{ matrix.issuance }}-${{ hashFiles('rosetta/src/rosetta/catalog.yaml', 'rosetta/src/rosetta/normalize.py', 'rosetta/src/rosetta/fetch.py') }}
|
|
109
|
+
restore-keys: |
|
|
110
|
+
nuthatch-${{ matrix.country }}-${{ matrix.issuance }}-
|
|
111
|
+
nuthatch-${{ matrix.country }}-
|
|
112
|
+
nuthatch-
|
|
113
|
+
|
|
114
|
+
- name: Write .cdsapirc
|
|
115
|
+
run: |
|
|
116
|
+
umask 077
|
|
117
|
+
cat > ~/.cdsapirc <<EOF
|
|
118
|
+
url: https://ecds.ecmwf.int/api
|
|
119
|
+
key: ${CDSAPI_KEY}
|
|
120
|
+
EOF
|
|
121
|
+
|
|
122
|
+
- name: Write .ecmwfapirc
|
|
123
|
+
run: |
|
|
124
|
+
umask 077
|
|
125
|
+
cat > ~/.ecmwfapirc <<EOF
|
|
126
|
+
{
|
|
127
|
+
"url": "https://api.ecmwf.int/v1",
|
|
128
|
+
"key": "${MARS_API_KEY}",
|
|
129
|
+
"email": "${MARS_API_EMAIL}"
|
|
130
|
+
}
|
|
131
|
+
EOF
|
|
132
|
+
|
|
133
|
+
- name: Run issuance
|
|
134
|
+
env:
|
|
135
|
+
S2S_STORE_ROOT: issuance-store-checkout/issuances
|
|
136
|
+
run: |
|
|
137
|
+
uv run python -m scripts.s2s.run_issuance \
|
|
138
|
+
--country "${{ matrix.country }}" \
|
|
139
|
+
--issuance "${{ matrix.issuance }}" \
|
|
140
|
+
--config scripts/s2s/s2s.yml
|
|
141
|
+
|
|
142
|
+
- name: Commit + push new issuance to issuance-store
|
|
143
|
+
working-directory: issuance-store-checkout
|
|
144
|
+
run: |
|
|
145
|
+
set -euo pipefail
|
|
146
|
+
git config user.name "github-actions[bot]"
|
|
147
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
148
|
+
git add issuances/
|
|
149
|
+
if git diff --cached --quiet; then
|
|
150
|
+
echo "Nothing to commit for ${{ matrix.country }} @ ${{ matrix.issuance }}"
|
|
151
|
+
exit 0
|
|
152
|
+
fi
|
|
153
|
+
git commit -m "forecast: ${{ matrix.country }} @ ${{ matrix.issuance }}"
|
|
154
|
+
# Retry-pull-rebase to absorb concurrent matrix shards.
|
|
155
|
+
for attempt in 1 2 3 4 5; do
|
|
156
|
+
git pull --rebase origin issuance-store && git push origin issuance-store && exit 0
|
|
157
|
+
sleep $((attempt * 5))
|
|
158
|
+
done
|
|
159
|
+
echo "Push failed after 5 attempts" >&2
|
|
160
|
+
exit 1
|
|
161
|
+
|
|
162
|
+
verify:
|
|
163
|
+
name: verification pass
|
|
164
|
+
needs: forecast
|
|
165
|
+
if: ${{ always() }} # Run even if some forecast shards failed; verify is independent.
|
|
166
|
+
runs-on: ubuntu-latest
|
|
167
|
+
steps:
|
|
168
|
+
- uses: actions/checkout@v4
|
|
169
|
+
- uses: actions/checkout@v4
|
|
170
|
+
with:
|
|
171
|
+
ref: issuance-store
|
|
172
|
+
path: issuance-store-checkout
|
|
173
|
+
- uses: actions/checkout@v4
|
|
174
|
+
with:
|
|
175
|
+
repository: accord-research/rosetta
|
|
176
|
+
path: rosetta
|
|
177
|
+
|
|
178
|
+
- uses: astral-sh/setup-uv@v6
|
|
179
|
+
with:
|
|
180
|
+
enable-cache: true
|
|
181
|
+
|
|
182
|
+
- name: Install africas2s + rosetta
|
|
183
|
+
run: |
|
|
184
|
+
uv sync
|
|
185
|
+
uv pip install -e ./rosetta
|
|
186
|
+
|
|
187
|
+
- name: Configure nuthatch cache location
|
|
188
|
+
run: |
|
|
189
|
+
mkdir -p ~/.cache/nuthatch
|
|
190
|
+
cat > ~/.nuthatch.toml <<EOF
|
|
191
|
+
[tool.nuthatch]
|
|
192
|
+
filesystem = "~/.cache/nuthatch"
|
|
193
|
+
skipped_filesystems = ["gs://sheerwater-datalake/caches"]
|
|
194
|
+
EOF
|
|
195
|
+
|
|
196
|
+
- name: Restore nuthatch cache
|
|
197
|
+
uses: actions/cache@v4
|
|
198
|
+
with:
|
|
199
|
+
path: ~/.cache/nuthatch
|
|
200
|
+
# Verify is a single job that needs obs for every country, so use one
|
|
201
|
+
# shared verify-scoped cache. Restores from the forecast shards' caches
|
|
202
|
+
# too (they fetched the same CHIRPS dates) via the `nuthatch-` prefix.
|
|
203
|
+
key: nuthatch-verify-${{ github.run_id }}-${{ hashFiles('rosetta/src/rosetta/catalog.yaml', 'rosetta/src/rosetta/normalize.py', 'rosetta/src/rosetta/fetch.py') }}
|
|
204
|
+
restore-keys: |
|
|
205
|
+
nuthatch-verify-
|
|
206
|
+
nuthatch-
|
|
207
|
+
|
|
208
|
+
- name: Write .cdsapirc
|
|
209
|
+
run: |
|
|
210
|
+
umask 077
|
|
211
|
+
cat > ~/.cdsapirc <<EOF
|
|
212
|
+
url: https://ecds.ecmwf.int/api
|
|
213
|
+
key: ${CDSAPI_KEY}
|
|
214
|
+
EOF
|
|
215
|
+
|
|
216
|
+
- name: Write .ecmwfapirc
|
|
217
|
+
run: |
|
|
218
|
+
umask 077
|
|
219
|
+
cat > ~/.ecmwfapirc <<EOF
|
|
220
|
+
{
|
|
221
|
+
"url": "https://api.ecmwf.int/v1",
|
|
222
|
+
"key": "${MARS_API_KEY}",
|
|
223
|
+
"email": "${MARS_API_EMAIL}"
|
|
224
|
+
}
|
|
225
|
+
EOF
|
|
226
|
+
|
|
227
|
+
- name: Run verification
|
|
228
|
+
run: |
|
|
229
|
+
uv run python -m scripts.s2s.verify \
|
|
230
|
+
--store-root issuance-store-checkout/issuances \
|
|
231
|
+
--verification-root issuance-store-checkout/verification \
|
|
232
|
+
--config scripts/s2s/s2s.yml
|
|
233
|
+
|
|
234
|
+
- name: Commit + push verification updates
|
|
235
|
+
working-directory: issuance-store-checkout
|
|
236
|
+
run: |
|
|
237
|
+
set -euo pipefail
|
|
238
|
+
git config user.name "github-actions[bot]"
|
|
239
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
240
|
+
git add verification/
|
|
241
|
+
if git diff --cached --quiet; then
|
|
242
|
+
echo "No new scores to commit"
|
|
243
|
+
exit 0
|
|
244
|
+
fi
|
|
245
|
+
git commit -m "verify: $(date -u +%Y-%m-%dT%H:%MZ)"
|
|
246
|
+
for attempt in 1 2 3 4 5; do
|
|
247
|
+
git pull --rebase origin issuance-store && git push origin issuance-store && exit 0
|
|
248
|
+
sleep $((attempt * 5))
|
|
249
|
+
done
|
|
250
|
+
exit 1
|
|
251
|
+
|
|
252
|
+
publish:
|
|
253
|
+
name: render + publish dashboard
|
|
254
|
+
needs: verify
|
|
255
|
+
if: ${{ always() }} # Publish whatever data made it through.
|
|
256
|
+
runs-on: ubuntu-latest
|
|
257
|
+
steps:
|
|
258
|
+
- uses: actions/checkout@v4 # main: code + site/ shell
|
|
259
|
+
- uses: actions/checkout@v4
|
|
260
|
+
with:
|
|
261
|
+
ref: issuance-store
|
|
262
|
+
path: issuance-store-checkout # data: issuances/ + verification/
|
|
263
|
+
- uses: actions/checkout@v4
|
|
264
|
+
with:
|
|
265
|
+
ref: gh-pages
|
|
266
|
+
path: gh-pages-checkout # publish target
|
|
267
|
+
- uses: actions/checkout@v4
|
|
268
|
+
with:
|
|
269
|
+
repository: accord-research/rosetta
|
|
270
|
+
path: rosetta
|
|
271
|
+
|
|
272
|
+
- uses: astral-sh/setup-uv@v6
|
|
273
|
+
with:
|
|
274
|
+
enable-cache: true
|
|
275
|
+
|
|
276
|
+
- name: Install africas2s + rosetta
|
|
277
|
+
run: |
|
|
278
|
+
uv sync
|
|
279
|
+
uv pip install -e ./rosetta
|
|
280
|
+
|
|
281
|
+
- name: Configure nuthatch cache location
|
|
282
|
+
run: |
|
|
283
|
+
mkdir -p ~/.cache/nuthatch
|
|
284
|
+
cat > ~/.nuthatch.toml <<EOF
|
|
285
|
+
[tool.nuthatch]
|
|
286
|
+
filesystem = "~/.cache/nuthatch"
|
|
287
|
+
skipped_filesystems = ["gs://sheerwater-datalake/caches"]
|
|
288
|
+
EOF
|
|
289
|
+
|
|
290
|
+
- name: Restore nuthatch cache
|
|
291
|
+
uses: actions/cache@v4
|
|
292
|
+
with:
|
|
293
|
+
path: ~/.cache/nuthatch
|
|
294
|
+
# Share with the verify job's cache — render fetches the same CHIRPS
|
|
295
|
+
# climatology for the comparison-grid obs panel.
|
|
296
|
+
key: nuthatch-publish-${{ github.run_id }}-${{ hashFiles('rosetta/src/rosetta/catalog.yaml', 'rosetta/src/rosetta/normalize.py', 'rosetta/src/rosetta/fetch.py') }}
|
|
297
|
+
restore-keys: |
|
|
298
|
+
nuthatch-verify-
|
|
299
|
+
nuthatch-
|
|
300
|
+
|
|
301
|
+
- name: Write .cdsapirc
|
|
302
|
+
run: |
|
|
303
|
+
umask 077
|
|
304
|
+
cat > ~/.cdsapirc <<EOF
|
|
305
|
+
url: https://ecds.ecmwf.int/api
|
|
306
|
+
key: ${CDSAPI_KEY}
|
|
307
|
+
EOF
|
|
308
|
+
|
|
309
|
+
- name: Render dashboard into a build dir
|
|
310
|
+
run: |
|
|
311
|
+
uv run python -m scripts.s2s.render_dashboard \
|
|
312
|
+
--store-root issuance-store-checkout/issuances \
|
|
313
|
+
--verification-root issuance-store-checkout/verification \
|
|
314
|
+
--dashboard-root build/s2s \
|
|
315
|
+
--config scripts/s2s/s2s.yml
|
|
316
|
+
|
|
317
|
+
- name: Assemble gh-pages tree (hub + theme + s2s/)
|
|
318
|
+
run: |
|
|
319
|
+
uv run python -m scripts.s2s.publish_pages \
|
|
320
|
+
--site-src site \
|
|
321
|
+
--s2s-build build/s2s \
|
|
322
|
+
--pages-root gh-pages-checkout
|
|
323
|
+
|
|
324
|
+
- name: Commit + push gh-pages
|
|
325
|
+
working-directory: gh-pages-checkout
|
|
326
|
+
run: |
|
|
327
|
+
set -euo pipefail
|
|
328
|
+
git config user.name "github-actions[bot]"
|
|
329
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
330
|
+
git add index.html theme.css
|
|
331
|
+
[ -d s2s ] && git add -A s2s || true
|
|
332
|
+
if git diff --cached --quiet; then
|
|
333
|
+
echo "No site changes to commit"
|
|
334
|
+
exit 0
|
|
335
|
+
fi
|
|
336
|
+
git commit -m "pages: $(date -u +%Y-%m-%dT%H:%MZ)"
|
|
337
|
+
for attempt in 1 2 3 4 5; do
|
|
338
|
+
git pull --rebase origin gh-pages && git push origin gh-pages && exit 0
|
|
339
|
+
sleep $((attempt * 5))
|
|
340
|
+
done
|
|
341
|
+
exit 1
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
|
|
13
|
+
- uses: astral-sh/setup-uv@v6
|
|
14
|
+
with:
|
|
15
|
+
enable-cache: true
|
|
16
|
+
|
|
17
|
+
- name: Install dependencies
|
|
18
|
+
run: uv sync --extra dev
|
|
19
|
+
|
|
20
|
+
- name: Run tests
|
|
21
|
+
run: |
|
|
22
|
+
uv run pytest tests/ \
|
|
23
|
+
--ignore=tests/test_agreement.py \
|
|
24
|
+
--ignore=tests/test_corrdiff.py \
|
|
25
|
+
--ignore=tests/test_corrdiff_integration.py \
|
|
26
|
+
-m "not gpu and not integration" \
|
|
27
|
+
-v
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Python bytecode and caches
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.so
|
|
5
|
+
|
|
6
|
+
# Local virtual environments
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
|
|
10
|
+
# Test and tooling caches
|
|
11
|
+
.pytest_cache/
|
|
12
|
+
.mypy_cache/
|
|
13
|
+
.ruff_cache/
|
|
14
|
+
.coverage
|
|
15
|
+
.coverage.*
|
|
16
|
+
htmlcov/
|
|
17
|
+
|
|
18
|
+
# Notebook and editor noise
|
|
19
|
+
.ipynb_checkpoints/
|
|
20
|
+
.DS_Store
|
|
21
|
+
|
|
22
|
+
# Local outputs/artifacts
|
|
23
|
+
demo_cache/
|
|
24
|
+
examples/output/
|
|
25
|
+
*.png
|
|
26
|
+
*.nc
|
|
27
|
+
*.zarr/
|
|
28
|
+
|
|
29
|
+
# PyCPT working directories
|
|
30
|
+
tmp_iri_*/
|
|
31
|
+
|
|
32
|
+
# Scripts cache and output
|
|
33
|
+
scripts/cache/
|
|
34
|
+
scripts/output/
|
|
35
|
+
|
|
36
|
+
# CPT Fortran source (downloaded by scripts/DWN_CPT_SRC.sh)
|
|
37
|
+
CPT_SRC/
|
|
38
|
+
|
|
39
|
+
# S2S pipeline outputs (regenerated by run_issuance / verify / render_dashboard;
|
|
40
|
+
# published to an orphan branch or external bucket, not tracked on the code branch)
|
|
41
|
+
dashboard/
|
|
42
|
+
verification/
|
|
43
|
+
issuances/
|
|
44
|
+
|
|
45
|
+
# Local session / tooling artifacts (Claude Code, superpowers, ad-hoc dumps)
|
|
46
|
+
.superpowers/
|
|
47
|
+
docs/superpowers/
|
|
48
|
+
.old_claude_env
|
|
49
|
+
github-issues.json
|
|
50
|
+
|
|
51
|
+
# Credential files (never commit)
|
|
52
|
+
.cdsapirc
|
|
53
|
+
.ecmwfapirc
|
|
54
|
+
.netrc
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Agent instructions for africas2s
|
|
2
|
+
|
|
3
|
+
Instructions for any AI coding agent (Claude Code, Codex, OpenCode, etc.) working in this repository.
|
|
4
|
+
|
|
5
|
+
## Before you start
|
|
6
|
+
|
|
7
|
+
Read [`skills/africas2s/SKILL.md`](skills/africas2s/SKILL.md) before writing or modifying code that uses africas2s. It is the authoritative quick reference for the public API, data conventions, method/metric/strategy registries, and the statistical discipline rules (tercile leakage, grid rules, CV requirements), with deeper detail in `skills/africas2s/references/`. If your harness supports Agent Skills natively, load the skill instead of re-deriving the API from source.
|
|
8
|
+
|
|
9
|
+
## Keep the docs and skill in sync — this is a hard requirement
|
|
10
|
+
|
|
11
|
+
The skill is a snapshot of the source. Any change that alters observable behavior MUST update the matching documentation **in the same PR**:
|
|
12
|
+
|
|
13
|
+
| If you change... | You must update... |
|
|
14
|
+
|---|---|
|
|
15
|
+
| Public verb signatures/behavior (`downscale`, `optimize`, `train`, `calibrate`, `ensemble`, `skill`, `skill_compare`, `seasonal_mme`, `flex_forecast`, ...) or result dataclasses | `skills/africas2s/SKILL.md` + `skills/africas2s/references/api.md` |
|
|
16
|
+
| `Index` (`indices.py`): named indices, `REGIONS`, `transform`/`weights`/`baseline`, `reduce` signature | `skills/africas2s/references/api.md` |
|
|
17
|
+
| Analog selection (`analog.py`), scenario completion (`completion.py`), climate positioning (`climate.py`), scalar-series calibration (`series.py`), calendar/season-step utilities (`time.py`) | `skills/africas2s/references/analog-completion.md` (+ `SKILL.md` "Analog completion & climate positioning") |
|
|
18
|
+
| Methods, calibrators, ensemble strategies, CV schemes, `pool_ensembles` (`ensemble.py`), tercile combination/masking (`combine.py`) — add/remove/rename, parameter changes | `skills/africas2s/references/methods.md` |
|
|
19
|
+
| Metrics, tercile conversion, boundaries, significance tools (`metrics/significance.py`, `metrics/cross_validation.py`) | `skills/africas2s/references/metrics-and-terciles.md` |
|
|
20
|
+
| Plotting/reporting functions or export formats — incl. `plotting/maps.py`, `plotting/scenarios.py`, `plotting/forecasts.py` | `skills/africas2s/references/plotting-reporting.md` |
|
|
21
|
+
| Error messages, extras, environment requirements | `skills/africas2s/references/troubleshooting.md` |
|
|
22
|
+
| Rosetta integration / input data shapes | `skills/africas2s/SKILL.md` ("Getting data in") |
|
|
23
|
+
| Anything user-facing | `README.md` if it covers the topic |
|
|
24
|
+
|
|
25
|
+
Also update `skills/africas2s/examples/` if a change breaks or obsoletes an example. If you are unsure whether a change is documented, grep `skills/` and `README.md` for the function, method name, or parameter you touched — stale docs are treated as bugs.
|
|
26
|
+
|
|
27
|
+
## Repo conventions
|
|
28
|
+
|
|
29
|
+
- Package layout: `src/africas2s/` (import name `africas2s`, distribution `africas2s`). Python ≥ 3.10, `uv` for dependency management.
|
|
30
|
+
- Methods/metrics/strategies/calibrators are looked up by name via `africas2s/registry.py` — new capabilities register there rather than being hard-wired.
|
|
31
|
+
- Tests: bare `pytest` must stay fast (< 30 s) and green; markers `integration`, `agreement`, `gpu` gate slow/real-data suites. Coverage target > 85% on `src/africas2s`. New behavior needs tests.
|
|
32
|
+
- Statistical honesty is a design invariant: cross-validated outputs must never leak held-out years (use `to_tercile_cv`, nested CV safeguards). Do not weaken these paths for convenience.
|
|
33
|
+
- CCA numerics intentionally match CPT Fortran 17.8.3 — changes there must preserve parity (`scripts/reproduce.py`, `agreement` tests).
|
africas2s-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 accord-research
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|