Skip to content

fix(delivery): 255-safe provenance descriptions + loud upload port (#131 findings) - #132

Merged
Polichinel merged 1 commit into
developmentfrom
fix/historical-upload-metadata
Jul 27, 2026
Merged

Polichinel merged 1 commit into
developmentfrom
fix/historical-upload-metadata

Conversation

@Polichinel

Copy link
Copy Markdown
Collaborator

Run-0 verification (#131) found the historical upload stranded as an orphan file: bytes in the bucket, metadata document rejected (description > 255 chars — the C-15 prose prefix), error only logged by the store's graceful degradation, port ledger falsely green.

  • delivery/provenance.compact_description: compact JSON provenance guaranteed ≤255, fail-loud (never truncate silently); both description paths use it; pipeline-core-free and unit-tested.
  • _ContractStorePort.upload now raises on success=False — upstream graceful degradation can't silently strand our artifacts again.

A rerun after this merge heals the gap: dedup is document-keyed, so the orphan (no document) won't block a fresh historical upload. 🤖 Generated with Claude Code

…riptions + loud upload port

Run-0's historical upload stranded an orphan: the file uploaded but Appwrite
rejected its metadata document (description attribute caps at 255 chars; the
prose-prefixed C-15 provenance exceeded it), and the store module's graceful
degradation only logged the error — the port's ledger then falsely claimed
success. Two fixes: provenance.compact_description (delivery/, pipeline-core-
free) emits compact JSON provenance guaranteed <=255 with fail-loud refusal to
truncate, used by both historical description paths; _ContractStorePort.upload
now inspects the OperationResult and RAISES on success=False — upstream
graceful degradation must never silently strand our artifacts.

Refs #131 (run-0 delivery verification).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Polichinel
Polichinel merged commit bf1da86 into development Jul 27, 2026
4 checks passed
@Polichinel
Polichinel deleted the fix/historical-upload-metadata branch July 27, 2026 19:00
Polichinel added a commit that referenced this pull request Jul 31, 2026
…onfig (#159)

Closes #149 and #145; closes register C-63; resolves C-29. Epic #148.

The frame-native contract path replaced the pandas path and won — run-0 delivered
global-land 2026-07-27, FAO served since. The replaced path was kept behind a
config fork "until run 0 proves the contract path live" (C-40) and never removed.
D-11 warned that if it lingered the duplication would become permanent. This is
the removal, not new work.

Two independent axes (wire_contract, data_format) gave four delivery modes;
production used one; omitting either key silently selected the retired half,
because .get() returning None is indistinguishable from a deliberate False. That
is the inference ADR-003 forbids, in the repo that authored it.

  unfao/managers/unfao.py   636 -> 406 lines
  14 config forks           -> 0, plus one refusal
  pandas / PGMDataset       -> gone from the manager

Deleted: the legacy _read_forecast_data body, _read_historical_data's pandas leg,
_append_metadata, _delivery_description, _clip_observed_history, the legacy _save
body (whose AppwriteConfig duplicated _unfao_appwrite_config verbatim), and
LEGACY_FORECAST_FILTERS. _prod_forecasts_datastore lost its name_scoped parameter
— it existed only for the caller that no longer exists (ISP).

Added: unfao/launch_config.py — the launch declarations, asserted not inferred.
Sibling of appwrite_env (that one validates the environment, this one the
delivery mode), same fail-loud shape, dependency-light. A launcher that omits a
key is refused BY NAME and told there is no fallback, so nobody "fixes" it by
setting False.

#145's silent uploads go with the legacy _save: the surviving path uploads only
through _ContractStorePort, which already raises on a failed result — the guard
written after run-0 stranded an invisible orphan (PR #132).

Tests: test_selection_guard.py rewritten to pin the RETIREMENT rather than a
golden string for deleted code, re-pointed at ADR-013's post-adoption record so
the disjointness fact stays checkable, and asserting the Hop-B clause still binds
— retiring our reader must not read as relaxing the consumer's obligation.
test_append_metadata.py deleted (it characterised a deleted method; its docstring
said "keep in lockstep with _append_metadata"). test_launch_config.py added.
Docstring maps in test_input_integrity_e2e.py corrected to the post-#149 tree.

ADR-013: dated post-adoption entry recording the Hop-A retirement, the retired
filter values, and that §11.4's Hop-B clause is untouched.

Review findings addressed in-commit (/review-diff verdict was HOLD):
- launch_config raised without logging — ADR-008:48 requires both. Fixed, with
  tests asserting the log, not just the raise.
- _transform annotated -> list while returning None. Fixed.
- the declaration check ran after _initialize_data_loader; a refused config paid
  for loader construction. Reordered.
Registered C-71: appwrite_env has the identical ADR-008 gap (pre-existing, #134).
Left for scope discipline — the module this one mirrors is now inconsistent with
it, which is worth tracking rather than silently widening S1.

Wire contract untouched: no file under wire/, delivery/ or fixtures/ in the diff.
ruff clean; 303 passed, 41 xfailed, 5 known local pyarrow byte-parity failures
(CI authoritative).

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant