diff --git a/docs/ADRs/013_sampled_forecast_wire_contract.md b/docs/ADRs/013_sampled_forecast_wire_contract.md index 7d2cf02..2ee920a 100644 --- a/docs/ADRs/013_sampled_forecast_wire_contract.md +++ b/docs/ADRs/013_sampled_forecast_wire_contract.md @@ -689,14 +689,23 @@ a "simplification." this contract governs the **data** crossing the Appwrite seam; the **identity/config** crossing the same seam (which key, which coordinates, sourced from where, named how) is governed by - **[the Appwrite Seam Contract — Identity, Secrets & Configuration Contract (VIEWS Appwrite seam)](https://github.com/views-platform/views-appwrite/blob/main/docs/ADRs/platform/the Appwrite Seam Contract_identity_secrets_configuration_contract.md)**, - homed in views-appwrite and referenced here **by URL, never by copy** — with its - coordinate registry - ([`coordinate_registry.toml`](https://github.com/views-platform/views-appwrite/blob/main/docs/ADRs/platform/coordinate_registry.toml)) + **[the Appwrite Seam Contract](https://github.com/views-platform/views-appwrite/blob/b54928f/docs/ADRs/platform/appwrite_seam_contract.md)**, + homed in views-appwrite and referenced here **by pinned URL, never by copy** — + with its coordinate registry + ([`coordinate_registry.toml`](https://github.com/views-platform/views-appwrite/blob/b54928f/docs/ADRs/platform/coordinate_registry.toml), v1.4.0) as the canonical source of the non-secret coordinates this repo's runtime resolves. This repo's declared environment (`unfao/appwrite_env.py`, fail-loud entry validation) follows that registry's names. + **Corrected 2026-08-02 (#184).** Both links were previously unpinned (`/blob/main/`), + and the first was **broken**: #158's rename of `PLATFORM-001` → *the Appwrite Seam + Contract* was applied as a blanket find-and-replace and rewrote the **filename inside + the URL**, producing a path containing spaces that could not resolve. The upstream file + has since been renamed to `appwrite_seam_contract.md` independently. Both now point at + a pinned commit, which is what "referenced by URL, never by copy" was always supposed + to mean — an unpinned `main` link drifts silently, and the registry moved 1.3.0 → 1.4.0 + on 2026-08-02. + --- ## §8 Non-goals (with recorded deferred intents) @@ -857,6 +866,20 @@ 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-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 + blanket find-and-replace, which rewrote the **filename inside the URL** — producing + `.../platform/the Appwrite Seam Contract_identity_secrets_configuration_contract.md`, + a path containing spaces. #158 was then closed while four `PLATFORM-001` citations + also survived in this repo's `.py`, one of them inside the message raised by + `appwrite_env.assert_env_declared`. Corrected in place (dated marker in §7d): the + upstream file is `appwrite_seam_contract.md`, and **both** §7d links are now pinned to + views-appwrite `b54928f` (registry v1.4.0) rather than tracking `main`. §7d claimed + *"referenced by URL, never by copy"* — true in letter and false in effect while an + unpinned link could drift under it, which it did: the registry moved 1.3.0 → 1.4.0 on + this date. `tests/test_doc_accuracy.py` now refuses the retired name in code. + (#184, epic #181.) - **2026-07-15 — §4.1a's recorded inconsistency CONFIRMED live.** During the Hop-B legacy-guard work (faoapi PR #200), a read-only audit of the live `unfao_bucket` found **six `orange_ensemble`-named forecast documents** stranded by the `name` diff --git a/tests/test_doc_accuracy.py b/tests/test_doc_accuracy.py index eb24a5e..2203627 100644 --- a/tests/test_doc_accuracy.py +++ b/tests/test_doc_accuracy.py @@ -149,3 +149,47 @@ def test_contract_package_does_not_import_the_partner(): f"contract/ imports the partner package: {offenders}. The machinery must be " "reusable by views-crafdapi / views-productionapi without taking FAO (C-69)." ) + + +# --- 3. retired cross-repo contract name (S3 / #184, finishing #158) -------------------- + +#: Retired 2026-07-31. The registry itself records the retirement: +#: ``former_contract_name = "PLATFORM-001" # retired 2026-07-31``. +_RETIRED_CONTRACT_NAME = "PLATFORM-001" + + +def test_the_retired_contract_name_is_gone_from_code(): + """A citation naming a contract that no longer exists sends the reader nowhere. + + #158 renamed ``PLATFORM-001`` to *the Appwrite Seam Contract* and was closed on + 2026-08-01 — but only the documentation half landed. Four references survived in + ``.py``, and one of them was **inside the message raised by + ``appwrite_env.assert_env_declared``**: the text an operator reads when a delivery + refuses to launch, pointing them at a retired name in a repo they do not own, on + the day their run failed. + + "Code" means all three roots that hold Python here — the package, the tests, and + ``scripts/`` (which builds the committed GAUL artifact and the §10 golden fixture). + Scanning fewer roots than the name claims is register **C-74**'s defect, found the + same day this test was written: a guard whose declared scope exceeds its actual + scan passes because the unscanned part happens to be clean. + + ``docs/ADRs/`` and ``reports/`` are deliberately excluded. They legitimately use + the old name when narrating what was decided under it — an ADR describing a 2026-07 + decision correctly says what the thing was called in 2026-07. Code has no such + excuse: it speaks in the present tense to whoever is reading it now. + """ + offenders = [] + roots = (_PKG, _REPO / "tests", _REPO / "scripts") + for source in sorted(f for root in roots for f in root.rglob("*.py")): + if source.resolve() == Path(__file__).resolve(): + continue # this file names it in order to ban it + for number, line in enumerate(source.read_text().splitlines(), 1): + if _RETIRED_CONTRACT_NAME in line: + offenders.append(f"{source.relative_to(_REPO)}:{number}") + assert not offenders, ( + f"{_RETIRED_CONTRACT_NAME!r} was retired on 2026-07-31 and must not appear in " + f"code: {offenders}. Use 'the Appwrite Seam Contract' and cite the registry by " + "pinned URL (views-appwrite/docs/ADRs/platform/coordinate_registry.toml). " + "Historical narration belongs in docs/ADRs or reports/, not here." + ) diff --git a/tests/test_env_declaration.py b/tests/test_env_declaration.py index 8ba81f6..17a23ba 100644 --- a/tests/test_env_declaration.py +++ b/tests/test_env_declaration.py @@ -183,8 +183,9 @@ def test_the_environment_refusal_logs_names_and_never_values(monkeypatch, caplog ) -def test_secret_env_names_follow_the_platform_naming_rule(): - # PLATFORM-001 D3: suffix _API_KEY/_PASSWORD/_TOKEN ⇒ secret. Exactly one +def test_secret_env_names_follow_the_seam_contract_naming_rule(): + # þing-01 D3, the Appwrite Seam Contract §3 ("Classification — declared, never + # inferred"): suffix _API_KEY/_PASSWORD/_TOKEN marks a secret. Exactly one # declared name is a secret; every other declared name is a coordinate. declared = set( appwrite_env.CONNECTION_ENV + appwrite_env.PROD_FORECASTS_ENV + appwrite_env.UNFAO_ENV diff --git a/tests/test_redaction_guard.py b/tests/test_redaction_guard.py index c3cfda7..5283f33 100644 --- a/tests/test_redaction_guard.py +++ b/tests/test_redaction_guard.py @@ -1,5 +1,5 @@ """Guards born from the þing-01 delivery-log/provenance redaction audit (#135, -orð_09 §3 commitment; PLATFORM-001 multi-carrier redaction clause). +orð_09 §3 commitment; the Appwrite Seam Contract's multi-carrier redaction clause). The audit (2026-07-28) found the delivery clean: no credential in any carrier — log lines carry filenames/run_ids/counts/regions, and the provenance description diff --git a/views_postprocessing/unfao/appwrite_env.py b/views_postprocessing/unfao/appwrite_env.py index b60a28d..d5eaf80 100644 --- a/views_postprocessing/unfao/appwrite_env.py +++ b/views_postprocessing/unfao/appwrite_env.py @@ -1,7 +1,16 @@ """The Appwrite-seam environment this package requires, DECLARED (þing-01 P1, #134). -Names follow the PLATFORM-001 coordinate registry (connection + target classes) -plus the one operator-issued secret slot. The LAUNCHER assembles the environment +Names follow **the Appwrite Seam Contract**'s coordinate registry (connection + +target classes) plus the one operator-issued secret slot. The contract is homed in +views-appwrite and referenced by pinned URL, never copied — copies were the +platform's original failure (þing-01 sáttmál S6): + + https://github.com/views-platform/views-appwrite/blob/b54928f/docs/ADRs/platform/coordinate_registry.toml + +That pin is registry **v1.4.0**. A pinned URL does not rot, but it does go stale — +naming the version is what makes the staleness legible to a reader here. + +The LAUNCHER assembles the environment (views-models M3: run.sh reads the owned registry; the secret stays the operator slot) — this package loads no dotenv and validates fail-loud instead (verdict D6). The old implicit borrow (`load_dotenv(ensemble_path_manager.dotenv)`) was the @@ -64,9 +73,10 @@ def assert_env_declared(names: tuple, *, store: str) -> None: # APPWRITE_DATASTORE_API_KEY secret slot. err_msg = ( f"{store}: the launcher did not assemble the required environment — " - f"missing {missing}. Coordinates come from the PLATFORM-001 registry " - "(views-models run.sh declares its sourcing); the secret is the " - "operator slot. This package no longer loads any dotenv (#134)." + f"missing {missing}. Coordinates come from the Appwrite Seam Contract's " + "coordinate registry, homed in views-appwrite (views-models run.sh " + "declares its sourcing); the secret is the operator slot. This package " + "no longer loads any dotenv (#134)." ) logger.error(err_msg) # ADR-008: logged persistently AND raised raise EnvironmentError(err_msg)