From 8cb916537dbc4418f4ea52af1b17d42ba4fee6df Mon Sep 17 00:00:00 2001 From: Polichinl Date: Mon, 6 Apr 2026 13:00:44 +0200 Subject: [PATCH] feat(governance): add ADRs, CICs, risk register, and resolve easy-win risks Expand governance framework and address 10 risk register items identified during repo-assimilation, expert-code-review, and test-review audits. Governance additions: - ADR-004: activate evolution and stability rules (three-tier classification) - ADR-010: technical risk register as governance artifact - CICs: PackageScaffoldBuilder, IntegrationTestRunner - Standard: physical architecture (heuristic, not strict) - Risk register: 30 entries seeded from audits Code changes: - Remove warnings.filterwarnings("ignore") from all 74 main.py files (C-12) - Migrate white_mustang to new CLI pattern, remove wandb.login() (C-25) - Unify DARTS/HydraNet manager instantiation to single-variable pattern (C-24) - Delete placeholder models thousand_miles and thrift_shop (C-09) - Add ViewsMonth-to-date mapping comment in config_partitions.py (C-21) Test additions: - test_algorithm_coherence.py: validate algorithm-to-package mapping (C-04, C-08) - Extend test_cli_pattern.py to cover ensembles + add warning suppression check - Add 5 red-team tests to test_failure_modes.py (C-15, C-23) Risk register status: Open 17 | Mitigated 4 | Resolved 3 | Accepted 3 Co-Authored-By: Claude Opus 4.6 (1M context) --- apis/un_fao/main.py | 3 - docs/ADRs/001_ontology.md | 2 +- docs/ADRs/004_evolution.md | 121 ++++++ docs/ADRs/005_testing.md | 16 +- docs/ADRs/010_technical_risk_register.md | 90 +++++ docs/ADRs/README.md | 18 +- docs/CICs/IntegrationTestRunner.md | 172 ++++++++ docs/CICs/PackageScaffoldBuilder.md | 143 +++++++ docs/CICs/README.md | 2 + docs/INSTANTIATION_CHECKLIST.md | 25 +- .../physical_architecture_standard.md | 98 +++++ docs/validate_docs.sh | 19 +- ensembles/cruel_summer/main.py | 4 - ensembles/pink_ponyclub/main.py | 4 - ensembles/rude_boy/main.py | 4 - ensembles/skinny_love/main.py | 4 - ensembles/white_mustang/main.py | 20 +- extractors/ucdp_extractor/main.py | 3 - .../configs/config_partitions.py | 2 + models/adolecent_slob/main.py | 18 +- models/average_cmbaseline/main.py | 3 - models/average_pgmbaseline/main.py | 3 - models/bad_blood/main.py | 4 - models/bittersweet_symphony/main.py | 4 - models/black_ranger/main.py | 3 - models/blank_space/main.py | 4 - models/blue_ranger/main.py | 3 - models/bouncy_organ/main.py | 18 +- models/brown_cheese/main.py | 4 - models/car_radio/main.py | 4 - models/caring_fish/main.py | 4 - models/cheap_thrills/main.py | 4 - models/chunky_cat/main.py | 4 - models/cool_cat/main.py | 18 +- models/counting_stars/main.py | 4 - models/dancing_queen/main.py | 18 +- models/dark_paradise/main.py | 4 - models/demon_days/main.py | 4 - models/elastic_heart/main.py | 18 +- models/electric_relaxation/main.py | 4 - models/emerging_principles/main.py | 18 +- models/fancy_feline/main.py | 18 +- models/fast_car/main.py | 4 - models/fluorescent_adolescent/main.py | 4 - models/fourtieth_symphony/main.py | 4 - models/good_life/main.py | 18 +- models/good_riddance/main.py | 4 - models/green_ranger/main.py | 3 - models/green_squirrel/main.py | 4 - models/heat_waves/main.py | 18 +- models/heavy_rotation/main.py | 4 - models/high_hopes/main.py | 4 - models/hot_stream/main.py | 18 +- models/invisible_string/main.py | 4 - models/lavender_haze/main.py | 4 - models/little_lies/main.py | 4 - models/locf_cmbaseline/main.py | 3 - models/locf_pgmbaseline/main.py | 3 - models/lovely_creature/main.py | 4 - models/midnight_rain/main.py | 4 - models/national_anthem/main.py | 4 - models/new_rules/main.py | 18 +- models/novel_heuristics/main.py | 18 +- models/old_money/main.py | 4 - models/ominous_ox/main.py | 4 - models/orange_pasta/main.py | 4 - models/party_princess/main.py | 18 +- models/pink_ranger/main.py | 3 - models/plastic_beach/main.py | 4 - models/popular_monster/main.py | 4 - models/preliminary_directives/main.py | 18 +- models/purple_alien/main.py | 9 +- models/purple_haze/main.py | 3 - models/red_ranger/main.py | 3 - models/teen_spirit/main.py | 4 - models/teenage_dirtbag/main.py | 18 +- models/thousand_miles/README.md | 58 --- models/thrift_shop/README.md | 58 --- models/twin_flame/main.py | 4 - models/wild_rose/main.py | 4 - models/wildest_dream/main.py | 4 - models/wuthering_heights/main.py | 4 - models/yellow_pikachu/main.py | 4 - models/yellow_ranger/main.py | 3 - models/yellow_submarine/main.py | 4 - models/zero_cmbaseline/main.py | 3 - models/zero_pgmbaseline/main.py | 3 - postprocessors/un_fao/main.py | 3 - reports/technical_risk_register.md | 371 ++++++++++++++++++ tests/test_algorithm_coherence.py | 128 ++++++ tests/test_cli_pattern.py | 39 +- tests/test_failure_modes.py | 55 ++- 92 files changed, 1376 insertions(+), 552 deletions(-) create mode 100644 docs/ADRs/004_evolution.md create mode 100644 docs/ADRs/010_technical_risk_register.md create mode 100644 docs/CICs/IntegrationTestRunner.md create mode 100644 docs/CICs/PackageScaffoldBuilder.md create mode 100644 docs/standards/physical_architecture_standard.md delete mode 100644 models/thousand_miles/README.md delete mode 100644 models/thrift_shop/README.md create mode 100644 reports/technical_risk_register.md create mode 100644 tests/test_algorithm_coherence.py diff --git a/apis/un_fao/main.py b/apis/un_fao/main.py index e3004d7c..7f7eebf6 100644 --- a/apis/un_fao/main.py +++ b/apis/un_fao/main.py @@ -1,11 +1,8 @@ import wandb -import warnings from pathlib import Path from views_faoapi.managers.model import APIPathManager from views_faoapi.managers.api import FAOApiManager -warnings.filterwarnings("ignore") - try: model_path = APIPathManager(Path(__file__)) except FileNotFoundError as fnf_error: diff --git a/docs/ADRs/001_ontology.md b/docs/ADRs/001_ontology.md index e4f94799..638f953b 100644 --- a/docs/ADRs/001_ontology.md +++ b/docs/ADRs/001_ontology.md @@ -20,7 +20,7 @@ The repository recognizes the following ontological categories: ### Domain Entities | Category | Location | Description | |----------|----------|-------------| -| **Models** | `models/*/` | Individual forecasting model launchers (~66). Each is a thin `main.py` + config directory that delegates to an external architecture package. | +| **Models** | `models/*/` | Individual forecasting model launchers (66 active). Each is a thin `main.py` + config directory that delegates to an external architecture package. | | **Ensembles** | `ensembles/*/` | Ensemble aggregation launchers (5). Aggregate predictions from constituent models. | ### Configuration Entities diff --git a/docs/ADRs/004_evolution.md b/docs/ADRs/004_evolution.md new file mode 100644 index 00000000..16792f5a --- /dev/null +++ b/docs/ADRs/004_evolution.md @@ -0,0 +1,121 @@ + +# ADR-004: Rules for Evolution and Stability + +**Status:** Accepted +**Date:** 2026-04-05 +**Deciders:** Project maintainers +**Informed:** All contributors + +--- + +## Context + +The preceding ADRs establish: + +- **ADR-001:** the ontology of the repository (what exists) +- **ADR-002:** the topology of the repository (how components may relate) +- **ADR-003:** semantic authority (who owns meaning and how it is declared) + +Together, these decisions define the system's structure and semantics at a point in time. + +What they do **not** yet define is how the system is allowed to **change over time**: +- which components are expected to be stable +- which components may evolve freely +- what constitutes a breaking change +- when compatibility guarantees apply +- when a new ADR is required + +In views-models, these questions are now concrete: + +- 68 models and 5 ensembles share identical partition boundaries across 73 files; a boundary change is a coordinated multi-file update (Risk R1). +- External consumers (the VIEWS platform, UN FAO API) depend on `white_mustang` ensemble output; breaking changes have real downstream cost. +- The config key vocabulary (`regression_targets`, `prediction_format`, `rolling_origin_stride`) is enforced by tests; adding or renaming required keys is a breaking change to all 68+ models. +- Contributors regularly express uncertainty about what is safe to change (hyperparameters: freely; partition boundaries: never without coordination). + +Multiple trigger conditions from the original deferred ADR-004 template are now met. + +--- + +## Decision + +The repository adopts a three-tier stability classification for its components: + +### Tier 1 — Stable (change requires ADR or explicit team decision) + +| Component | Examples | Rationale | +|---|---|---| +| Partition boundaries | `(121, 444)`, `(445, 492)`, `(493, 540)` | Cross-model comparability depends on identical splits | +| Required config keys | `name`, `algorithm`, `level`, `steps`, `time_steps`, `deployment_status` | Enforced by `test_config_completeness.py`; adding/removing breaks all models | +| Config file set | The 6 config files per model | Enforced by `test_model_structure.py`; scaffold builder generates this set | +| CLI argument contract | `-r`, `-t`, `-e`, `-f`, `--sweep` | All `run.sh` and integration tests depend on this interface | +| Deployment status vocabulary | `shadow`, `deployed`, `baseline`, `deprecated` | Enforced by test; production gating depends on it | + +### Tier 2 — Conventional (change requires updating all models + tests) + +| Component | Examples | Rationale | +|---|---|---| +| Model naming convention | `adjective_noun` lowercase | Enforced by `test_model_structure.py`; catalog scripts depend on pattern | +| Directory structure | `configs/`, `artifacts/`, `data/`, `main.py`, `run.sh` | Enforced by tests; scaffold builder generates this layout | +| CLI import pattern | `from views_pipeline_core.cli import ForecastingModelArgs` | Enforced by `test_cli_pattern.py` | +| Ensemble dependency declarations | `config_meta["models"]` list | Enforced by `test_ensemble_configs.py` | + +### Tier 3 — Volatile (changed freely by model owners) + +| Component | Examples | Rationale | +|---|---|---| +| Hyperparameters | All keys in `config_hyperparameters.py` beyond `steps`/`time_steps` | Algorithm-specific; model owner's domain | +| Querysets | Feature selection and transformation chains in `config_queryset.py` | Model owner's domain | +| W&B experiment tracking | Run names, tags, logging frequency | Operational convenience | +| Model-specific README content | Beyond scaffold-generated sections | Documentation convenience | + +--- + +## Rationale + +The three-tier model makes the cost of change explicit: + +- **Stable** components have high coordination cost and downstream impact. Changes require an ADR or explicit team decision, plus updates to all affected models and tests. +- **Conventional** components have moderate coordination cost. Changes propagate across the model zoo but don't affect external consumers. +- **Volatile** components are model-local. No coordination required. + +This classification reflects the existing reality (tests already enforce Stable and Conventional tiers) while making the rules discoverable for contributors. + +--- + +## Consequences + +### Positive +- Contributors can immediately determine whether a change is safe to make unilaterally +- The cost of adding new required config keys is made explicit before the change is attempted +- Partition boundary changes are recognized as architectural events, not routine updates + +### Negative +- Stable components resist change even when change is desirable — the coordination cost is real +- The 73-file partition duplication (intentional per ADR-002) amplifies the cost of Stable-tier changes +- Model owners may be tempted to treat Conventional components as Volatile; tests are the enforcement mechanism + +--- + +## Implementation Notes + +- Stability tiers are enforced primarily by the test suite, not by tooling +- The integration test runner (`run_integration_tests.sh`) provides behavioral verification but is not in CI; Stable-tier changes should include an integration test run +- ADR-001 already defines a stability classification consistent with these tiers; this ADR makes the rules actionable + +--- + +## Open Questions + +- Should partition boundary changes require a formal migration tool (updating all 73 files atomically)? +- Should there be a deprecation protocol for removing models (currently only `electric_relaxation` is deprecated)? +- Should Tier 2 changes require a PR review from a specific set of maintainers? + +--- + +## References + +- [ADR-001](001_ontology.md) — Ontology stability levels +- [ADR-002](002_topology.md) — Self-contained config files (why duplication is intentional) +- [ADR-003](003_authority.md) — Authority of declarations +- [ADR-005](005_testing.md) — Testing enforces tiers +- [ADR-009](009_boundary_contracts.md) — Boundary contracts define the Stable-tier interface diff --git a/docs/ADRs/005_testing.md b/docs/ADRs/005_testing.md index f6f83f81..0a793a85 100644 --- a/docs/ADRs/005_testing.md +++ b/docs/ADRs/005_testing.md @@ -25,12 +25,12 @@ We adopt a three-team testing taxonomy: |------|---------|----------------------| | **Green** (Correctness) | Verify the system works as intended | `test_config_completeness.py` — required keys exist, values are valid | | **Beige** (Convention) | Catch configuration drift and convention violations | `test_model_structure.py` — naming, file presence; `test_config_partitions.py` — delegation to shared module; `test_cli_pattern.py` — CLI import consistency | -| **Red** (Adversarial) | Expose failure modes by testing edge cases | Not yet implemented — future work | +| **Red** (Adversarial) | Expose failure modes by testing edge cases | `test_failure_modes.py` — config loading error paths | ### Test Design Principles 1. **Tests must run without ML dependencies** — Tests parse source code and use `importlib.util` to load config modules, avoiding dependency on `views_pipeline_core`, `ingester3`, or algorithm packages. -2. **Tests are parametrized over all models** — Every test runs against all ~66 models, catching drift immediately. +2. **Tests are parametrized over all models** — Every test runs against all 66 models, catching drift immediately. 3. **Tests run fast** — The full suite completes in ~2 seconds. ### Current Test Suite @@ -42,6 +42,10 @@ We adopt a three-team testing taxonomy: | `tests/test_model_structure.py` | Beige | Naming convention, required files, config directory structure | | `tests/test_cli_pattern.py` | Beige | New CLI import pattern, no explicit `wandb.login()` | | `tests/test_catalogs.py` | Green | No `exec()` usage, markdown generation correctness | +| `tests/test_ensemble_configs.py` | Green | Ensemble structure, required keys, constituent model existence and level consistency | +| `tests/test_darts_reproducibility.py` | Green | DARTS reproducibility gate parameter completeness (skipped without `views_r2darts2`) | +| `tests/test_algorithm_coherence.py` | Beige | Algorithm-to-package mapping, requirements.txt consistency with main.py imports | +| `tests/test_failure_modes.py` | Red | Config loading error paths: syntax errors, missing functions, non-existent files | ### Test Requirements for Changes @@ -53,11 +57,11 @@ We adopt a three-team testing taxonomy: ## Known Gaps -- No red-team (adversarial) tests yet - Catalog generation function tests require `views_pipeline_core` (skipped in most dev environments) -- No cross-validation between `config_meta.algorithm` and `main.py` manager import -- No ensemble config tests -- Tests are not wired into CI (`.github/workflows/`) +- DARTS reproducibility tests require `views_r2darts2` (skipped without it); no equivalent for stepshifter or baseline +- Tests are not wired into CI (`.github/workflows/`) — see Risk Register C-03 +- No static validation of queryset correctness — see Risk Register C-02 +- Red-team coverage is limited to config loading infrastructure; no adversarial tests for runtime behavior --- diff --git a/docs/ADRs/010_technical_risk_register.md b/docs/ADRs/010_technical_risk_register.md new file mode 100644 index 00000000..92f27e49 --- /dev/null +++ b/docs/ADRs/010_technical_risk_register.md @@ -0,0 +1,90 @@ + +# ADR-010: Technical Risk Register as a Governance Artifact + +**Status:** Accepted +**Date:** 2026-04-05 +**Deciders:** Project maintainers +**Informed:** All contributors + +--- + +## Context + +Repository assimilation (April 2026) identified 11 structural risks in views-models, ranging from partition coordination fragility (high severity) to untested scaffold builders (medium severity). These risks are architectural — they emerge from design decisions, not from bugs in any single file. + +Without a persistent, structured register, risks are: +- Discovered during audits but forgotten between them +- Discussed informally but not tracked to resolution +- Rediscovered by new contributors who lack context on prior analysis + +--- + +## Decision + +The repository maintains a **Technical Risk Register** at `reports/technical_risk_register.md`. + +### Concern Format + +Each entry uses this format: + +| Field | Description | +|---|---| +| **ID** | `C-xx` for concerns, `D-xx` for disagreements | +| **Tier** | 1 (critical) through 4 (informational) | +| **Title** | Short description | +| **Trigger** | The specific circumstance under which the risk becomes actionable | +| **Source** | How this concern was identified (e.g., repo-assimilation, expert review, incident) | +| **Status** | Open, Mitigated, Accepted, Resolved | +| **Notes** | Additional context, references to related ADRs or PRs | + +### Tier Definitions + +| Tier | Meaning | Response | +|---|---|---| +| **1** | Critical structural risk; failure would affect multiple models or external consumers | Must be addressed or explicitly accepted with rationale | +| **2** | Significant risk; failure would affect a class of models or a governance mechanism | Should be addressed in the next development cycle | +| **3** | Moderate risk; failure would cause inconvenience or require manual intervention | Address when adjacent work touches the area | +| **4** | Informational; noted for awareness | No action required unless promoted | + +### When Entries Are Added + +Concerns are opened during: +- Repository assimilation audits +- Expert code reviews +- Tech debt cleanup sessions +- Falsification audits +- Incident post-mortems + +### When Entries Are Closed + +Concerns are resolved when: +- The underlying risk is eliminated (code change + test) +- The risk is explicitly accepted with rationale (documented in Notes) +- The risk is superseded by a different concern + +--- + +## Rationale + +A structured register makes risks visible, trackable, and reviewable. It prevents the pattern of "we know about that problem" without any record of what "that problem" actually is. + +--- + +## Consequences + +### Positive +- Risks persist across conversations and contributors +- New contributors can quickly understand known architectural weaknesses +- Audit findings have a concrete landing place + +### Negative +- Register requires maintenance; stale entries reduce trust +- Risk of "concern inflation" if trivial items are registered at high tiers + +--- + +## References + +- `reports/technical_risk_register.md` — the register itself +- [ADR-004](004_evolution.md) — Evolution rules that influence risk severity +- [ADR-005](005_testing.md) — Testing gaps are a common risk source diff --git a/docs/ADRs/README.md b/docs/ADRs/README.md index c3408dc7..1015edd8 100644 --- a/docs/ADRs/README.md +++ b/docs/ADRs/README.md @@ -13,7 +13,7 @@ These ADRs define system philosophy and governance: - **[ADR-001](001_ontology.md)** — Ontology of the Repository - **[ADR-002](002_topology.md)** — Topology and Dependency Rules - **[ADR-003](003_authority.md)** — Authority of Declarations Over Inference -- **ADR-004** — Evolution and Stability *(Deferred)* +- **[ADR-004](004_evolution.md)** — Rules for Evolution and Stability - **[ADR-005](005_testing.md)** — Testing as Mandatory Critical Infrastructure - **[ADR-006](006_intent_contracts.md)** — Intent Contracts for Non-Trivial Classes - **[ADR-007](007_silicon_agents.md)** — Silicon-Based Agents as Untrusted Contributors @@ -27,23 +27,27 @@ These ADRs define system philosophy and governance: - **Ontology (001)** defines what exists. - **Topology (002)** defines structural direction. - **Authority (003)** defines who owns meaning. +- **Evolution (004)** defines stability tiers and change rules. - **Boundary Contracts (009)** define interaction rules. - **Observability (008)** enforces failure semantics. - **Testing (005)** verifies system integrity. - **Intent Contracts (006)** bind class-level behavior. - **Automation Governance (007)** constrains silicon-based agents. +- **Risk Register (010)** tracks structural risks. --- ## Project-Specific ADRs (010+) -No project-specific ADRs have been written yet. Candidates: +- **[ADR-010](010_technical_risk_register.md)** — Technical Risk Register as a Governance Artifact -- **ADR-010** — Partition Boundary Semantics (why 121-444/445-492/493-540) -- **ADR-011** — CM-before-PGM Ensemble Ordering -- **ADR-012** — Config Key Evolution Policy (how to add new required keys) -- **ADR-013** — Model Naming Convention and Governance -- **ADR-014** — Conda Environment Sharing via run.sh +Candidates for future ADRs: + +- Partition Boundary Semantics — ViewsMonth 121 = Jan 1990, 444 = Dec 2016, 492 = Dec 2020, 540 = Dec 2024; rationale for these split points is undocumented (C-21) +- CM-before-PGM Ensemble Ordering +- Config Key Evolution Policy (how to add new required keys) +- Model Naming Convention and Governance +- Conda Environment Sharing via run.sh --- diff --git a/docs/CICs/IntegrationTestRunner.md b/docs/CICs/IntegrationTestRunner.md new file mode 100644 index 00000000..736a9814 --- /dev/null +++ b/docs/CICs/IntegrationTestRunner.md @@ -0,0 +1,172 @@ + +# Class Intent Contract: IntegrationTestRunner + +**Status:** Active +**Owner:** Project maintainers +**Last reviewed:** 2026-04-05 +**Related ADRs:** ADR-004, ADR-005, ADR-008, ADR-009 + +--- + +## 1. Purpose + +`run_integration_tests.sh` is the only mechanism that tests actual model training and evaluation in views-models. It trains and evaluates each selected model on calibration and/or validation partitions using a shared conda environment, logs results per model, and produces a pass/fail summary. It never aborts on individual model failure — every model gets its turn. + +--- + +## 2. Non-Goals (Explicit Exclusions) + +- Does **not** run forecasting partitions (only calibration and validation) +- Does **not** validate model output quality or prediction accuracy — only that training and evaluation complete without error +- Does **not** replace the pytest structural test suite; the two are complementary +- Does **not** manage or create conda environments — it activates an existing one +- Does **not** modify any model code, configs, or artifacts +- Does **not** run in CI — it is a local, manual tool + +--- + +## 3. Responsibilities and Guarantees + +- Guarantees that every matched model is executed for every requested partition, regardless of prior failures (no early abort) +- Guarantees crash isolation: each model runs in its own subshell (`bash -c "..."`) +- Guarantees per-model timeout enforcement via `timeout` command (default: 1800 seconds) +- Guarantees that results are classified as exactly one of: `PASS`, `FAIL(exit_code)`, `TIMEOUT` +- Guarantees that per-model stdout/stderr is captured to `$LOG_DIR/$partition/$model.log` +- Guarantees a structured summary log at `$LOG_DIR/summary.log` +- Guarantees exit code 0 only if all runs pass; exit code 1 if any fail or timeout + +--- + +## 4. Inputs and Assumptions + +### CLI Arguments + +| Flag | Default | Description | +|---|---|---| +| `--env` | `views_pipeline` | Conda environment name to activate | +| `--models` | (all) | Space-separated model names to include | +| `--level` | (all) | Filter by level: `cm` or `pgm` | +| `--library` | (all) | Filter by algorithm library: `baseline`, `stepshifter`, `r2darts2`, `hydranet` | +| `--exclude` | `purple_alien` | Space-separated model names to skip | +| `--partitions` | `calibration validation` | Space-separated partition names | +| `--timeout` | `1800` | Seconds per model per partition | + +### Assumptions + +- The named conda environment exists and has all model dependencies installed +- Each model directory has `main.py` accepting `-r -t -e` arguments +- `--level` filtering requires `config_meta.py` to be loadable by Python 3 with `importlib` +- `--library` filtering requires `requirements.txt` to contain the library name (e.g., `views-baseline`) +- Model discovery uses `main.py` existence as the inclusion criterion + +--- + +## 5. Outputs and Side Effects + +- **Log directory:** `logs/integration_test_$TIMESTAMP/` with per-partition subdirectories +- **Per-model logs:** `$partition/$model.log` — complete stdout/stderr from training + evaluation +- **Summary log:** `summary.log` — tabular pass/fail results +- **Console output:** Colorized progress and summary table +- **Exit code:** 0 (all pass) or 1 (any fail/timeout) +- **Side effects on model directories:** Training produces artifacts in `models/$model/artifacts/` and W&B logs in `models/$model/wandb/` — these are normal training side effects, not introduced by the test runner + +--- + +## 6. Failure Modes and Loudness + +| Condition | Behavior | +|---|---| +| Model training crashes | Captured in log; classified as `FAIL(exit_code)`; script continues | +| Model exceeds timeout | Killed by `timeout`; classified as `TIMEOUT`; script continues | +| No models match filters | Prints "No models found to test"; exits 1 | +| Conda environment doesn't exist | Activation fails inside subshell; model classified as `FAIL` | +| `config_meta.py` unloadable (during `--level` filter) | Model silently excluded from filtered set (Python stderr to /dev/null) | +| Unknown CLI flag | Prints error; exits 1 | + +The runner itself never fails silently. Individual model failures are captured and reported, not swallowed. + +--- + +## 7. Boundaries and Interactions + +| Interacts With | Direction | Nature | +|---|---|---| +| `models/*/main.py` | Invokes | Subprocess via `python main.py -r $partition -t -e` | +| `models/*/configs/config_meta.py` | Reads (for `--level` filter) | `importlib.util` from Python | +| `models/*/requirements.txt` | Reads (for `--library` filter) | `grep` for package name | +| Conda | Activates | `conda activate $ENV` in subshell | +| `logs/` | Writes | Timestamped log directories | + +Does **not** interact with: ensemble directories, APIs, extractors, postprocessors, or the pytest test suite. + +--- + +## 8. Examples of Correct Usage + +```bash +# Run all models on both partitions +bash run_integration_tests.sh + +# Run only country-month stepshifter models on calibration +bash run_integration_tests.sh --level cm --library stepshifter --partitions "calibration" + +# Run specific models with 60-minute timeout +bash run_integration_tests.sh --models "counting_stars bad_blood" --timeout 3600 + +# Use a different conda environment +bash run_integration_tests.sh --env views_r2darts2 +``` + +--- + +## 9. Examples of Incorrect Usage + +```bash +# Wrong: expecting this to run forecasting +bash run_integration_tests.sh --partitions "forecasting" +# main.py will attempt to forecast, but the runner is designed for +# calibration/validation where ground truth exists + +# Wrong: assuming --exclude appends to defaults +bash run_integration_tests.sh --exclude "new_model" +# This REPLACES the default exclusion (purple_alien), not appends to it + +# Wrong: expecting this to run in CI +# The runner takes hours and requires a GPU-capable environment; +# it is not wired into .github/workflows/ +``` + +--- + +## 10. Test Alignment + +- **No tests exist** for the integration test runner itself. +- The runner IS the test mechanism for behavioral (green-team) model validation. +- ADR-005 documents it as complementary to the pytest structural suite. +- Known gap: not in CI (Risk Register C-03). + +--- + +## 11. Evolution Notes + +- If integrated into CI (even partially — e.g., a subset of models), the timeout defaults and filtering logic would need revisiting. +- The `--level` filter shells out to Python to load `config_meta.py` — this is fragile if `config_meta.py` gains new dependencies. +- The `--exclude` flag replaces rather than appends; this is a common source of user surprise and a candidate for change. + +--- + +## 12. Known Deviations + +- **Not in CI:** The only behavioral test mechanism is manual (Risk Register C-03). A model can be merged broken. +- **`--level` filter silences errors:** `2>/dev/null` on the Python subprocess means if `config_meta.py` is broken, the model is silently excluded from `--level`-filtered runs rather than flagged. +- **`--exclude` replaces defaults:** Documented in `--help` but surprising — passing `--exclude "foo"` removes the default `purple_alien` exclusion. +- **No ensemble coverage:** The runner only discovers models in `models/`; ensembles in `ensembles/` are not tested by this mechanism. + +--- + +## End of Contract + +This document defines the **intended meaning** of `run_integration_tests.sh`. + +Changes to behavior that violate this intent are bugs. +Changes to intent must update this contract. diff --git a/docs/CICs/PackageScaffoldBuilder.md b/docs/CICs/PackageScaffoldBuilder.md new file mode 100644 index 00000000..53721c9b --- /dev/null +++ b/docs/CICs/PackageScaffoldBuilder.md @@ -0,0 +1,143 @@ + +# Class Intent Contract: PackageScaffoldBuilder + +**Status:** Active +**Owner:** Project maintainers +**Last reviewed:** 2026-04-05 +**Related ADRs:** ADR-001, ADR-002, ADR-006, ADR-008 + +--- + +## 1. Purpose + +`PackageScaffoldBuilder` creates the directory structure and initial files for a new model architecture package (e.g., `views-stepshifter`). It delegates package creation and validation to `views_pipeline_core.managers.package.PackageManager` and adds supplementary files (`.gitignore`, example manager script). + +--- + +## 2. Non-Goals (Explicit Exclusions) + +- Does **not** implement any algorithm logic; it generates the skeleton only +- Does **not** validate that the generated package is importable or functional +- Does **not** register the package with PyPI, GitHub, or any package index +- Does **not** create model directories — that is `ModelScaffoldBuilder`'s responsibility +- Does **not** manage conda environments or dependencies + +--- + +## 3. Responsibilities and Guarantees + +- Guarantees that `PackageManager.create_views_package()` and `PackageManager.validate_views_package()` are called in sequence +- Guarantees that errors from `create_views_package()` or `validate_views_package()` are logged at ERROR level and re-raised (fail-loud) +- Guarantees that `build_package_directories()` creates the manager subdirectory if it does not exist +- Guarantees that `build_package_scripts()` generates an `example_manager.py` from the `views_pipeline_core` template +- Guarantees that `add_gitignore()` generates a `.gitignore` from the `views_pipeline_core` template + +--- + +## 4. Inputs and Assumptions + +- **Constructor:** Receives a `PackageManager` instance (from `views_pipeline_core`) +- **Assumption:** The `PackageManager` is initialized with a valid path and `validate=False` (validation happens in `build_package_scaffold()`) +- **Assumption:** `views_pipeline_core.templates.package` templates (`template_example_manager`, `template_gitignore`) are installed and accessible + +### Interactive CLI (when run as `__main__`): + +- Prompts for `package_name` — validated by `PackageManager.validate_package_name()` (format: `views-packagename`, lowercase) +- Prompts for optional `package_path` — defaults to `cwd / package_name`; validated that parent directory exists + +--- + +## 5. Outputs and Side Effects + +- **Directories created:** Package root, manager subdirectory +- **Files created:** `example_manager.py`, `.gitignore`, plus whatever `PackageManager.create_views_package()` generates internally +- **Logging:** INFO-level log on successful scaffold creation; ERROR-level on failure +- **No return values:** All methods return `None` + +--- + +## 6. Failure Modes and Loudness + +| Condition | Behavior | +|---|---| +| `create_views_package()` raises | Logged at ERROR, re-raised — **fail loud** | +| `validate_views_package()` raises | Logged at ERROR, re-raised — **fail loud** | +| Invalid package name (interactive) | Loops until valid input provided | +| Invalid base directory (interactive) | Loops until valid path provided | +| Template files missing | Raises from `views_pipeline_core` — not caught here | + +All structural failures propagate. No silent degradation. + +--- + +## 7. Boundaries and Interactions + +| Interacts With | Direction | Nature | +|---|---|---| +| `views_pipeline_core.managers.package.PackageManager` | Delegates to | Package creation and validation | +| `views_pipeline_core.templates.package.template_example_manager` | Calls | File generation | +| `views_pipeline_core.templates.package.template_gitignore` | Calls | File generation | + +Does **not** interact with: model directories, config files, conda environments, or any other scaffold builder. + +--- + +## 8. Examples of Correct Usage + +```python +from views_pipeline_core.managers.package import PackageManager + +pm = PackageManager("/path/to/views-newpackage", validate=False) +builder = PackageScaffoldBuilder(pm) +builder.build_package_scaffold() +builder.build_package_directories() +builder.build_package_scripts() +builder.add_gitignore() +``` + +--- + +## 9. Examples of Incorrect Usage + +```python +# Wrong: using PackageScaffoldBuilder to create a model directory +builder = PackageScaffoldBuilder(some_package_manager) +builder.build_package_scaffold() +# This creates a *package* skeleton, not a model directory + +# Wrong: calling build_package_scripts() before build_package_directories() +# The manager/ subdirectory may not exist yet +builder.build_package_scripts() # may fail if directory missing +``` + +--- + +## 10. Test Alignment + +- **No tests exist** for `PackageScaffoldBuilder`. This is a known gap (Risk Register C-07). +- A green-team test should verify: scaffold output creates expected directories and files. +- A beige-team test should verify: generated package name matches `views-*` convention. + +--- + +## 11. Evolution Notes + +- If `views_pipeline_core` templates change, scaffold output changes silently — no regression test catches this. +- The class is thin (~30 lines of logic); most complexity lives in `PackageManager`. If `PackageManager` evolves, this class may need updates. + +--- + +## 12. Known Deviations + +- **No tests:** The scaffold builder is entirely untested (Risk Register C-07). A `views_pipeline_core` template change could silently break newly scaffolded packages. +- **No assessment method:** Unlike `ModelScaffoldBuilder`, this class has no `assess_*` method to validate what it created. +- **Execution order dependency:** `build_package_scripts()` assumes `build_package_directories()` has already run, but this ordering is not enforced or documented in code. + +--- + +## End of Contract + +This document defines the **intended meaning** of `PackageScaffoldBuilder`. + +Changes to behavior that violate this intent are bugs. +Changes to intent must update this contract. diff --git a/docs/CICs/README.md b/docs/CICs/README.md index 6e7c56ac..5c70d060 100644 --- a/docs/CICs/README.md +++ b/docs/CICs/README.md @@ -16,6 +16,8 @@ An Intent Contract is a human-readable, unambiguous declaration of: - `ModelScaffoldBuilder.md` - `EnsembleScaffoldBuilder.md` - `CatalogExtractor.md` +- `PackageScaffoldBuilder.md` +- `IntegrationTestRunner.md` --- diff --git a/docs/INSTANTIATION_CHECKLIST.md b/docs/INSTANTIATION_CHECKLIST.md index 74cece99..68ddd33d 100644 --- a/docs/INSTANTIATION_CHECKLIST.md +++ b/docs/INSTANTIATION_CHECKLIST.md @@ -1,6 +1,6 @@ # Instantiation Checklist -Completed during initial adoption of governance docs for views-models. +Completed during initial adoption (2026-03-15) and updated (2026-04-05) with governance expansion. --- @@ -8,19 +8,20 @@ Completed during initial adoption of governance docs for views-models. ### All adopted ADRs - [x] Update Status from template to Accepted -- [x] Fill in Date (2026-03-15), Deciders (Simon), Informed (All contributors) +- [x] Fill in Date, Deciders (Project maintainers), Informed (All contributors) ### Per-ADR adaptation notes - [x] **ADR-000:** Path set to `docs/ADRs/` -- [x] **ADR-001:** Ontology categories mapped to views-models entities (models, configs, ensembles, tooling, etc.) +- [x] **ADR-001:** Ontology categories mapped to views-models entities (68 models, 5 ensembles, configs, tooling, etc.) - [x] **ADR-002:** Dependency direction defined (models → external packages, self-contained configs) - [x] **ADR-003:** Fail-loud examples adapted to config validation and partition consistency -- [x] **ADR-004:** Deferred (evolution/stability rules not yet needed) +- [x] **ADR-004:** Activated (2026-04-05) — three-tier stability classification (Stable/Conventional/Volatile) - [x] **ADR-005:** Testing taxonomy mapped to existing test suite (green/beige categories) -- [x] **ADR-006:** Intent contracts identified for 4 entities +- [x] **ADR-006:** Intent contracts identified for 5 entities - [x] **ADR-007:** Silicon agent constraints adapted for bulk config operations - [x] **ADR-008:** Observability grounded in current logging patterns and known deviations - [x] **ADR-009:** Boundary contracts mapped to config validation tests +- [x] **ADR-010:** Technical risk register ADR created, register seeded with 11 risks from repo-assimilation --- @@ -29,8 +30,9 @@ Completed during initial adoption of governance docs for views-models. - [x] Replace placeholder active contracts list in `CICs/README.md` - [x] Create `ModelScaffoldBuilder.md` - [x] Create `EnsembleScaffoldBuilder.md` -- [x] Create `CommonPartitions.md` - [x] Create `CatalogExtractor.md` +- [x] Create `PackageScaffoldBuilder.md` (2026-04-05) +- [x] Create `IntegrationTestRunner.md` (2026-04-05) --- @@ -45,7 +47,14 @@ Completed during initial adoption of governance docs for views-models. ## Standards - [x] Adapt `logging_and_observability_standard.md` to current patterns and known deviations -- [ ] Physical architecture standard — skipped (not applicable to this repo's architecture) +- [x] Adapt `physical_architecture_standard.md` as default heuristic (not strict enforcement) (2026-04-05) + +--- + +## Risk Register + +- [x] Create `reports/technical_risk_register.md` seeded with 11 concerns from repo-assimilation (2026-04-05) +- [x] Create governing ADR-010 (2026-04-05) --- @@ -54,4 +63,4 @@ Completed during initial adoption of governance docs for views-models. - [x] No files still have Status `--template--` - [x] No phantom references to non-existent files - [x] All cross-ADR references resolve correctly -- [ ] Run `validate_docs.sh` to check internal consistency +- [x] Run `validate_docs.sh` to check internal consistency diff --git a/docs/standards/physical_architecture_standard.md b/docs/standards/physical_architecture_standard.md new file mode 100644 index 00000000..a0a86dca --- /dev/null +++ b/docs/standards/physical_architecture_standard.md @@ -0,0 +1,98 @@ +# Physical Architecture Standard + +**Governing ADR:** ADR-002 (Topology and Dependency Rules) +**Status:** Active (heuristic, not strict) +**Last reviewed:** 2026-04-05 + +--- + +## Scope + +This standard defines the **default heuristic** for file and directory organization in views-models. It is the ruling convention in the absence of a good argument for locality. When locality provides a meaningful benefit (e.g., keeping a model's configs together with its entrypoint), deviation is acceptable and does not require an ADR. + +--- + +## 1. The 1-Class-1-File Heuristic + +**Every non-trivial class should live in its own file named after the class in `snake_case`.** + +- **Preferred:** `PackageScaffoldBuilder` lives in `build_package_scaffold.py` +- **Acceptable deviation:** Module-level functions (e.g., `extract_models()` in `create_catalogs.py`) that are not classes — the 1-class-1-file rule does not apply to pure functions. +- **Exception:** Trivial data containers or closely related helpers may coexist in the same file. + +### Current State in views-models + +The repo is primarily composed of: +- **Config files:** Pure functions returning dicts (no classes) — standard does not apply +- **Model entrypoints:** `main.py` files with no class definitions — standard does not apply +- **Scaffold builders:** One class per file (`build_model_scaffold.py`, `build_ensemble_scaffold.py`, `build_package_scaffold.py`) — **compliant** +- **Catalog scripts:** Module-level functions — standard does not apply + +The 1-class-1-file heuristic is naturally satisfied because most logic in this repository lives in external packages, not in local classes. + +--- + +## 2. Directory Ontology + +Files must be located in directories that match their **functional category**. + +| Directory | Category | Contents | +|---|---|---| +| `models/` | Domain entities | Self-contained model directories (configs, entrypoint, artifacts) | +| `ensembles/` | Domain entities | Self-contained ensemble directories | +| `apis/` | Data pipeline | API connectors | +| `extractors/` | Data pipeline | Data extraction modules | +| `postprocessors/` | Data pipeline | Output post-processing | +| `tests/` | Verification | Pytest modules and conftest | +| `docs/` | Governance | ADRs, CICs, protocols, standards | +| `envs/` | Infrastructure | Conda environments (local, not tracked) | +| `.github/workflows/` | Infrastructure | CI/CD pipelines | +| `reports/` | Observability | Risk register, generated reports | +| `logs/` | Observability | Integration test logs | +| Root (`*.py`) | Tooling | Scaffold builders, catalog generators | + +### Locality Exception + +Model directories (`models/{name}/`) bundle configs, data, artifacts, logs, and entrypoints together. This violates strict ontological separation (configs aren't in a top-level `configs/` directory) but is the correct design — models are independently deployable units, and locality is the stronger organizing principle here. This is explicitly sanctioned by ADR-002. + +--- + +## 3. Symmetrical Hubs + +When heterogeneous logic of the same kind must be consolidated, use a symmetrical hub file. + +### Current Hubs in views-models + +This repo has minimal need for symmetrical hubs because most logic lives in external packages. The closest analogue is: +- `tests/conftest.py` — consolidates all test fixtures and parametrization logic + +### When to Create a Hub + +If this repository accumulates: +- Multiple custom exceptions → create `utils/exceptions.py` +- Multiple shared helpers → create `utils/helpers.py` +- Multiple shared data transforms → create `utils/transforms.py` + +Until then, no hub files are needed. + +--- + +## 4. Import Conventions + +- **Explicit imports:** Avoid `from module import *` +- **No circular dependencies:** Follow ADR-002's dependency direction +- **Config files are import-isolated:** Config files (except `config_queryset.py`) must not import from other repo modules + +These conventions are already enforced by ADR-002 and tested by `test_cli_pattern.py`. + +--- + +## 5. Enforcement + +This standard is a **heuristic, not a gate**. It is not enforced by CI or automated tooling. + +- During code review: prefer the standard unless the contributor provides a good argument for locality +- During scaffold generation: the standard is embedded in `build_model_scaffold.py` templates +- During repo assimilation: note deviations as informational, not defects + +The standard exists to prevent drift toward disorganization, not to reject legitimate locality-driven decisions. diff --git a/docs/validate_docs.sh b/docs/validate_docs.sh index 578527d3..15351f90 100755 --- a/docs/validate_docs.sh +++ b/docs/validate_docs.sh @@ -55,10 +55,6 @@ while IFS= read -r ref; do file=$(echo "$ref" | cut -d: -f1) adr_num=$(echo "$ref" | grep -oP 'ADR-00\K[0-9]' | head -1) if [ -n "$adr_num" ]; then - # Skip ADR-004 (intentionally deferred) - if [ "$adr_num" = "4" ]; then - continue - fi match_count=$(find ADRs -name "00${adr_num}_*.md" 2>/dev/null | wc -l) if [ "$match_count" -eq 0 ]; then echo " ERROR: $file references ADR-00${adr_num} but no matching file found" @@ -67,6 +63,21 @@ while IFS= read -r ref; do fi done < <(grep -rn 'ADR-00[0-9]' --include='*.md' . 2>/dev/null || true) +# 3b. Cross-ADR reference integrity (project-specific: 010+) +echo "--- Checking cross-ADR references (project-specific: 010+) ---" +while IFS= read -r ref; do + [[ -z "$ref" ]] && continue + file=$(echo "$ref" | cut -d: -f1) + adr_num=$(echo "$ref" | grep -oP 'ADR-0\K[0-9]{2}' | head -1) + if [ -n "$adr_num" ] && [ "$adr_num" -ge 10 ]; then + match_count=$(find ADRs -name "0${adr_num}_*.md" 2>/dev/null | wc -l) + if [ "$match_count" -eq 0 ]; then + echo " ERROR: $file references ADR-0${adr_num} but no matching file found" + errors=$((errors + 1)) + fi + fi +done < <(grep -rn 'ADR-0[0-9][0-9]' --include='*.md' . 2>/dev/null || true) + # 4. Check that referenced protocol files exist echo "--- Checking protocol file references ---" while IFS= read -r ref; do diff --git a/ensembles/cruel_summer/main.py b/ensembles/cruel_summer/main.py index 637bda88..bfc4c99c 100644 --- a/ensembles/cruel_summer/main.py +++ b/ensembles/cruel_summer/main.py @@ -1,16 +1,12 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers.ensemble import EnsemblePathManager, EnsembleManager -warnings.filterwarnings("ignore") - try: ensemble_path = EnsemblePathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/ensembles/pink_ponyclub/main.py b/ensembles/pink_ponyclub/main.py index 102fb755..73ec279b 100644 --- a/ensembles/pink_ponyclub/main.py +++ b/ensembles/pink_ponyclub/main.py @@ -1,16 +1,12 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers.ensemble import EnsemblePathManager, EnsembleManager -warnings.filterwarnings("ignore") - try: ensemble_path = EnsemblePathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/ensembles/rude_boy/main.py b/ensembles/rude_boy/main.py index 102fb755..73ec279b 100644 --- a/ensembles/rude_boy/main.py +++ b/ensembles/rude_boy/main.py @@ -1,16 +1,12 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers.ensemble import EnsemblePathManager, EnsembleManager -warnings.filterwarnings("ignore") - try: ensemble_path = EnsemblePathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/ensembles/skinny_love/main.py b/ensembles/skinny_love/main.py index 637bda88..bfc4c99c 100644 --- a/ensembles/skinny_love/main.py +++ b/ensembles/skinny_love/main.py @@ -1,16 +1,12 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers.ensemble import EnsemblePathManager, EnsembleManager -warnings.filterwarnings("ignore") - try: ensemble_path = EnsemblePathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/ensembles/white_mustang/main.py b/ensembles/white_mustang/main.py index 066e835c..c5b92ed1 100644 --- a/ensembles/white_mustang/main.py +++ b/ensembles/white_mustang/main.py @@ -1,31 +1,19 @@ -import wandb -import warnings from pathlib import Path -from views_pipeline_core.cli.utils import parse_args, validate_arguments -from views_pipeline_core.managers.log import LoggingManager +from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers.ensemble import EnsemblePathManager, EnsembleManager -warnings.filterwarnings("ignore") - try: ensemble_path = EnsemblePathManager(Path(__file__)) - logger = LoggingManager(ensemble_path).get_logger() except FileNotFoundError as fnf_error: - raise RuntimeError( - f"File not found: {fnf_error}. Check the file path and try again." - ) + raise RuntimeError(f"File not found: {fnf_error}. Check the file path and try again.") except PermissionError as perm_error: - raise RuntimeError( - f"Permission denied: {perm_error}. Check your permissions and try again." - ) + raise RuntimeError(f"Permission denied: {perm_error}. Check your permissions and try again.") except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") if __name__ == "__main__": - wandb.login() - args = parse_args() - validate_arguments(args) + args = ForecastingModelArgs.parse_args() manager = EnsembleManager( ensemble_path=ensemble_path, diff --git a/extractors/ucdp_extractor/main.py b/extractors/ucdp_extractor/main.py index 2b16d0e3..b3957909 100644 --- a/extractors/ucdp_extractor/main.py +++ b/extractors/ucdp_extractor/main.py @@ -1,11 +1,8 @@ import wandb -import warnings from pathlib import Path from views_graphdb.manager.extractor import UCDPExtractorManager from views_graphdb.manager.extractor import ExtractorPathManager -warnings.filterwarnings("ignore") - try: extractor_path = ExtractorPathManager(Path(__file__)) except FileNotFoundError as fnf_error: diff --git a/models/adolecent_slob/configs/config_partitions.py b/models/adolecent_slob/configs/config_partitions.py index 27314c19..78a50844 100644 --- a/models/adolecent_slob/configs/config_partitions.py +++ b/models/adolecent_slob/configs/config_partitions.py @@ -1,5 +1,7 @@ from ingester3.ViewsMonth import ViewsMonth +# ViewsMonth reference: 121 = Jan 1990, 444 = Dec 2016, 492 = Dec 2020, 540 = Dec 2024 + def generate(steps: int = 36) -> dict: """ diff --git a/models/adolecent_slob/main.py b/models/adolecent_slob/main.py index 7cfdac63..415d553a 100644 --- a/models/adolecent_slob/main.py +++ b/models/adolecent_slob/main.py @@ -1,12 +1,9 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_r2darts2 import DartsForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: @@ -15,13 +12,12 @@ if __name__ == "__main__": args = ForecastingModelArgs.parse_args() + manager = DartsForecastingModelManager( + model_path=model_path, + wandb_notifications=args.wandb_notifications, + ) + if args.sweep: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_sweep_run(args) + manager.execute_sweep_run(args) else: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_single_run(args) \ No newline at end of file + manager.execute_single_run(args) \ No newline at end of file diff --git a/models/average_cmbaseline/main.py b/models/average_cmbaseline/main.py index 8ef12185..239bc072 100644 --- a/models/average_cmbaseline/main.py +++ b/models/average_cmbaseline/main.py @@ -1,11 +1,8 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_baseline.manager.baseline_manager import BaselineForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: diff --git a/models/average_pgmbaseline/main.py b/models/average_pgmbaseline/main.py index 8ef12185..239bc072 100644 --- a/models/average_pgmbaseline/main.py +++ b/models/average_pgmbaseline/main.py @@ -1,11 +1,8 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_baseline.manager.baseline_manager import BaselineForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: diff --git a/models/bad_blood/main.py b/models/bad_blood/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/bad_blood/main.py +++ b/models/bad_blood/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/bittersweet_symphony/main.py b/models/bittersweet_symphony/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/bittersweet_symphony/main.py +++ b/models/bittersweet_symphony/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/black_ranger/main.py b/models/black_ranger/main.py index 8ef12185..239bc072 100644 --- a/models/black_ranger/main.py +++ b/models/black_ranger/main.py @@ -1,11 +1,8 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_baseline.manager.baseline_manager import BaselineForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: diff --git a/models/blank_space/main.py b/models/blank_space/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/blank_space/main.py +++ b/models/blank_space/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/blue_ranger/main.py b/models/blue_ranger/main.py index 8ef12185..239bc072 100644 --- a/models/blue_ranger/main.py +++ b/models/blue_ranger/main.py @@ -1,11 +1,8 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_baseline.manager.baseline_manager import BaselineForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: diff --git a/models/bouncy_organ/main.py b/models/bouncy_organ/main.py index 4f935dfb..e46045ea 100644 --- a/models/bouncy_organ/main.py +++ b/models/bouncy_organ/main.py @@ -1,12 +1,9 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_r2darts2 import DartsForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: @@ -15,13 +12,12 @@ if __name__ == "__main__": args = ForecastingModelArgs.parse_args() + manager = DartsForecastingModelManager( + model_path=model_path, + wandb_notifications=args.wandb_notifications, + ) + if args.sweep: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_sweep_run(args) + manager.execute_sweep_run(args) else: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_single_run(args) + manager.execute_single_run(args) diff --git a/models/brown_cheese/main.py b/models/brown_cheese/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/brown_cheese/main.py +++ b/models/brown_cheese/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/car_radio/main.py b/models/car_radio/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/car_radio/main.py +++ b/models/car_radio/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/caring_fish/main.py b/models/caring_fish/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/caring_fish/main.py +++ b/models/caring_fish/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/cheap_thrills/main.py b/models/cheap_thrills/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/cheap_thrills/main.py +++ b/models/cheap_thrills/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/chunky_cat/main.py b/models/chunky_cat/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/chunky_cat/main.py +++ b/models/chunky_cat/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/cool_cat/main.py b/models/cool_cat/main.py index 7cfdac63..415d553a 100644 --- a/models/cool_cat/main.py +++ b/models/cool_cat/main.py @@ -1,12 +1,9 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_r2darts2 import DartsForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: @@ -15,13 +12,12 @@ if __name__ == "__main__": args = ForecastingModelArgs.parse_args() + manager = DartsForecastingModelManager( + model_path=model_path, + wandb_notifications=args.wandb_notifications, + ) + if args.sweep: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_sweep_run(args) + manager.execute_sweep_run(args) else: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_single_run(args) \ No newline at end of file + manager.execute_single_run(args) \ No newline at end of file diff --git a/models/counting_stars/main.py b/models/counting_stars/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/counting_stars/main.py +++ b/models/counting_stars/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/dancing_queen/main.py b/models/dancing_queen/main.py index 7cfdac63..415d553a 100644 --- a/models/dancing_queen/main.py +++ b/models/dancing_queen/main.py @@ -1,12 +1,9 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_r2darts2 import DartsForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: @@ -15,13 +12,12 @@ if __name__ == "__main__": args = ForecastingModelArgs.parse_args() + manager = DartsForecastingModelManager( + model_path=model_path, + wandb_notifications=args.wandb_notifications, + ) + if args.sweep: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_sweep_run(args) + manager.execute_sweep_run(args) else: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_single_run(args) \ No newline at end of file + manager.execute_single_run(args) \ No newline at end of file diff --git a/models/dark_paradise/main.py b/models/dark_paradise/main.py index e8ca6061..7eb8d1ad 100644 --- a/models/dark_paradise/main.py +++ b/models/dark_paradise/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/demon_days/main.py b/models/demon_days/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/demon_days/main.py +++ b/models/demon_days/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/elastic_heart/main.py b/models/elastic_heart/main.py index 7cfdac63..415d553a 100644 --- a/models/elastic_heart/main.py +++ b/models/elastic_heart/main.py @@ -1,12 +1,9 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_r2darts2 import DartsForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: @@ -15,13 +12,12 @@ if __name__ == "__main__": args = ForecastingModelArgs.parse_args() + manager = DartsForecastingModelManager( + model_path=model_path, + wandb_notifications=args.wandb_notifications, + ) + if args.sweep: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_sweep_run(args) + manager.execute_sweep_run(args) else: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_single_run(args) \ No newline at end of file + manager.execute_single_run(args) \ No newline at end of file diff --git a/models/electric_relaxation/main.py b/models/electric_relaxation/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/electric_relaxation/main.py +++ b/models/electric_relaxation/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/emerging_principles/main.py b/models/emerging_principles/main.py index 8f4ef3e4..c34d4530 100644 --- a/models/emerging_principles/main.py +++ b/models/emerging_principles/main.py @@ -1,4 +1,3 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager @@ -7,8 +6,6 @@ apply_nbeats_patch() -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: @@ -17,13 +14,12 @@ if __name__ == "__main__": args = ForecastingModelArgs.parse_args() + manager = DartsForecastingModelManager( + model_path=model_path, + wandb_notifications=args.wandb_notifications, + ) + if args.sweep: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_sweep_run(args) + manager.execute_sweep_run(args) else: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_single_run(args) \ No newline at end of file + manager.execute_single_run(args) \ No newline at end of file diff --git a/models/fancy_feline/main.py b/models/fancy_feline/main.py index 7cfdac63..415d553a 100644 --- a/models/fancy_feline/main.py +++ b/models/fancy_feline/main.py @@ -1,12 +1,9 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_r2darts2 import DartsForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: @@ -15,13 +12,12 @@ if __name__ == "__main__": args = ForecastingModelArgs.parse_args() + manager = DartsForecastingModelManager( + model_path=model_path, + wandb_notifications=args.wandb_notifications, + ) + if args.sweep: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_sweep_run(args) + manager.execute_sweep_run(args) else: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_single_run(args) \ No newline at end of file + manager.execute_single_run(args) \ No newline at end of file diff --git a/models/fast_car/main.py b/models/fast_car/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/fast_car/main.py +++ b/models/fast_car/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/fluorescent_adolescent/main.py b/models/fluorescent_adolescent/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/fluorescent_adolescent/main.py +++ b/models/fluorescent_adolescent/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/fourtieth_symphony/main.py b/models/fourtieth_symphony/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/fourtieth_symphony/main.py +++ b/models/fourtieth_symphony/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/good_life/main.py b/models/good_life/main.py index 7cfdac63..415d553a 100644 --- a/models/good_life/main.py +++ b/models/good_life/main.py @@ -1,12 +1,9 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_r2darts2 import DartsForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: @@ -15,13 +12,12 @@ if __name__ == "__main__": args = ForecastingModelArgs.parse_args() + manager = DartsForecastingModelManager( + model_path=model_path, + wandb_notifications=args.wandb_notifications, + ) + if args.sweep: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_sweep_run(args) + manager.execute_sweep_run(args) else: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_single_run(args) \ No newline at end of file + manager.execute_single_run(args) \ No newline at end of file diff --git a/models/good_riddance/main.py b/models/good_riddance/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/good_riddance/main.py +++ b/models/good_riddance/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/green_ranger/main.py b/models/green_ranger/main.py index 8ef12185..239bc072 100644 --- a/models/green_ranger/main.py +++ b/models/green_ranger/main.py @@ -1,11 +1,8 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_baseline.manager.baseline_manager import BaselineForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: diff --git a/models/green_squirrel/main.py b/models/green_squirrel/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/green_squirrel/main.py +++ b/models/green_squirrel/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/heat_waves/main.py b/models/heat_waves/main.py index 7cfdac63..415d553a 100644 --- a/models/heat_waves/main.py +++ b/models/heat_waves/main.py @@ -1,12 +1,9 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_r2darts2 import DartsForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: @@ -15,13 +12,12 @@ if __name__ == "__main__": args = ForecastingModelArgs.parse_args() + manager = DartsForecastingModelManager( + model_path=model_path, + wandb_notifications=args.wandb_notifications, + ) + if args.sweep: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_sweep_run(args) + manager.execute_sweep_run(args) else: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_single_run(args) \ No newline at end of file + manager.execute_single_run(args) \ No newline at end of file diff --git a/models/heavy_rotation/main.py b/models/heavy_rotation/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/heavy_rotation/main.py +++ b/models/heavy_rotation/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/high_hopes/main.py b/models/high_hopes/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/high_hopes/main.py +++ b/models/high_hopes/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/hot_stream/main.py b/models/hot_stream/main.py index 7cfdac63..415d553a 100644 --- a/models/hot_stream/main.py +++ b/models/hot_stream/main.py @@ -1,12 +1,9 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_r2darts2 import DartsForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: @@ -15,13 +12,12 @@ if __name__ == "__main__": args = ForecastingModelArgs.parse_args() + manager = DartsForecastingModelManager( + model_path=model_path, + wandb_notifications=args.wandb_notifications, + ) + if args.sweep: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_sweep_run(args) + manager.execute_sweep_run(args) else: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_single_run(args) \ No newline at end of file + manager.execute_single_run(args) \ No newline at end of file diff --git a/models/invisible_string/main.py b/models/invisible_string/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/invisible_string/main.py +++ b/models/invisible_string/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/lavender_haze/main.py b/models/lavender_haze/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/lavender_haze/main.py +++ b/models/lavender_haze/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/little_lies/main.py b/models/little_lies/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/little_lies/main.py +++ b/models/little_lies/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/locf_cmbaseline/main.py b/models/locf_cmbaseline/main.py index 8ef12185..239bc072 100644 --- a/models/locf_cmbaseline/main.py +++ b/models/locf_cmbaseline/main.py @@ -1,11 +1,8 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_baseline.manager.baseline_manager import BaselineForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: diff --git a/models/locf_pgmbaseline/main.py b/models/locf_pgmbaseline/main.py index 8ef12185..239bc072 100644 --- a/models/locf_pgmbaseline/main.py +++ b/models/locf_pgmbaseline/main.py @@ -1,11 +1,8 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_baseline.manager.baseline_manager import BaselineForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: diff --git a/models/lovely_creature/main.py b/models/lovely_creature/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/lovely_creature/main.py +++ b/models/lovely_creature/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/midnight_rain/main.py b/models/midnight_rain/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/midnight_rain/main.py +++ b/models/midnight_rain/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/national_anthem/main.py b/models/national_anthem/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/national_anthem/main.py +++ b/models/national_anthem/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/new_rules/main.py b/models/new_rules/main.py index 8f4ef3e4..c34d4530 100644 --- a/models/new_rules/main.py +++ b/models/new_rules/main.py @@ -1,4 +1,3 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager @@ -7,8 +6,6 @@ apply_nbeats_patch() -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: @@ -17,13 +14,12 @@ if __name__ == "__main__": args = ForecastingModelArgs.parse_args() + manager = DartsForecastingModelManager( + model_path=model_path, + wandb_notifications=args.wandb_notifications, + ) + if args.sweep: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_sweep_run(args) + manager.execute_sweep_run(args) else: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_single_run(args) \ No newline at end of file + manager.execute_single_run(args) \ No newline at end of file diff --git a/models/novel_heuristics/main.py b/models/novel_heuristics/main.py index 95d552e6..1ad9e520 100644 --- a/models/novel_heuristics/main.py +++ b/models/novel_heuristics/main.py @@ -1,4 +1,3 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager @@ -6,8 +5,6 @@ from views_r2darts2 import DartsForecastingModelManager, apply_nbeats_patch apply_nbeats_patch() -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: @@ -16,13 +13,12 @@ if __name__ == "__main__": args = ForecastingModelArgs.parse_args() + manager = DartsForecastingModelManager( + model_path=model_path, + wandb_notifications=args.wandb_notifications, + ) + if args.sweep: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_sweep_run(args) + manager.execute_sweep_run(args) else: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_single_run(args) + manager.execute_single_run(args) diff --git a/models/old_money/main.py b/models/old_money/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/old_money/main.py +++ b/models/old_money/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/ominous_ox/main.py b/models/ominous_ox/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/ominous_ox/main.py +++ b/models/ominous_ox/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/orange_pasta/main.py b/models/orange_pasta/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/orange_pasta/main.py +++ b/models/orange_pasta/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/party_princess/main.py b/models/party_princess/main.py index 9ac16dfc..a313eb73 100644 --- a/models/party_princess/main.py +++ b/models/party_princess/main.py @@ -1,12 +1,9 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_r2darts2 import DartsForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: @@ -15,13 +12,12 @@ if __name__ == "__main__": args = ForecastingModelArgs.parse_args() + manager = DartsForecastingModelManager( + model_path=model_path, + wandb_notifications=args.wandb_notifications, + ) + if args.sweep: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_sweep_run(args) + manager.execute_sweep_run(args) else: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_single_run(args) + manager.execute_single_run(args) diff --git a/models/pink_ranger/main.py b/models/pink_ranger/main.py index 8ef12185..239bc072 100644 --- a/models/pink_ranger/main.py +++ b/models/pink_ranger/main.py @@ -1,11 +1,8 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_baseline.manager.baseline_manager import BaselineForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: diff --git a/models/plastic_beach/main.py b/models/plastic_beach/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/plastic_beach/main.py +++ b/models/plastic_beach/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/popular_monster/main.py b/models/popular_monster/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/popular_monster/main.py +++ b/models/popular_monster/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/preliminary_directives/main.py b/models/preliminary_directives/main.py index 8f4ef3e4..c34d4530 100644 --- a/models/preliminary_directives/main.py +++ b/models/preliminary_directives/main.py @@ -1,4 +1,3 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager @@ -7,8 +6,6 @@ apply_nbeats_patch() -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: @@ -17,13 +14,12 @@ if __name__ == "__main__": args = ForecastingModelArgs.parse_args() + manager = DartsForecastingModelManager( + model_path=model_path, + wandb_notifications=args.wandb_notifications, + ) + if args.sweep: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_sweep_run(args) + manager.execute_sweep_run(args) else: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_single_run(args) \ No newline at end of file + manager.execute_single_run(args) \ No newline at end of file diff --git a/models/purple_alien/main.py b/models/purple_alien/main.py index 2945ea84..ba365f14 100644 --- a/models/purple_alien/main.py +++ b/models/purple_alien/main.py @@ -1,4 +1,3 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager @@ -6,8 +5,6 @@ # Import your model manager class here from views_hydranet.manager.hydranet_manager import HydranetManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) @@ -25,7 +22,9 @@ if __name__ == "__main__": args = ForecastingModelArgs.parse_args() + manager = HydranetManager(model_path=model_path) + if args.sweep: - HydranetManager(model_path=model_path).execute_sweep_run(args) + manager.execute_sweep_run(args) else: - HydranetManager(model_path=model_path).execute_single_run(args) + manager.execute_single_run(args) diff --git a/models/purple_haze/main.py b/models/purple_haze/main.py index 63621928..7eb8d1ad 100644 --- a/models/purple_haze/main.py +++ b/models/purple_haze/main.py @@ -1,11 +1,8 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: diff --git a/models/red_ranger/main.py b/models/red_ranger/main.py index 8ef12185..239bc072 100644 --- a/models/red_ranger/main.py +++ b/models/red_ranger/main.py @@ -1,11 +1,8 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_baseline.manager.baseline_manager import BaselineForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: diff --git a/models/teen_spirit/main.py b/models/teen_spirit/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/teen_spirit/main.py +++ b/models/teen_spirit/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/teenage_dirtbag/main.py b/models/teenage_dirtbag/main.py index 7cfdac63..415d553a 100644 --- a/models/teenage_dirtbag/main.py +++ b/models/teenage_dirtbag/main.py @@ -1,12 +1,9 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_r2darts2 import DartsForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: @@ -15,13 +12,12 @@ if __name__ == "__main__": args = ForecastingModelArgs.parse_args() + manager = DartsForecastingModelManager( + model_path=model_path, + wandb_notifications=args.wandb_notifications, + ) + if args.sweep: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_sweep_run(args) + manager.execute_sweep_run(args) else: - DartsForecastingModelManager( - model_path=model_path, - wandb_notifications=args.wandb_notifications - ).execute_single_run(args) \ No newline at end of file + manager.execute_single_run(args) \ No newline at end of file diff --git a/models/thousand_miles/README.md b/models/thousand_miles/README.md deleted file mode 100644 index 9017539d..00000000 --- a/models/thousand_miles/README.md +++ /dev/null @@ -1,58 +0,0 @@ -# Thousand Miles -## Overview - - -| Information | Details | -|---------------------|--------------------------------| -| **Model Algorithm** | TiDEModel | -| **Level of Analysis** | cm | -| **Targets** | ln_ged_sb_dep | -| **Features** | thousand_miles | -| **Feature Description** | Base features for neural network models | -| **Metrics** | RMSLE, CRPS, MSE, MSLE, y_hat_bar | -| **Deployment Status** | shadow | - -## Repository Structure - -``` -Thousand Miles -├── README.md -├── main.py -├── requirements.txt -├── run.sh -├── logs -├── artifacts -├── configs -│ ├── config_deployment.py -│ ├── config_hyperparameters.py -│ ├── config_meta.py -│ ├── config_partitions.py -│ ├── config_queryset.py -│ ├── config_sweep.py -├── data -│ ├── generated -│ ├── processed -│ ├── raw -├── reports -├── notebooks -``` - -## Setup Instructions - -Clone the [views-pipeline-core](https://github.com/views-platform/views-pipeline-core) and the [views-models](https://github.com/views-platform/views-models) repository. - - -## Usage -Modify configurations in configs/. - -If you already have an existing environment, run the `main.py` file. If you don't have an existing environment, run the `run.sh` file. - -``` -python main.py -r calibration -t -e - -or - -./run.sh -r calibration -t -e -``` - - diff --git a/models/thrift_shop/README.md b/models/thrift_shop/README.md deleted file mode 100644 index 9d0328d2..00000000 --- a/models/thrift_shop/README.md +++ /dev/null @@ -1,58 +0,0 @@ -# Thrift Shop -## Overview - - -| Information | Details | -|---------------------|--------------------------------| -| **Model Algorithm** | TFTModel | -| **Level of Analysis** | cm | -| **Targets** | ln_ged_sb_dep | -| **Features** | thrift_shop | -| **Feature Description** | Base features for neural network models | -| **Metrics** | RMSLE, CRPS, MSE, MSLE, y_hat_bar | -| **Deployment Status** | shadow | - -## Repository Structure - -``` -Thrift Shop -├── README.md -├── main.py -├── requirements.txt -├── run.sh -├── logs -├── artifacts -├── configs -│ ├── config_deployment.py -│ ├── config_hyperparameters.py -│ ├── config_meta.py -│ ├── config_partitions.py -│ ├── config_queryset.py -│ ├── config_sweep.py -├── data -│ ├── generated -│ ├── processed -│ ├── raw -├── reports -├── notebooks -``` - -## Setup Instructions - -Clone the [views-pipeline-core](https://github.com/views-platform/views-pipeline-core) and the [views-models](https://github.com/views-platform/views-models) repository. - - -## Usage -Modify configurations in configs/. - -If you already have an existing environment, run the `main.py` file. If you don't have an existing environment, run the `run.sh` file. - -``` -python main.py -r calibration -t -e - -or - -./run.sh -r calibration -t -e -``` - - diff --git a/models/twin_flame/main.py b/models/twin_flame/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/twin_flame/main.py +++ b/models/twin_flame/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/wild_rose/main.py b/models/wild_rose/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/wild_rose/main.py +++ b/models/wild_rose/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/wildest_dream/main.py b/models/wildest_dream/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/wildest_dream/main.py +++ b/models/wildest_dream/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/wuthering_heights/main.py b/models/wuthering_heights/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/wuthering_heights/main.py +++ b/models/wuthering_heights/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/yellow_pikachu/main.py b/models/yellow_pikachu/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/yellow_pikachu/main.py +++ b/models/yellow_pikachu/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/yellow_ranger/main.py b/models/yellow_ranger/main.py index 8ef12185..239bc072 100644 --- a/models/yellow_ranger/main.py +++ b/models/yellow_ranger/main.py @@ -1,11 +1,8 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_baseline.manager.baseline_manager import BaselineForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: diff --git a/models/yellow_submarine/main.py b/models/yellow_submarine/main.py index 6fbf36fa..ef7d8805 100644 --- a/models/yellow_submarine/main.py +++ b/models/yellow_submarine/main.py @@ -1,17 +1,13 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: raise RuntimeError(f"Unexpected error: {e}. Check the logs for details.") - if __name__ == "__main__": args = ForecastingModelArgs.parse_args() diff --git a/models/zero_cmbaseline/main.py b/models/zero_cmbaseline/main.py index 8ef12185..239bc072 100644 --- a/models/zero_cmbaseline/main.py +++ b/models/zero_cmbaseline/main.py @@ -1,11 +1,8 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_baseline.manager.baseline_manager import BaselineForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: diff --git a/models/zero_pgmbaseline/main.py b/models/zero_pgmbaseline/main.py index 8ef12185..239bc072 100644 --- a/models/zero_pgmbaseline/main.py +++ b/models/zero_pgmbaseline/main.py @@ -1,11 +1,8 @@ -import warnings from pathlib import Path from views_pipeline_core.cli import ForecastingModelArgs from views_pipeline_core.managers import ModelPathManager from views_baseline.manager.baseline_manager import BaselineForecastingModelManager -warnings.filterwarnings("ignore") - try: model_path = ModelPathManager(Path(__file__)) except Exception as e: diff --git a/postprocessors/un_fao/main.py b/postprocessors/un_fao/main.py index 2a5b310c..dc6a8c8c 100644 --- a/postprocessors/un_fao/main.py +++ b/postprocessors/un_fao/main.py @@ -1,5 +1,4 @@ import wandb -import warnings from pathlib import Path from views_postprocessing.unfao.managers import UNFAOPostProcessorManager from views_pipeline_core.managers.postprocessor.postprocessor import PostprocessorPathManager @@ -7,8 +6,6 @@ # Import your model manager class here # E.g. from views_stepshifter.manager.stepshifter_manager import StepshifterManager -warnings.filterwarnings("ignore") - try: model_path = PostprocessorPathManager(Path(__file__)) except FileNotFoundError as fnf_error: diff --git a/reports/technical_risk_register.md b/reports/technical_risk_register.md new file mode 100644 index 00000000..744ef777 --- /dev/null +++ b/reports/technical_risk_register.md @@ -0,0 +1,371 @@ +# Technical Risk Register — views-models + +**Last updated:** 2026-04-06 +**Governing ADR:** [ADR-010](../docs/ADRs/010_technical_risk_register.md) +**Total entries:** 30 (26 concerns + 4 disagreements) +**Concerns:** Open 17 | Mitigated 4 | Resolved 3 | Accepted 3 +**Disagreements:** Open 4 + +--- + +## Open Concerns + +### C-01 — Partition boundary updates require atomic edits to 73 files + +| Field | Value | +|---|---| +| **Tier** | 1 | +| **Trigger** | A decision is made to change calibration, validation, or forecasting partition boundaries | +| **Source** | repo-assimilation | +| **Status** | Open | +| **Notes** | ADR-002 mandates self-contained configs (intentional duplication). `test_config_partitions.py` detects drift. The coordination cost is the price of model independence. A migration tool could reduce risk but does not exist. | + +--- + +### C-02 — No static validation of queryset correctness + +| Field | Value | +|---|---| +| **Tier** | 1 | +| **Trigger** | A VIEWS database column is renamed or removed, or a queryset references a non-existent column | +| **Source** | repo-assimilation | +| **Status** | Open | +| **Notes** | `config_queryset.py` is the most complex config file (up to 734 lines) with zero test coverage. Failures are runtime-only (data fetch phase). Validation would require access to the VIEWS database schema. | + +--- + +### C-03 — Integration tests are manual-only, not in CI + +| Field | Value | +|---|---| +| **Tier** | 2 | +| **Trigger** | A model breaks at training time but all CI checks pass | +| **Source** | repo-assimilation | +| **Status** | Open | +| **Notes** | `run_integration_tests.sh` is the only mechanism testing actual model training/evaluation. It runs locally and takes hours. The CI pytest workflow (`run_tests.yml`) only runs fast structural tests. A model can be merged broken. | + +--- + +### C-04 — Algorithm label / implementation drift + +| Field | Value | +|---|---| +| **Tier** | 3 | +| **Trigger** | `config_meta["algorithm"]` is changed without updating `main.py` imports, or vice versa | +| **Source** | repo-assimilation | +| **Status** | Mitigated | +| **Notes** | `test_algorithm_coherence.py::TestAlgorithmManagerCoherence` validates that `config_meta["algorithm"]` belongs to the correct package family and that the package matches `main.py` imports. Uses a hardcoded `ALGORITHM_TO_PACKAGE` mapping that must be updated when new algorithms are added. | + +--- + +### C-05 — Incomplete hyperparameter validation for non-DARTS models + +| Field | Value | +|---|---| +| **Tier** | 3 | +| **Trigger** | A stepshifter or baseline model is created with missing hyperparameters | +| **Source** | repo-assimilation | +| **Status** | Open | +| **Notes** | `test_darts_reproducibility.py` validates DARTS models against a canonical parameter list, but stepshifter (~20 models) and baseline (~6 models) have no equivalent check. A missing hyperparameter surfaces only at training time. | + +--- + +### C-06 — `config_queryset.py` has unique external dependencies among config files + +| Field | Value | +|---|---| +| **Tier** | 3 | +| **Trigger** | Tooling or tests attempt to load `config_queryset.py` without `viewser` and `views_pipeline_core` installed | +| **Source** | repo-assimilation | +| **Status** | Accepted | +| **Notes** | Accepted as intentional deviation per ADR-002. The `viewser` DSL is essential for queryset definition. Testing gap addressed separately via C-02. | + +--- + +### C-07 — Scaffold builder is untested + +| Field | Value | +|---|---| +| **Tier** | 3 | +| **Trigger** | A `views_pipeline_core` template update changes scaffold output, causing newly created models to fail existing tests | +| **Source** | repo-assimilation | +| **Status** | Open | +| **Notes** | `build_model_scaffold.py` and `build_ensemble_scaffold.py` generate the initial structure for all new models. No test validates that scaffold output satisfies `test_model_structure.py` or `test_config_completeness.py`. | + +--- + +### C-08 — `requirements.txt` / `main.py` coherence is unvalidated + +| Field | Value | +|---|---| +| **Tier** | 4 | +| **Trigger** | A model's `requirements.txt` specifies one algorithm package but `main.py` imports a different one | +| **Source** | repo-assimilation | +| **Status** | Mitigated | +| **Notes** | `test_algorithm_coherence.py::TestRequirementsCoherence` validates that `requirements.txt` package name (normalized hyphens to underscores) matches the package imported in `main.py`. | + +--- + +### C-09 — Two placeholder models with no implementation + +| Field | Value | +|---|---| +| **Tier** | 4 | +| **Trigger** | Tooling or documentation includes `thousand_miles` or `thrift_shop` as active models | +| **Source** | repo-assimilation | +| **Status** | Resolved | +| **Notes** | Both directories deleted (2026-04-06). | + +--- + +### C-10 — Conda environments committed to repository tree + +| Field | Value | +|---|---| +| **Tier** | 4 | +| **Trigger** | A contributor mistakes `envs/` contents for tracked repository state | +| **Source** | repo-assimilation | +| **Status** | Accepted | +| **Notes** | Accepted. `envs/` contents are gitignored. The directories exist as local convenience for contributors. | + +--- + +### C-11 — Single deployed model limits deployment path testing + +| Field | Value | +|---|---| +| **Tier** | 4 | +| **Trigger** | A second model moves to `deployed` status and encounters untested deployment-path behavior | +| **Source** | repo-assimilation | +| **Status** | Accepted | +| **Notes** | Accepted as current deployment posture. Deployment gating tested via `test_config_completeness.py::test_deployment_status_is_valid`. Additional models will be deployed as they mature. | + +--- + +### C-12 — Global warning suppression in all model entrypoints + +| Field | Value | +|---|---| +| **Tier** | 2 | +| **Trigger** | A numerical instability, deprecation, or data quality issue produces a Python warning that is silently swallowed | +| **Source** | expert-code-review (Martin, Nygard, Hickey) | +| **Status** | Resolved | +| **Notes** | `warnings.filterwarnings("ignore")` removed from all 74 `main.py` files (2026-04-06). Enforcement test added: `test_cli_pattern.py::test_no_global_warning_suppression` (AST-based, parametrized across all models and ensembles). | + +--- + +### C-13 — No prediction quality validation before ensemble aggregation + +| Field | Value | +|---|---| +| **Tier** | 2 | +| **Trigger** | A constituent model produces NaN, Inf, or wildly off-scale predictions; ensemble silently aggregates or propagates them | +| **Source** | expert-code-review (Nygard, Kleppmann) | +| **Status** | Open | +| **Notes** | `white_mustang` (deployed ensemble) aggregates via median. No NaN/Inf check or range validation occurs before aggregation. If multiple constituent models produce garbage, the ensemble output degrades silently. Downstream consumers (UN FAO API) receive degraded data. | + +--- + +### C-14 — Concurrent model training can silently overwrite artifacts + +| Field | Value | +|---|---| +| **Tier** | 4 | +| **Trigger** | Two training runs for the same model execute simultaneously, writing to the same `artifacts/` directory | +| **Source** | expert-code-review (Kleppmann) | +| **Status** | Open | +| **Notes** | Artifacts have no run ID or timestamp in filenames. The second writer silently overwrites the first. Low probability but destroys reproducibility when it occurs. W&B logs exist but are not cross-referenced with artifact files. | + +--- + +### C-15 — Zero CIC failure mode test coverage + +| Field | Value | +|---|---| +| **Tier** | 1 | +| **Trigger** | Any CIC-documented failure mode occurs in production and the system does not behave as declared | +| **Source** | test-review (Nygard) | +| **Status** | Mitigated | +| **Notes** | `test_failure_modes.py` expanded from 4 to 9 tests (2026-04-06). New tests cover: empty config files, import errors, runtime errors, integration test runner exit codes. Remaining gap: no tests for scaffold builder `FileExistsError`, no tests for ensemble aggregation failure. 9 of 21 CIC failure modes now covered. | + +--- + +### C-16 — Zero direct unit tests for any CIC class + +| Field | Value | +|---|---| +| **Tier** | 2 | +| **Trigger** | A refactor of `build_model_scaffold.py`, `create_catalogs.py`, or any other CIC class introduces a regression | +| **Source** | test-review (Beck, Feathers) | +| **Status** | Open | +| **Notes** | All 5 CIC-documented classes (`ModelScaffoldBuilder`, `EnsembleScaffoldBuilder`, `PackageScaffoldBuilder`, `CatalogExtractor`, `IntegrationTestRunner`) have zero direct unit tests. Tests validate their *outputs* (model directory structure) but never instantiate or exercise the classes. 33 CIC guarantees total, only 2 directly tested (6%), 6 indirectly tested (18%), 25 untested (76%). | + +--- + +### C-17 — Tooling scripts are untested "edit and pray" zones + +| Field | Value | +|---|---| +| **Tier** | 2 | +| **Trigger** | A developer modifies `create_catalogs.py`, `update_readme.py`, or `generate_features_catalog.py` and introduces a regression | +| **Source** | test-review (Feathers) | +| **Status** | Open | +| **Notes** | `create_catalogs.py` (237 lines), `update_readme.py` (281 lines), `generate_features_catalog.py` (117 lines) have near-zero test coverage. These are change-prone scripts modified when model metadata patterns change. `create_catalogs.py` only has `exec()` absence validated; core logic `extract_models()` is untested. | + +--- + +### C-18 — `build_model_scaffold.py` I/O coupling prevents testability + +| Field | Value | +|---|---| +| **Tier** | 3 | +| **Trigger** | Any attempt to write automated tests for `ModelScaffoldBuilder` or `EnsembleScaffoldBuilder` | +| **Source** | test-review (Beck), expert-code-review (Martin, Ousterhout) | +| **Status** | Open | +| **Notes** | `build_model_scripts()` uses `input()` directly for user prompts and makes network calls to GitHub API. No dependency injection seam exists. The class cannot be instantiated in a test without monkey-patching stdin. This is the root cause of C-07 (scaffold builder untested). | + +--- + +### C-19 — `create_catalogs.py` has no transactional file write safety + +| Field | Value | +|---|---| +| **Tier** | 3 | +| **Trigger** | `create_catalogs.py` crashes between reading and writing `README.md` | +| **Source** | test-review (Feathers), expert-code-review (Martin) | +| **Status** | Open | +| **Notes** | The `__main__` block reads README.md, modifies it in memory, and writes it back without transactional safety. If the script crashes mid-write, README could be corrupted. The CI workflow `update_catalogs.yml` auto-commits the result. Should write to temp file then atomically rename. | + +--- + +### C-20 — No timeout or circuit breaker in data fetch path + +| Field | Value | +|---|---| +| **Tier** | 2 | +| **Trigger** | The VIEWS database is slow or unreachable during model training | +| **Source** | expert-code-review (Nygard) | +| **Status** | Open | +| **Notes** | Models fetch data via `viewser.Queryset.publish()` with no timeout, retry limit, or fallback. A database outage hangs every model indefinitely during normal operation. The only timeout is the external `timeout` command in `run_integration_tests.sh` (1800s), which only applies during integration testing. | + +--- + +### C-21 — Partition boundary semantics undocumented + +| Field | Value | +|---|---| +| **Tier** | 3 | +| **Trigger** | A new contributor or auditor asks "why 121? why 444?" and finds no answer | +| **Source** | expert-code-review (Kleppmann) | +| **Status** | Mitigated | +| **Notes** | ViewsMonth-to-date mapping added as comment in `models/adolecent_slob/configs/config_partitions.py` and in `docs/ADRs/README.md` ADR-011 candidate description (2026-04-06). Full rationale for split points still pending as a future ADR. | + +--- + +### C-22 — No idempotency guarantee in model training artifacts + +| Field | Value | +|---|---| +| **Tier** | 3 | +| **Trigger** | A model is re-trained and previous artifacts are silently overwritten without versioning | +| **Source** | expert-code-review (Kleppmann) | +| **Status** | Open | +| **Notes** | Models write artifacts to `artifacts/` and W&B logs to `wandb/`. Re-running overwrites previous artifacts without versioning or deduplication. `force_reset: true` in DARTS hyperparameters acknowledges this but doesn't solve it. Related to C-14 (concurrent overwrite) but also applies to sequential re-runs. | + +--- + +### C-23 — Test suite is overwhelmingly beige; red coverage is low + +| Field | Value | +|---|---| +| **Tier** | 2 | +| **Trigger** | A failure mode occurs that convention/structure tests cannot detect | +| **Source** | test-review (category distribution analysis) | +| **Status** | Mitigated | +| **Notes** | Red coverage improved from 4 to 9 tests (2026-04-06). New tests cover config loading edge cases and integration test runner failure modes. Distribution still heavily beige (~64%) but red category is no longer negligible. Further improvement requires testing scaffold builder and ensemble aggregation failure modes. | + +--- + +### C-24 — DARTS model `main.py` duplicates manager instantiation + +| Field | Value | +|---|---| +| **Tier** | 4 | +| **Trigger** | A DARTS model's manager constructor signature changes and only one of the two instantiations is updated | +| **Source** | expert-code-review (Martin) | +| **Status** | Resolved | +| **Notes** | All 15 DARTS models and `purple_alien` (HydraNet) refactored to single-instantiation pattern (2026-04-06). Manager is now assigned to local variable before the `args.sweep` branch, matching the stepshifter/baseline convention. | + +--- + +### C-25 — `white_mustang` ensemble uses deprecated CLI import pattern + +| Field | Value | +|---|---| +| **Tier** | 3 | +| **Trigger** | `views_pipeline_core` removes the deprecated `cli.utils` module | +| **Source** | expert-code-review (Martin) | +| **Status** | Resolved | +| **Notes** | `white_mustang/main.py` rewritten to match `cruel_summer` pattern (2026-04-06): uses `ForecastingModelArgs`, no `wandb.login()`, no `LoggingManager`. `test_cli_pattern.py` extended to cover all ensembles via `any_model_dir` fixture, plus new `test_no_global_warning_suppression` test. | + +--- + +### C-26 — `IntegrationTestRunner` `--level` filter silently excludes broken models + +| Field | Value | +|---|---| +| **Tier** | 3 | +| **Trigger** | A model's `config_meta.py` has a syntax error; `--level cm` filtering silently skips it | +| **Source** | test-review (Leveson) | +| **Status** | Open | +| **Notes** | The `--level` filter shells out to Python with `2>/dev/null`. If `config_meta.py` is broken, the model is silently excluded from the filtered set. A broken model escapes testing because the test runner can't classify it, and no one is notified. CIC documents this as a known deviation. | + +--- + +## Disagreements + +### D-01 — Intentional config duplication vs. DRY principle + +| Field | Value | +|---|---| +| **Tier** | 3 | +| **Trigger** | Partition boundary update requires editing 73 files atomically | +| **Source** | expert-code-review (Martin vs. Ousterhout/Hickey) | +| **Status** | Open | +| **Notes** | Martin (Clean Code) considers 73 identical files a DRY violation creating coordination nightmares. Ousterhout (Complexity) and Hickey (Simplicity) support the duplication because it eliminates shared-state reasoning and keeps each model self-contained. Resolution: the duplication is load-bearing; build a migration tool rather than centralizing. Related to C-01. | + +--- + +### D-02 — Hardcoded algorithm-to-package mapping vs. factory pattern + +| Field | Value | +|---|---| +| **Tier** | 4 | +| **Trigger** | A new algorithm is added and the test mapping must be manually updated | +| **Source** | expert-code-review (GoF vs. Beck/Hickey) | +| **Status** | Open | +| **Notes** | Gang of Four would prefer a factory in `views_pipeline_core` that maps algorithm→manager, eliminating the need for `ALGORITHM_TO_PACKAGE` in `test_algorithm_coherence.py`. Beck accepts the mapping as pragmatic (test failure = correct signal). Hickey prefers data (dict) over abstraction (factory). Resolution: correct for this repo's scope; factory is a cross-repo decision for `views_pipeline_core`. | + +--- + +### D-03 — `config_queryset.py` dependency exception: essential or architectural violation + +| Field | Value | +|---|---| +| **Tier** | 3 | +| **Trigger** | Decision to refactor config loading or extend test coverage to querysets | +| **Source** | expert-code-review (Martin vs. Kleppmann vs. Ousterhout) | +| **Status** | Open | +| **Notes** | Martin considers `config_queryset.py`'s external dependencies an architectural boundary violation — configs should be pure. Kleppmann notes it's where data correctness is defined and can't be simplified away. Ousterhout acknowledges the mental tax but accepts it as irreducible complexity. Resolution: the dependency is essential (querysets require the `viewser` DSL). The gap is in testing — AST-based validation of column structure could create a testable seam without requiring external packages. Related to C-02, C-06. | + +--- + +### D-04 — Static analysis tests vs. behavioral execution tests + +| Field | Value | +|---|---| +| **Tier** | 2 | +| **Trigger** | A model passes all pytest structural tests but fails at runtime | +| **Source** | test-review (Beck vs. Nygard) | +| **Status** | Open | +| **Notes** | The test suite is almost entirely static analysis (AST parsing, importlib loading, regex extraction). Beck notes this gives exceptional speed (1.41s for 2374 tests) and clean behavioral contracts. Nygard counters that the gap between "structure is correct" and "system works" is wide and uncovered — no `main.py` is ever executed, no training pipeline is ever triggered. The suite validates the blueprint but never builds the house. Related to C-03, C-15. | diff --git a/tests/test_algorithm_coherence.py b/tests/test_algorithm_coherence.py new file mode 100644 index 00000000..0c4175b5 --- /dev/null +++ b/tests/test_algorithm_coherence.py @@ -0,0 +1,128 @@ +"""Tests for cross-artifact coherence: algorithm, manager import, and requirements. + +Validates that config_meta['algorithm'], the manager import in main.py, +and the package declared in requirements.txt all agree with each other. + +Addresses risks C-04 and C-08 from the technical risk register. +""" +import ast +import re +from pathlib import Path + +import pytest + +from tests.conftest import load_config_module + +# Verified empirically from all 66 active models on 2026-04-04. +# Update this mapping when a new algorithm is added to a package. +ALGORITHM_TO_PACKAGE = { + # views_stepshifter algorithms + "HurdleModel": "views_stepshifter", + "XGBRegressor": "views_stepshifter", + "XGBRFRegressor": "views_stepshifter", + "LGBMRegressor": "views_stepshifter", + "RandomForestRegressor": "views_stepshifter", + "ShurfModel": "views_stepshifter", + # views_r2darts2 algorithms + "TCNModel": "views_r2darts2", + "TFTModel": "views_r2darts2", + "BlockRNNModel": "views_r2darts2", + "NBEATSModel": "views_r2darts2", + "TransformerModel": "views_r2darts2", + "TiDEModel": "views_r2darts2", + "TSMixerModel": "views_r2darts2", + # views_baseline algorithms + "MixtureBaseline": "views_baseline", + "AverageModel": "views_baseline", + "ZeroModel": "views_baseline", + "LocfModel": "views_baseline", + # views_hydranet algorithms + "HydraNet": "views_hydranet", +} + + +def _extract_manager_package(main_path: Path) -> str | None: + """Extract the top-level package name from the non-pipeline-core import in main.py. + + Handles both patterns: + - from views_r2darts2 import DartsForecastingModelManager + - from views_stepshifter.manager.stepshifter_manager import StepshifterManager + + Returns the top-level package (e.g., 'views_r2darts2') or None. + """ + source = main_path.read_text() + tree = ast.parse(source) + for node in ast.walk(tree): + if isinstance(node, ast.ImportFrom) and node.module: + top_package = node.module.split(".")[0] + if top_package.startswith("views_") and top_package != "views_pipeline_core": + return top_package + return None + + +def _extract_requirements_package(req_path: Path) -> str | None: + """Extract package name from requirements.txt, normalizing hyphens to underscores.""" + if not req_path.exists(): + return None + for line in req_path.read_text().splitlines(): + line = line.strip() + if line and not line.startswith("#"): + pkg_name = re.split(r"[><=!~@]", line)[0].strip() + return pkg_name.replace("-", "_") + return None + + +class TestAlgorithmManagerCoherence: + """Risk C-04: config_meta['algorithm'] must be consistent with main.py manager import.""" + + def test_algorithm_is_in_known_mapping(self, model_dir): + """The declared algorithm must appear in the known algorithm-to-package mapping.""" + module = load_config_module(model_dir / "configs" / "config_meta.py") + algorithm = module.get_meta_config()["algorithm"] + assert algorithm in ALGORITHM_TO_PACKAGE, ( + f"{model_dir.name}: algorithm '{algorithm}' is not in the known " + f"algorithm-to-package mapping. If this is a new algorithm, add it " + f"to ALGORITHM_TO_PACKAGE in test_algorithm_coherence.py." + ) + + def test_algorithm_matches_manager_package(self, model_dir): + """The algorithm's expected package must match the package actually imported in main.py.""" + module = load_config_module(model_dir / "configs" / "config_meta.py") + algorithm = module.get_meta_config()["algorithm"] + if algorithm not in ALGORITHM_TO_PACKAGE: + pytest.skip(f"Algorithm '{algorithm}' not in mapping") + + expected_package = ALGORITHM_TO_PACKAGE[algorithm] + actual_package = _extract_manager_package(model_dir / "main.py") + + assert actual_package is not None, ( + f"{model_dir.name}: could not extract manager package from main.py" + ) + assert actual_package == expected_package, ( + f"{model_dir.name}: algorithm '{algorithm}' belongs to '{expected_package}' " + f"but main.py imports from '{actual_package}'" + ) + + +class TestRequirementsCoherence: + """Risk C-08: requirements.txt package must match main.py import package.""" + + def test_requirements_package_matches_import(self, model_dir): + """The package in requirements.txt must match the package imported in main.py.""" + req_path = model_dir / "requirements.txt" + if not req_path.exists(): + pytest.skip(f"{model_dir.name} has no requirements.txt") + + req_package = _extract_requirements_package(req_path) + import_package = _extract_manager_package(model_dir / "main.py") + + assert req_package is not None, ( + f"{model_dir.name}: could not extract package from requirements.txt" + ) + assert import_package is not None, ( + f"{model_dir.name}: could not extract manager package from main.py" + ) + assert req_package == import_package, ( + f"{model_dir.name}: requirements.txt declares '{req_package}' " + f"but main.py imports from '{import_package}'" + ) diff --git a/tests/test_cli_pattern.py b/tests/test_cli_pattern.py index 224ac118..65f4e437 100644 --- a/tests/test_cli_pattern.py +++ b/tests/test_cli_pattern.py @@ -7,7 +7,13 @@ import pytest -from tests.conftest import ALL_MODEL_DIRS, MODEL_NAMES +from tests.conftest import ( + ALL_MODEL_DIRS, ALL_ENSEMBLE_DIRS, + MODEL_NAMES, ENSEMBLE_NAMES, +) + +ALL_DIRS = ALL_MODEL_DIRS + ALL_ENSEMBLE_DIRS +ALL_NAMES = MODEL_NAMES + ENSEMBLE_NAMES def _find_imports_from(tree: ast.AST, module: str) -> list[ast.ImportFrom]: @@ -32,24 +38,35 @@ def _find_attribute_calls(tree: ast.AST, obj: str, method: str) -> list[ast.Call class TestCLIPattern: - @pytest.mark.parametrize("model_dir", ALL_MODEL_DIRS, ids=MODEL_NAMES) - def test_uses_new_cli_import(self, model_dir): - """All models should import from views_pipeline_core.cli, not cli.utils.""" - source = (model_dir / "main.py").read_text() + @pytest.mark.parametrize("any_dir", ALL_DIRS, ids=ALL_NAMES) + def test_uses_new_cli_import(self, any_dir): + """All models and ensembles should import from views_pipeline_core.cli, not cli.utils.""" + source = (any_dir / "main.py").read_text() tree = ast.parse(source) old_imports = _find_imports_from(tree, "views_pipeline_core.cli.utils") assert len(old_imports) == 0, ( - f"{model_dir.name}/main.py uses old CLI pattern " + f"{any_dir.name}/main.py uses old CLI pattern " "(views_pipeline_core.cli.utils). Migrate to ForecastingModelArgs." ) - @pytest.mark.parametrize("model_dir", ALL_MODEL_DIRS, ids=MODEL_NAMES) - def test_no_explicit_wandb_login(self, model_dir): - """Models should not call wandb.login() directly — the manager handles it.""" - source = (model_dir / "main.py").read_text() + @pytest.mark.parametrize("any_dir", ALL_DIRS, ids=ALL_NAMES) + def test_no_explicit_wandb_login(self, any_dir): + """Models and ensembles should not call wandb.login() directly — the manager handles it.""" + source = (any_dir / "main.py").read_text() tree = ast.parse(source) wandb_login_calls = _find_attribute_calls(tree, "wandb", "login") assert len(wandb_login_calls) == 0, ( - f"{model_dir.name}/main.py calls wandb.login() explicitly. " + f"{any_dir.name}/main.py calls wandb.login() explicitly. " "Remove it — the manager handles authentication." ) + + @pytest.mark.parametrize("any_dir", ALL_DIRS, ids=ALL_NAMES) + def test_no_global_warning_suppression(self, any_dir): + """Models and ensembles must not globally suppress warnings (ADR-008).""" + source = (any_dir / "main.py").read_text() + tree = ast.parse(source) + suppression_calls = _find_attribute_calls(tree, "warnings", "filterwarnings") + assert len(suppression_calls) == 0, ( + f"{any_dir.name}/main.py calls warnings.filterwarnings() — " + f"this contradicts ADR-008 (Observability)" + ) diff --git a/tests/test_failure_modes.py b/tests/test_failure_modes.py index f1ad4712..693c49cb 100644 --- a/tests/test_failure_modes.py +++ b/tests/test_failure_modes.py @@ -2,10 +2,13 @@ These tests use temporary files to inject failures and verify that the config loading infrastructure fails loudly rather than silently. +Addresses CIC failure modes for CatalogExtractor and config loading. """ +import subprocess + import pytest -from tests.conftest import load_config_module +from tests.conftest import load_config_module, REPO_ROOT class TestConfigLoadingSyntaxError: @@ -42,3 +45,53 @@ def test_function_returning_non_dict_is_loadable(self, tmp_path): module = load_config_module(bad_return) result = module.get_meta_config() assert not isinstance(result, dict) + + def test_empty_config_file_loads_without_functions(self, tmp_path): + """An empty config file loads as a module but has no callable functions.""" + empty = tmp_path / "config_meta.py" + empty.write_text("") + module = load_config_module(empty) + assert not hasattr(module, "get_meta_config") + assert not hasattr(module, "get_hp_config") + assert not hasattr(module, "generate") + + def test_config_with_import_error_raises(self, tmp_path): + """A config that imports a non-existent module must raise ImportError.""" + bad_import = tmp_path / "config_meta.py" + bad_import.write_text("from nonexistent_package import something\n") + with pytest.raises((ImportError, ModuleNotFoundError)): + load_config_module(bad_import) + + def test_config_with_runtime_error_raises(self, tmp_path): + """A config with top-level code that raises must propagate the error.""" + bad_runtime = tmp_path / "config_meta.py" + bad_runtime.write_text("raise ValueError('bad config')\n") + with pytest.raises(ValueError, match="bad config"): + load_config_module(bad_runtime) + + +class TestIntegrationTestRunnerFailureModes: + """Red-team tests for run_integration_tests.sh (CIC: IntegrationTestRunner). + + Unlike the config loading tests above (which use tmp_path fixtures), + these tests invoke the shell script via subprocess to verify CLI + argument handling and exit code behavior. + """ + + def test_nonexistent_model_exits_with_error(self): + """Requesting a non-existent model must exit with code 1.""" + result = subprocess.run( + ["bash", str(REPO_ROOT / "run_integration_tests.sh"), + "--models", "nonexistent_model_xyz_12345"], + capture_output=True, text=True, timeout=30, + ) + assert result.returncode == 1 + + def test_unknown_flag_exits_with_error(self): + """An unknown CLI flag must exit with code 1.""" + result = subprocess.run( + ["bash", str(REPO_ROOT / "run_integration_tests.sh"), + "--bogus-flag"], + capture_output=True, text=True, timeout=10, + ) + assert result.returncode == 1