frontend: fix the three inconsistencies the onboarding guide found #99

Merged
admin_emi merged 2 commits from fix/frontend-doc-and-parity-gaps into dev 2026-07-25 21:11:34 +00:00
Owner

Follow-up to #98, which documented these but deliberately didn't fix them.

1. frontend/CLAUDE.md and README.md described a service that isn't deployed

Both described the Python FastAPI/Jinja implementation. The live service is Go (frontend/server/). Both now describe it, state plainly that the Python files at that level are the superseded original, and list the duplicate contract copies they still carry (api_client.py's API_VERSION pin, format.py's F_COUNTRIES).

CLAUDE.md also claimed make test-unit is "the tier CI runs." It isn't — CI's only frontend check is Dockerfile's builder stage running gofmt -l + go vet + go test ./..., so a failing Go test is what fails CI. Corrected.

Deleting the Python is left as an open question rather than done in passing: the Python tiers still run, against fixtures the Go tests share.

2. static/units.js's F_REGIONS was guarded by nothing

Three source files claimed "a test asserts all three stay identical." The only assertion compared the Go set against the backend's Python; nothing read units.js. The sets happened to agree, held in step by convention.

TestFCountriesMatchesUnitsJS now parses it and diffs both directions.

The part worth reviewing: the pre-existing TestFCountriesMatchesBackend skips in CI. The frontend image's build context is frontend/, so backend/ is structurally unreachable from the builder stage — and the builder stage is the only place CI executes these tests. It has always been a checkout-only guard.

static/ is in the context, so frontend/Dockerfile copies units.js into the builder stage specifically so the new assertion runs during the image build. Verified by mutating units.js and confirming the image build fails:

#15 7.421 --- FAIL: TestFCountriesMatchesUnitsJS (0.00s)
#15 7.421     format_test.go:128: static/units.js has "ZZ", ours does not
#15 ERROR: process "... go vet ./... && go test ./..." did not complete successfully: exit code: 1

Also verified failing in the other direction (removing a code) and passing once restored.

3. Both docker-compose.test.yml files pointed at retired image paths

Both defaulted BACKEND_IMAGE_PATH to emi/thermograph-backend/app; the published path is emi/thermograph/backend. Corrected in both.

The frontend harness additionally pinned THERMOGRAPH_BACKEND_TEST_TAG to the split-era v0.0.2-split-ci. Rather than swap one hardcoded pin for another, scripts/backend-for-tests.sh now derives the tag from the checkout — sha-<12hex of git log -1 -- backend/>, the same domain-keyed rule build-push.yml and deploy.yml use — so the harness follows the tree. docker-compose.test.yml requires the variable (:?) instead of defaulting it, so a stale pin can't creep back in silently, and the script fails with a useful message when the derived tag has no published image.

Note the pathspec is :/backend/ (repo-root-relative): a bare backend/ resolves against the script's cwd (frontend/) and would silently match nothing.

4. backend/CLAUDE.md carried the backend half of the same claim

Its F_COUNTRIES bullet said "there is a test asserting this" and pointed at frontend/format.py — the superseded Python. Now names the Go and browser copies and says where each assertion actually runs. Its pct_ordinal bullet likewise now names the Go SSR copy alongside shared.js.

Verification

  • backend suite: 429 passed, 8 skipped
  • frontend: gofmt -l empty, go vet ./... clean, all 7 packages ok
  • frontend image builds; mutation of units.js fails that build (above)
  • make backend-up pulls and serves on the derived tag sha-d4a00099f2fd
  • shellcheck over every *.sh in the tree: zero findings
  • all relative links in the touched docs resolve

One thing I did not fix

make test-integration fails 7 of 16 with 503 against a freshly-booted throwaway backend — the database is empty, so nothing is warm. I reproduced it identically on the old image and path (7 failed / 9 passed both ways), so it predates this change and isn't caused by it. Recorded in docs/onboarding/ as a heads-up; not investigated further.

https://claude.ai/code/session_01AfXqHrxCJLs2D7hpQkiUiJ

Follow-up to #98, which documented these but deliberately didn't fix them. ## 1. `frontend/CLAUDE.md` and `README.md` described a service that isn't deployed Both described the Python FastAPI/Jinja implementation. The live service is Go (`frontend/server/`). Both now describe it, state plainly that the Python files at that level are the superseded original, and list the duplicate contract copies they still carry (`api_client.py`'s `API_VERSION` pin, `format.py`'s `F_COUNTRIES`). `CLAUDE.md` also claimed `make test-unit` is *"the tier CI runs."* It isn't — CI's only frontend check is `Dockerfile`'s builder stage running `gofmt -l` + `go vet` + `go test ./...`, so a failing **Go** test is what fails CI. Corrected. Deleting the Python is left as an open question rather than done in passing: the Python tiers still run, against fixtures the Go tests share. ## 2. `static/units.js`'s `F_REGIONS` was guarded by nothing Three source files claimed *"a test asserts all three stay identical."* The only assertion compared the **Go** set against the backend's Python; nothing read `units.js`. The sets happened to agree, held in step by convention. `TestFCountriesMatchesUnitsJS` now parses it and diffs both directions. **The part worth reviewing:** the pre-existing `TestFCountriesMatchesBackend` **skips in CI**. The frontend image's build context is `frontend/`, so `backend/` is structurally unreachable from the builder stage — and the builder stage is the only place CI executes these tests. It has always been a checkout-only guard. `static/` *is* in the context, so `frontend/Dockerfile` copies `units.js` into the builder stage specifically so the new assertion runs during the image build. Verified by mutating `units.js` and confirming the **image build fails**: ``` #15 7.421 --- FAIL: TestFCountriesMatchesUnitsJS (0.00s) #15 7.421 format_test.go:128: static/units.js has "ZZ", ours does not #15 ERROR: process "... go vet ./... && go test ./..." did not complete successfully: exit code: 1 ``` Also verified failing in the other direction (removing a code) and passing once restored. ## 3. Both `docker-compose.test.yml` files pointed at retired image paths Both defaulted `BACKEND_IMAGE_PATH` to `emi/thermograph-backend/app`; the published path is `emi/thermograph/backend`. Corrected in both. The frontend harness additionally pinned `THERMOGRAPH_BACKEND_TEST_TAG` to the split-era `v0.0.2-split-ci`. Rather than swap one hardcoded pin for another, `scripts/backend-for-tests.sh` now **derives** the tag from the checkout — `sha-<12hex of git log -1 -- backend/>`, the same domain-keyed rule `build-push.yml` and `deploy.yml` use — so the harness follows the tree. `docker-compose.test.yml` requires the variable (`:?`) instead of defaulting it, so a stale pin can't creep back in silently, and the script fails with a useful message when the derived tag has no published image. Note the pathspec is `:/backend/` (repo-root-relative): a bare `backend/` resolves against the script's cwd (`frontend/`) and would silently match nothing. ## 4. `backend/CLAUDE.md` carried the backend half of the same claim Its `F_COUNTRIES` bullet said "there is a test asserting this" and pointed at `frontend/format.py` — the superseded Python. Now names the Go and browser copies and says where each assertion actually runs. Its `pct_ordinal` bullet likewise now names the Go SSR copy alongside `shared.js`. ## Verification - backend suite: **429 passed, 8 skipped** - frontend: `gofmt -l` empty, `go vet ./...` clean, all 7 packages `ok` - frontend image builds; mutation of `units.js` fails that build (above) - `make backend-up` pulls and serves on the derived tag `sha-d4a00099f2fd` - `shellcheck` over every `*.sh` in the tree: **zero findings** - all relative links in the touched docs resolve ## One thing I did not fix `make test-integration` fails 7 of 16 with `503` against a freshly-booted throwaway backend — the database is empty, so nothing is warm. I reproduced it **identically on the old image and path** (7 failed / 9 passed both ways), so it predates this change and isn't caused by it. Recorded in `docs/onboarding/` as a heads-up; not investigated further. https://claude.ai/code/session_01AfXqHrxCJLs2D7hpQkiUiJ
admin_emi added 2 commits 2026-07-25 18:44:26 +00:00
1. CLAUDE.md and README.md described the superseded Python service. Both now
   describe server/ (Go), say plainly that the Python files at that level are
   the original the port was made from, and drop CLAUDE.md's claim that
   `make test-unit` is "the tier CI runs" — CI's only frontend check is the
   Dockerfile builder stage's gofmt + vet + go test.

2. static/units.js's F_REGIONS was guarded by nothing, despite three source
   comments claiming "a test asserts all three stay identical": the only check
   compared the Go set against the backend's Python. TestFCountriesMatchesUnitsJS
   now diffs the browser copy both directions.

   That backend cross-check also skips in CI — the image build context is
   frontend/, so backend/ is unreachable from the builder stage, which is the
   only place CI runs these tests. static/ IS in the context, so the Dockerfile
   copies units.js into the builder and the new assertion runs during the image
   build. Verified by mutating units.js and confirming the build fails.

3. Both docker-compose.test.yml files defaulted to the retired
   emi/thermograph-backend/app path, and the frontend harness pinned the
   split-era v0.0.2-split-ci tag. Path corrected in both. Rather than swap one
   hardcoded pin for another, backend-for-tests.sh now derives the tag from the
   checkout — sha-<12hex of `git log -1 -- backend/`>, the same domain-keyed
   rule build-push.yml and deploy.yml use — and compose requires the variable
   so a stale pin cannot creep back in.

Verified: backend 429 passed/8 skipped; frontend go vet clean and all packages
ok; frontend image builds; `make backend-up` pulls and serves on the derived
tag; shellcheck zero findings across the tree.

Unrelated pre-existing issue noted in the docs, not fixed here:
`make test-integration` fails 7/16 with 503 against a cold throwaway backend
(empty database, nothing warm). Reproduced identically on the old image, so it
predates this change.

Claude-Session: https://claude.ai/code/session_01AfXqHrxCJLs2D7hpQkiUiJ
backend: correct the Fahrenheit-set and pct_ordinal contract notes
All checks were successful
secrets-guard / encrypted (pull_request) Successful in 5s
PR build (required check) / changes (pull_request) Successful in 8s
shell-lint / shellcheck (pull_request) Successful in 7s
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Successful in 1m35s
PR build (required check) / build-backend (pull_request) Successful in 1m47s
PR build (required check) / gate (pull_request) Successful in 2s
259f3f170d
The F_COUNTRIES bullet claimed "there is a test asserting this" and pointed at
frontend/format.py — the superseded Python service. Name the Go and browser
copies that are actually deployed, and state where each assertion really runs:
the backend cross-check skips inside the frontend image build (backend/ is
outside that build context, and the builder stage is the only place CI runs
those tests), while the units.js check does run there.

Claude-Session: https://claude.ai/code/session_01AfXqHrxCJLs2D7hpQkiUiJ
admin_emi merged commit 5f20fba9f5 into dev 2026-07-25 21:11:34 +00:00
admin_emi deleted branch fix/frontend-doc-and-parity-gaps 2026-07-25 21:11:35 +00:00
admin_emi referenced this pull request from a commit 2026-08-01 14:29:41 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Jinemi/thermograph#99
No description provided.