Testing plan wave 0: close two live defects, hard-block outbound sends, gate the prod path #88

Merged
emi merged 5 commits from test/wave0-safety-and-gating into dev 2026-08-02 01:28:15 +00:00
2 changed files with 38 additions and 2 deletions
Showing only changes of commit e377c4de03 - Show all commits

View file

@ -6,7 +6,7 @@ pages:
about: about:
title: "About Thermograph: how the weather grades are calculated" title: "About Thermograph: how the weather grades are calculated"
description: >- description: >-
How Thermograph works: ~45 years of ERA5 climate history, a ±7-day How Thermograph works: ~45 years of ERA5 climate history, a ±7-day
seasonal window, and empirical percentiles that grade each day relative to seasonal window, and empirical percentiles that grade each day relative to
its own location. its own location.
privacy: privacy:
@ -21,7 +21,7 @@ pages:
temperatures by month, all-time records, and how today's weather compares temperatures by month, all-time records, and how today's weather compares
to local history. to local history.
glossary_index: glossary_index:
title: "Weather & climate glossary: heat index, feels-like, percentile, and more" title: "Weather & climate glossary: heat index, feels-like, percentile, and more"
description: >- description: >-
Plain-language definitions of weather and climate terms: climate normal, Plain-language definitions of weather and climate terms: climate normal,
percentile, temperature anomaly, feels-like, heat index, wind chill, percentile, temperature anomaly, feels-like, heat index, wind chill,

View file

@ -3,6 +3,7 @@ package contentdata
import ( import (
"os" "os"
"path/filepath" "path/filepath"
"regexp"
"testing" "testing"
) )
@ -109,3 +110,38 @@ func TestLoadRealContentFiles(t *testing.T) {
} }
} }
} }
// pages.yaml's title/description are interpolated as plain strings into
// <title> and <meta name="description"> (base.html.tmpl), so html/template
// escapes them. An HTML entity written in the YAML is therefore escaped a
// second time and the user sees the literal source: "&plusmn;7-day" in the
// SERP snippet, "Weather &amp; climate glossary" in the browser tab. Both
// shipped live until this test existed.
//
// glossary.yaml's `body` is deliberately NOT checked: it is typed
// template.HTML (see glossary_term.html.tmpl) and rendered raw, so entities
// and <b> tags there are correct and must stay.
func TestRealPagesHaveNoDoubleEscapedEntities(t *testing.T) {
dir := filepath.Join("..", "..", "..", "content")
if _, err := os.Stat(filepath.Join(dir, "pages.yaml")); err != nil {
t.Skipf("real content dir not available: %v", err)
}
pages, err := LoadPages(dir)
if err != nil {
t.Fatalf("LoadPages(real): %v", err)
}
// Named (&amp;), decimal (&#177;) and hex (&#xB1;) entity forms.
entity := regexp.MustCompile(`&([a-zA-Z][a-zA-Z0-9]*|#[0-9]+|#[xX][0-9a-fA-F]+);`)
for key, p := range pages {
for field, value := range map[string]string{
"title": p.Title, "description": p.Description,
} {
if m := entity.FindString(value); m != "" {
t.Errorf("pages.yaml[%s].%s contains the HTML entity %q; "+
"write the character literally (this field is escaped at "+
"render time, so the entity reaches the user as source)",
key, field, m)
}
}
}
}