Skip to content

S1 — Delete the retired delivery path; refuse an incomplete config #149

Closed

Description

@Polichinel

Epic: #148 · Closes C-63, #145 · Resolves C-29 · Unblocks S2–S8

Background

The frame-native contract path won on 2026-07-27 (run-0, global-land, FAO served since). The pandas path it replaced was kept behind a config fork "until run 0 proves the contract path live" (register C-40) and never removed. This story is that removal. It is not new work — it is the named post-run-0 follow-up, four days overdue, and D-11 warned that if it lingers the duplication becomes permanent.

Two independent dispatch axes, four theoretical modes, one used:

Axis Gate Declared by
Historical representation declared_data_format(queryset) == "feature_frame" (unfao.py:130) views-models config_queryset.py:62
Delivery protocol configs.get("wire_contract") (:233, :294, :323, :409, :520) views-models config_meta.py:26

Production declares both. Omitting either silently selects the retired half — that is the inference ADR-003 forbids.

Work

Delete the legacy leg at every fork:

  • _read_forecast_data :236-270 — legacy body; keep the contract call
  • _read_historical_data :134-146 — pandas leg; _read_historical_frame becomes the reader
  • _transform :288-298 — legacy leg (geography attaches at artifact build)
  • _validate :300-348 — both legacy legs; keep the contract assertion + _check_coverage
  • _check_coverage :414-418 — legacy forecast branch
  • _save :523-577 — body becomes return self._save_contract()
  • _append_metadata :276-286, _delivery_description :619-636 — legacy-only
  • LEGACY_FORECAST_FILTERS :29-34
  • _historical_coverage_source :579+ — collapse to the frame branch
  • imports :5, :7, :14 — read_dataframe, PGMDataset, pandas if unreferenced

Add the single refusal. One place, at the manager's entry, raising and naming the missing key — not .get() with a silent default. Follow the shape of appwrite_env.assert_env_declared (unfao/appwrite_env.py:41), which is this repo's existing fail-loud-on-missing-declaration idiom.

Reuse, do not rewrite: _ContractStorePort (:37-77) already carries the fail-loud upload guard that #145 asks for; _unfao_appwrite_config() (:499) already builds the config the deleted legacy body duplicated verbatim; _save_contract (:442) is the surviving path.

Do not touch unfao/enrichment.py or unfao/extraction.py in this story — S3 and S4 handle them once the callers are gone.

Acceptance criteria

  • unfao/managers/unfao.py < 450 lines (from 636)
  • Zero wire_contract / data_format branches outside the single refusal
  • A launch config missing either key raises, naming the key — new test asserts this
  • #145's silent uploads are gone: no dsm.upload_data(...) whose result is discarded
  • test_hop_b_sink_e2e.py byte-parity unchanged and green — proves the surviving path did not move

Testing / validation

  • ruff check .; pytest -q --deselect tests/test_datafactory_deploy_readiness.py — the 5 known local pyarrow byte-parity failures only, no new ones
  • Four test files couple to legacy-only symbols and need rework, not deletion: test_append_metadata.py (12 hits), test_selection_guard.py (3), test_input_integrity_e2e.py (3), test_falsification_fao_notes_relevance.py (1)
  • test_selection_guard.py pins LEGACY_FORECAST_FILTERS as an ADR-013 §11.4 golden string. Re-point it at the ADR's post-adoption record — do not drop the guarantee, the historical fact stays pinned after the code goes.

Risk

The legacy path has no end-to-end test, so it could already be broken and nothing would report it. That cuts both ways: it is also why deleting it is low-risk — unreachability is established by config (config_meta.py:26, config_queryset.py:62), not by test.

ADR-013 §11.4 is satisfied, not violated: it required a type-aware guard live before the first contract upload — both guards merged 2026-07-15, run-0 uploaded 2026-07-27. Deleting the legacy reader retires the selector §11.4 was protecting.

Activity

  1. added 2 commits that reference this issue on Jul 31, 2026
    b2a4f99
    cdf4a42
  2. Polichinel commented on Jul 31, 2026

    @Polichinel
    CollaboratorAuthor

    Done in PR #159 (merged to development). Manager 636→410 lines; 14 config forks → 0 plus one refusal; pandas/PGMDataset gone from the manager. unfao/launch_config.py added — a launcher omitting a key is refused by name and told there is no fallback. #145 closed with it. Register C-63 closed, C-29 resolved. Review found the new module raised without logging (ADR-008) — fixed in-commit with tests asserting the log; C-71 registered for the pre-existing identical gap in appwrite_env.

  3. added 5 commits that reference this issue on Aug 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    implementationCode implementation workstoryA single reviewable unit of an epic

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions