diff --git a/reports/register_changelog.md b/reports/register_changelog.md index 0c73e53..d8105ea 100644 --- a/reports/register_changelog.md +++ b/reports/register_changelog.md @@ -321,6 +321,44 @@ difference between it and everything else in this cluster. --- +## v1.12.0 deployed — three concerns get evidence, one of them uncomfortable (2026-08-13) + +The release reached the server, and the redeploy was run as **all three** `server_quickref.md` steps +rather than the tag file alone — which is C-343's entire content. + +**C-331 was already resolved; today it became true in production.** #423 fixed the heartbeat URL and +drilled it with a canary. But a fix merged is not a fix running: the deployed tag still carried the +old form until this release. Both halves were checked on the host — all three sites read +`printf 'url = "%s"' … | curl -K -`, and then `curl -K -` was *executed* on the box. That second +check is the one that mattered: every ping is guarded by `|| true`, so a form this machine's curl +rejected would have silenced the dead-man switch while looking identical to a working one. This is +the C-322/C-324 distinction — fixed-in-code and fixed-in-production are different claims — applied +before anyone had to learn it again. + +**C-348 was measured and stays open, which is the honest disposition.** The host runs Python +**3.12.3**, resolving `tifffile 2026.5.15` / `imagecodecs 2026.5.10` — the current fork, the one +`test-py313` covers. Production has been on the right side of the floor all along. + +Read the reason rather than the result: 3.12.3 is Ubuntu 24.04's system interpreter, and the guide +in force said *"Install Python 3.10+"*. **The server is correct by distro accident, not by +decision** — which is precisely what the entry says, so measuring it does not close it. One +observation is not an assertion, and the next reprovision on a distro shipping 3.11 would silently +install the March-2026 decoder. + +**C-343's instance was clean before we touched anything** — tag file, HEAD and environment all said +v1.11.0. On 2026-08-08 those three disagreed for five days. The instance is remediated; the concern +is not, because #434 (the pre-flight that would *prevent* recurrence) was closed unstarted with +epic #421. Worth stating plainly rather than letting a clean reading imply a fix. + +**C-347's trigger fired and was actioned.** `test-py313` reported green on `development` and on +`main` — the precondition — and was then added to the required-status-check lists on both, with the +result read back rather than assumed. That readback discipline is C-340's, and it is now applied to +branch protection as well as to merge methods. This changelog entry's own pull request is the first +to pass through the new required check, which is the only way to find out that requiring it does not +deadlock every merge. + +--- + ## The Python floor, and a refutation that expired (2026-08-13) `#443` lowered `requires-python` from `>=3.12` to `>=3.11`. Two entries registered: **C-347** diff --git a/reports/technical_risk_register.md b/reports/technical_risk_register.md index f6b7472..d143d02 100644 --- a/reports/technical_risk_register.md +++ b/reports/technical_risk_register.md @@ -1,7 +1,7 @@ # Technical Risk Register **Date:** 2026-03-17 (updated 2026-07-27) -**Last update:** 2026-08-13 — the Python floor dropped to `>=3.11` (#443/#444), registering C-347 (the required CI check decodes with a different codec build than the server), C-348 (nothing asserts the server's interpreter) and C-349 (a config value restated in prose has nothing binding it back). Full narrative history, including corrections and retractions, is in [`register_changelog.md`](register_changelog.md). Keep this line to one sentence: the header is an index, and the search-window guard (`test_falsification_merge_readiness.py`, 8000 chars) is what it protects. New narrative goes in the changelog, never here (#404). +**Last update:** 2026-08-13 — v1.12.0 released and deployed: the Python floor is `>=3.11` on PyPI, C-331 is now exercised on the host rather than only merged, C-347's trigger fired and `test-py313` is a required check on both branches, and C-348 was measured (the server runs 3.12.3, correct by distro accident) but stays open. Full narrative history, including corrections and retractions, is in [`register_changelog.md`](register_changelog.md). Keep this line to one sentence: the header is an index, and the search-window guard (`test_falsification_merge_readiness.py`, 8000 chars) is what it protects. New narrative goes in the changelog, never here (#404). **Source:** 71 audits, reviews, and incidents — multi-expert engineering review, repo assimilation, falsification audits, test reviews, security sweeps, and production incidents. Full list in [`register_changelog.md`](register_changelog.md#where-the-findings-came-from). Add new sources there, not here (#404). **Status:** 349 concern IDs assigned (C-28 merged into C-31, C-107 merged into C-60, C-183 merged into C-44, C-44 merged into C-164, C-03 merged into C-176): 304 resolved-or-demoted, 42 open concerns (0 Tier 1, 4 Tier 2, 12 Tier 3, 20 Tier 4, 6 deferred by design; 4 with fired trigger); 5 demoted to tech-debt backlog 2026-08-04, 8 open disagreements. 167 resolved concerns as full entries + 19 early-archive reference rows + 120 struck-through in active register (299 unique after dedup — 5 appear in both archive and active) + 32 resolved disagreements in archive. 42 disagreement IDs total: 34 resolved, 8 open. **Archive:** Resolved concerns and disagreements are in `archive/technical_risk_register_resolved.md`. @@ -164,7 +164,7 @@ | C-346 | 4 | Four copies of `test_version_not_already_tagged` use a conditional `xfail` that reads as rigorous and is circular — the test runs only when the version is untagged, then asserts it is untagged. Measured green in every reachable state | **Before trusting any `xfail`-marked test as a gate**: name the state that makes it fail. If none does, it is decoration | Test infra | | C-345 | 2 | Verification tooling reported a green suite that was red, twice in one session — a piped `pytest \| tail; echo $?` yields the pipe's status, and a task notification reported "exit code 0" for a run that exited 1 | **When capturing a long-running check's result** — piping it, backgrounding it, or reading a notification instead of an unpiped `$?`. Redirect to a file, capture `$?` unpiped, and grep `^FAILED` as a second reader | Test infra | | ~~C-344~~ | ~~2~~ | ~~`views-deploy`'s `~/.profile` was mode 644 inside a 751 home — every harvest credential (`UCDP_API_TOKEN`, `ACLED_*`, `GDL_API_TOKEN`, `HEARTBEAT_URL`) readable by all four accounts, continuously~~ | Registered and resolved 2026-08-10 (#432): `chmod 600`, verified unreadable from a second account and still readable by the owner. Rotation considered and **declined** by the operator 2026-08-10 — a judgement about who holds the three accounts, not evidence of non-access; revisit if a new shell account appears (C-88) | Credential hygiene | -| ~~C-331~~ | ~~4~~ | ~~`HEARTBEAT_URL` capability URL passed on the curl command line — readable via `/proc`~~ | Resolved 2026-08-10 (#423): all three pings take the URL on stdin via `-K -`; drilled with a canary and a negative control. The entry's own suggested unquoted form was superseded — it truncates at whitespace and sends anyway | Operational monitoring | +| ~~C-331~~ | ~~4~~ | ~~`HEARTBEAT_URL` capability URL passed on the curl command line — readable via `/proc`~~ | Resolved 2026-08-10 (#423): all three pings take the URL on stdin via `-K -`; drilled with a canary and a negative control. The entry's own suggested unquoted form was superseded — it truncates at whitespace and sends anyway. **Deployed and exercised on the host 2026-08-13** with v1.12.0: all three sites verified in the checked-out script, and `curl -K -` itself run on the box — a deployed-but-rejected form would have silenced every ping behind `|| true`, so shipping the fix and running it are different claims (C-322/C-324) | Operational monitoring | | C-332 | 3 | Credential redaction incomplete — `_redact_url` ignores URL userinfo, `zarr_path` interpolated raw into 7 messages, netrc exceptions log contents, `BasicAuth`/`_TokenState` reprs | **Before interpolating any URL, path, or credential-bearing value into a log line or exception message** — that is the act that creates the exposure, not editing these files | Credential hygiene | | C-334 | 3 | Removing a runtime dependency from a published library breaks dependents relying on it transitively — caught pre-release (matplotlib/views-hydranet) | **Before removing any runtime dependency**, grep sibling repos for module-level imports; "nothing under src/ imports it" is not sufficient evidence | Dependency policy | | ~~C-335~~ | ~~2~~ | ~~Nothing watches the data-serving path — green while every consumer gets nothing~~ | Resolved 2026-08-03: Better Stack monitor live and verified (Up, ~27ms, test alert delivered) + serving-freshness.yml for the content half | Operational monitoring | @@ -176,8 +176,8 @@ | ~~C-341~~ | ~~4~~ | ~~Deploy gates only run where someone types pytest — C-320's fix made them skip-with-reason in CI, so they assure only whoever runs the suite at the right moment | **When adding a deploy gate, or relying on one for release assurance:** ~~ | Resolved 2026-08-11 (#424 gave the answerable gates a scheduled runner; #425 deleted the one that could never answer and replaced it with a publish-time guard) | Test infra | | ~~C-342~~ | ~~3~~ | ~~A stale committed `uv.lock` is invisible — `uv sync` (ci.yml:24,42,60,99) rewrites it in place, so CI goes green on a lock that does not match the committed `pyproject.toml` and the stale one stays in git~~ | Resolved 2026-08-11 (#424): `uv lock --check` in the `test` job, before `uv sync`; drilled both directions and the ordering is itself guarded by `tests/test_ci_gates.py` | Dependency policy | | C-343 | 2 | Writing `~/.views-deploy-tag` is not deploying — the server ran v1.10.0 for five days while the tag file said v1.11.0 and views-frames stayed at the frozen 1.0.0. The in-script `git checkout` cannot fix the running script (bash has buffered it) and never runs `uv sync` | **At the next release** — deploy with all three `server_quickref.md` steps, then verify tag file, `git describe --tags` and installed version all agree | Deployment | -| C-347 | 3 | The required CI check exercises a different raster decoder than production — since the 3.11 floor the lock forks, so `test` decodes with `imagecodecs 2026.3.6` while the server uses `2026.5.10`. `test-py313` covers the production line but is **not a required check**, and a red nobody must satisfy is ignorable | **Before the next release tag, and whenever `tifffile` or `imagecodecs` moves in either fork** — confirm `test-py313` is green, and whether it has been added to the required lists on `main` and `development`. Resolved when it is required on both | Test infra | -| C-348 | 3 | Nothing asserts which Python the production server runs, and the floor now admits one that installs a **different raster line**. `preflight.py`, `check_health.py` and `refresh_pipeline.sh` contain no `sys.version_info` check of any kind. Created by #443 — this risk did not exist under `>=3.12` | **At the next server provisioning, Python upgrade on the Hetzner host, or any runbook edit that says `apt install python3`** — pin the interpreter explicitly and record which raster fork it resolves | Server hardening | +| C-347 | 3 | The required CI check exercises a different raster decoder than production — since the 3.11 floor the lock forks, so `test` decodes with `imagecodecs 2026.3.6` while the server uses `2026.5.10`. `test-py313` covers the production line but is **not a required check**, and a red nobody must satisfy is ignorable | **Fired and actioned 2026-08-13.** `test-py313` reported green on `development` and on `main`, and was then added to the required-status-check lists on both (readback verified). Re-opens if the job is renamed or the requirement dropped | Test infra | +| C-348 | 3 | Nothing asserts which Python the production server runs, and the floor now admits one that installs a **different raster line**. `preflight.py`, `check_health.py` and `refresh_pipeline.sh` contain no `sys.version_info` check of any kind. Created by #443 — this risk did not exist under `>=3.12`. **Measured 2026-08-13: the host runs Python 3.12.3 (Ubuntu 24.04's system interpreter), so it resolves `tifffile 2026.5.15` / `imagecodecs 2026.5.10` — the current fork.** Reassuring, and it is an accident: the guide said "Install Python 3.10+" and this distro happened to hand it 3.12. Still OPEN because one observation is not an assertion | **At the next server provisioning, Python upgrade on the Hetzner host, or any runbook edit that says `apt install python3`** — pin the interpreter explicitly and record which raster fork it resolves | Server hardening | | C-349 | 4 | A config value restated in prose has nothing binding it back — `hetzner_deployment_guide.md` said "Install Python 3.10+" for the three months `pyproject.toml` declared `>=3.12`, an instruction producing an environment where the package could not install. The #444 pin guard binds *workflow* pins to `requires-python`; nothing binds *prose* | **When writing a Python version, or any pyproject value, into a guide or ADR** — link to the declaration instead of restating it, or accept that the copy will not be checked | Documentation drift | | C-333 | 4 | UCDP's custom auth header survives a cross-host redirect (`requests` strips only `Authorization`) — credential egress, not log leakage | **Before the next harvester auth review**, or if UCDP announces a host or redirect change — whichever is first | Credential hygiene | | ~~C-303~~ | ~~4~~ | ~~ADR-049 §Validation mandates 3 provenance counters; builder logs only 1~~ | Resolved 2026-06-28 (added `n_excluded_where_prec` and `n_passthrough_where_prec` to builder ledger entry) | ADR-049 provenance | @@ -3279,6 +3279,8 @@ Cross-ref: C-348 (the server-side half of the same question), C-320 (a check tha The deployment guide made this concrete: it said *"Install Python 3.10+"* for the three months the project declared `>=3.12` — an instruction that produced an uninstallable environment, and nothing noticed, because the guide and `pyproject.toml` were each internally consistent and never compared. Fixed in #443 by naming an explicit interpreter. +**Measured, 2026-08-13, during the v1.12.0 redeploy.** `.venv/bin/python` on the host reports **3.12.3**, with `tifffile 2026.5.15` and `imagecodecs 2026.5.10` — the current fork, the same one `test-py313` covers. So production has been on the right side of the floor throughout. Read the *reason* rather than the result: 3.12.3 is Ubuntu 24.04's system Python, and the guide in force said "Install Python 3.10+". The box is correct by distro accident, not by decision, which is the whole content of this entry. **Not resolved:** an observation on one day is not an assertion, and the next reprovision on a distro shipping 3.11 would silently install the March-2026 decoder. + **Tier 3, not 2.** No evidence of a wrong number today, and the two codec lines are two months apart on a mature library rather than a semantic rewrite. But it is a silent, unrecorded determinant of production numeric output, which is why it is not Tier 4. **Note for whoever closes this.** If it becomes a check, it must **skip with a reason** when run off-server rather than pass trivially (C-320). A test that quietly passes everywhere except the one machine it is about would be a new instance of the class it is meant to close.