Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions docs/ADRs/013_sampled_forecast_wire_contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,49 @@ yet) — consumers must not treat it as authoritative before then. The lift of t
caveat is tracked as a reminder in pipeline-core: their issue #279 (filed
2026-07-19) fires when the first real release ships.

**§2.2a Amendment A2 — run maturity, drafted 2026-08-05, NOT YET IN FORCE.**

Requested by views-postprocessing #133 on behalf of views-faoapi (its ADR-033, epic
#244) so that a consumer can tell a production run from a test one. This clause defines
the field and the cost of adopting it. **It is not adopted, and `contract_version`
remains 1.5.** Nothing in this section describes bytes that ship today.

*The field.* A fourth key inside `provenance`:

| key | type | meaning |
|---|---|---|
| `status` | string | the producing run's maturity in views-models ADR-017's vocabulary — `graduate`, `candidate`, and the rest. Never inferred; absent is not `graduate`. |

*Why this is an amendment and not a free addition.* §2.1 clause 1 opens the header to
new **top-level** keys and closes the three sub-objects. `provenance` is one of them, so
a fourth key is a contract change by this document's own rule. It is purely additive, so
it is a **MINOR** bump — 1.5 → 1.6 — and a reader built for 1.5 still accepts a 1.6
artifact.

*What adoption actually costs, which is the reason it is deferred.* `contract_version`
is written **inside the header bytes**, and §10 pins those bytes. So a MINOR bump is not
a free-standing edit: it rebuilds the golden fixture, and §10 requires all three
implementing repositories to re-vendor the new bytes and re-pin their root hashes
together. The full coordination cost is paid for one optional field.

*Who can stamp it, and it is not this repository.* Hop-B shard headers are the Hop-A
headers **re-embedded untouched** (`contract/wire/sink.py`). This repository forwards
provenance; it does not compose it, and it does not know a run's maturity. Synthesising
one here would be a producer guessing at a fact it was not told — precisely the
inference this platform's declare-don't-infer rule exists to forbid. **The stamp belongs
to the Hop-A producer (views-models),** and this repository's part is to forward it,
which requires no code change once the key is admitted.

*Named trigger for adoption (ADR-014 §4).* Adopt A2 **when the next re-vendor of the
§10 fixture happens for another reason** — the pyarrow fix tracked as register C-72 /
issue #174 is the one currently expected, since it also changes delivered bytes and also
requires all three repos to move together. Riding along costs nothing extra; going alone
costs a three-repo coordination for a field the consumer has stated it only surfaces.
**Owner:** whoever executes that re-vendor. If views-faoapi ever promotes `status` from a
surfaced label to a serving gate, that supersedes this trigger and A2 should be adopted
on its own.


**§2.3 Governance hook.** Changing `sample_count` (wire thinning) or `dtype` on the
**FAO delivery** changes the published HDI/MAP numbers, and is therefore a
**re-baseline event**: it requires sign-off under views-faoapi **ADR-023
Expand Down Expand Up @@ -890,6 +933,18 @@ runs can therefore never touch the live bucket by accident.
Dated events after adoption. Errata correct errors in this document; other entries
record execution progress against it.

- **2026-08-05 — Amendment A2 drafted, not in force (§2.2a; `contract_version` stays
1.5):** views-postprocessing #133 asked for three declared fields on the run manifest —
`maturity`, `source`, and a required schema version. Measured against what is actually
delivered and actually read, **two of the three already ship**, and the third is not
ours to stamp. `source` is `provenance.ensemble`, forwarded from the Hop-A header and
read by views-faoapi as exactly that. The schema version is `contract_version`, present
on the run manifest and in every shard header. Only maturity is missing, it belongs in
`provenance`, and `provenance` is a closed sub-object — hence A2 rather than a silent
addition. The request was written against the manifest; the consumer reads the shard
header. Recorded because an accepted ask nobody re-measured would have produced a
three-repo fixture re-vendor to add two fields that were already there.

- **2026-08-02 — Erratum E2 (§7d links; `contract_version` stays 1.5):** §7d's first
link was **broken and had never resolved**. Issue #158 renamed the cross-repo contract
from `PLATFORM-001` to *the Appwrite Seam Contract* and the rename was applied as a
Expand Down
34 changes: 32 additions & 2 deletions reports/technical_risk_register.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
| Project | views-postprocessing |
| Owner | Dylan Pinheiro / PRIO MD&D Team |
| Last Updated | 2026-08-05 |
| Total Concerns | 84 |
| Open Concerns | 11 |
| Total Concerns | 85 |
| Open Concerns | 12 |
| Resolved Concerns | 73 |

---
Expand Down Expand Up @@ -161,6 +161,36 @@ that indexes only deleted code is noise.

## Open Concerns

### C-85: A cross-repo ask is adopted on its stated terms without anyone measuring the current state

| Field | Value |
|-------|-------|
| ID | C-85 |
| Tier | 3 — no delivery is affected and no wrong data ships. What is at risk is spending a coordinated three-repository change on work that is already done, which is expensive in exactly the currency this platform has least of. |
| Source | #133 execution (2026-08-05) — the ask was re-measured before implementing it |
| Trigger | The next time an issue filed by another repository's seat is picked up for implementation. Before writing code, check what this repository already delivers and what the consumer already reads — the two are stated in the issue and were both wrong last time. |
| Owner | Whoever implements a cross-repo issue. This is a habit, not a mechanism; see below for why no guard is proposed. |
| Location | Not a code defect. #133; ADR-013 §2.2a. |

#133 asked for three declared fields — `maturity`, `source`, a required schema version — and said `_save_contract` ships the forecast run only. It was filed in good faith by the views-faoapi seat, accepted, and carried on the backlog for weeks. Measured on 2026-08-05, before writing anything:

| the ask | the measured state |
|---|---|
| stamp `source`, *"`source="unknown"` is what's live today"* | **already delivered** as `provenance.ensemble`, and views-faoapi reads exactly that key |
| declare a required schema version | **already delivered** as `contract_version` — on the run manifest and in every shard header |
| stamp `maturity` on the run manifest | genuinely missing — but it belongs in the **shard header**, which is where the consumer reads it, and it is **not this repository's to stamp** |
| *"the global historical is not uploaded"* → decide whether FAO stops receiving it | **false.** `_save_contract` uploads it, `category="historical"`, under the same interlock as the forecast. There was no decision to make |

**Two of three fields already shipped, and the decision had no premise.** Had the issue been implemented as written, the cost would have been a `contract_version` bump — which is written *inside* the header bytes that §10 pins — and therefore a rebuild of the golden fixture and a coordinated re-vendor across all three implementing repositories, in order to add two fields that were already there.

**Why the request was wrong is more useful than that it was wrong.** It was not careless. It was written against the **run manifest**, which is the artifact whose name suggests it carries run-level facts. The consumer reads them from the **shard header's `provenance`**, because that is where the producing pipeline's identity travels. Both seats were describing a real need and neither was describing the same object. A cross-repo ask names an artifact in the other repo's vocabulary, and vocabulary is exactly what does not survive the trip.

**No guard is proposed, deliberately.** There is no mechanical check for "is this request still true", and inventing a ceremony — a template, a checklist field — would be process theatre that decays into an unread heading. What made the difference here was reading the consumer's source before writing any, and that is a habit worth writing down rather than automating. Registered so the next person has the worked example instead of the rule.

Cross-refs: **C-72** (the re-vendor this would have triggered, and the trigger A2 now rides on), **C-77** (the historical leg whose correctness is what makes the co-delivery premise false), ADR-013 §2.2a, ADR-014 §4 (the deferral's named trigger), #133, views-faoapi ADR-033 and its register C-169.

---

### C-84: Every identity this repo delivers under dies on 2026-11-17, within 3h35m of the other

| Field | Value |
Expand Down
36 changes: 36 additions & 0 deletions tests/test_falsify_adr013_s2.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import re
from pathlib import Path

import pytest


_ADR = Path(__file__).resolve().parent.parent / "docs" / "ADRs" / "013_sampled_forecast_wire_contract.md"

Expand Down Expand Up @@ -43,3 +45,37 @@ def test_s2_has_no_unexplained_gid_epic():
if "gid/id epic" in s2:
# keeping the phrase requires an inline explanation of what that episode was
assert re.search(r"gid/id epic[^.]{0,200}(identifier|meant|ambigu)", s2)


def test_s2_2a_is_not_secretly_in_force():
"""§2.2a defines a field that does NOT ship. Guard the "does not" (ADR-014 §1).

Amendment A2 admits `provenance.status` and says plainly that it is not adopted and
`contract_version` stays 1.5. That is a claim about the code, written in a document,
and this repository has been caught three times this epic by prose describing work it
had not done — here the risk runs the other way, which is worse: someone implements
A2, ships 1.6, and leaves §2.2a still saying it is not in force. A reader planning
the three-repo re-vendor would then believe it was still owed.

So the guard is bidirectional. Either §2.2a says A2 is unadopted and the code agrees,
or the section was rewritten on adoption and this test must be rewritten with it.
"""
from views_postprocessing.contract.wire.header import _PROVENANCE_KEYS, CONTRACT_VERSION

s2 = _s2()
if "NOT YET IN FORCE" not in s2:
pytest.skip(
"§2.2a no longer declares itself unadopted — A2 was presumably adopted. "
"Rewrite this test against whatever the section now claims; do not delete it."
)

assert CONTRACT_VERSION == "1.5", (
f"§2.2a says `contract_version` remains 1.5; the header declares "
f"{CONTRACT_VERSION}. If A2 (or anything else) was adopted, the ADR is now "
"describing a contract that is not the one shipping."
)
assert "status" not in _PROVENANCE_KEYS, (
"§2.2a says A2 is not in force, but `status` is in the closed provenance keyset. "
"The field shipped and the amendment was never marked adopted — which leaves the "
"§10 golden fixture, three repos' vendored copies, and this document disagreeing."
)
Loading