v0.316.0 shipped it dead. Every shell asked for `?v={{.AssetTag}}`, TestAssetTag_EveryShellUsesIt
passed, and the first live load through the public address rendered `/static/style.css?v=` —
EMPTY. addShellAssetData was called only by executeTemplateLang (the sign-in, claim, recovery,
guest-share and catch-all pages). The dashboard path had never needed it, because layout.html used
to ask for {{.Version}}, which baseData supplies; moving it to {{.AssetTag}} left nothing to
supply the value.
An empty buster is a CONSTANT. It would never have changed again — worse than the per-version one
it replaced, and invisible to a test that only checks the markup. executeTemplate now calls the
same function executeTemplateLang does, which is literally what the v0.255.0 comment above that
call asked for: "setting it at the single choke point every shell renders through means a new
shell cannot miss it". There were two choke points.
TestAssetTag_ReachesTheRenderedPage renders six real URLs through the production router and asserts
the buster is non-empty, 8 hex, and not a version. Red-proved by removing the call again: four
pages fail naming the empty value.
A PATCH VERSION, not a second push of 0.316.0 — the rule this release added, applied to its own
mistake rather than around it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117kRTSgs3rJWUFGxyoWN6Y
This commit is contained in:
1 parent
48d8674876
commit
006ceab58a
3 files changed
+64
No files matched your search
@@ -1,3 +1,19 @@
|
|||||||
|
## v0.316.1 — the asset tag actually reaches the dashboard pages (2026-10-15)
|
||||||
|
|
||||||
|
**MinAgent: 0.155.0** (unchanged). A patch release because **a version number is pushed once** — the
|
||||||
|
rule this release added, applied to its own mistake rather than around it.
|
||||||
|
|
||||||
|
- **v0.316.0 shipped the asset tag dead on every dashboard page.** Every shell asked for
|
||||||
|
`?v={{.AssetTag}}` and the template test passed, but `addShellAssetData` was only ever called by
|
||||||
|
`executeTemplateLang` — the stranger-facing pages. The dashboard path had never needed it, because
|
||||||
|
`layout.html` used to ask for `{{.Version}}`, which `baseData` supplies. The first live page load
|
||||||
|
rendered `/static/style.css?v=` — **empty, which is a constant, and a constant busts nothing.**
|
||||||
|
Found in a browser on the public address; the markup was right and the value was absent.
|
||||||
|
`executeTemplate` now calls the same one function, which is what v0.255.0's own comment asked for.
|
||||||
|
- `TestAssetTag_ReachesTheRenderedPage` asserts the rendered buster is NON-EMPTY, 8 hex and not a
|
||||||
|
version, on six real URLs through the production router. `TestAssetTag_EveryShellUsesIt` checks the
|
||||||
|
markup; it could not see this, and asserting a link exists proves nothing about what it carries.
|
||||||
|
|
||||||
## v0.316.0 — the app page as one column; a version number is pushed once (2026-10-15)
|
## v0.316.0 — the app page as one column; a version number is pushed once (2026-10-15)
|
||||||
|
|
||||||
**MinAgent: 0.155.0** (unchanged — no new agent call). No golden (`09` §3 decision 250). Design:
|
**MinAgent: 0.155.0** (unchanged — no new agent call). No golden (`09` §3 decision 250). Design:
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package web
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@@ -64,6 +65,47 @@ func TestAssetTag_ChangesPerBuild(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestAssetTag_ReachesTheRenderedPage — the half TestAssetTag_EveryShellUsesIt cannot see.
|
||||||
|
//
|
||||||
|
// THIS TEST EXISTS BECAUSE THE SUITE MISSED A DEAD FIX. Every shell asked for
|
||||||
|
// `?v={{.AssetTag}}`, the template test passed, and the first live page load rendered
|
||||||
|
// `/static/style.css?v=` — empty. `addShellAssetData` was called only by executeTemplateLang (the
|
||||||
|
// stranger-facing pages); the dashboard path had never needed it, because layout.html used to ask
|
||||||
|
// for `{{.Version}}`, which baseData supplies. The markup was right and the value was absent, which
|
||||||
|
// is worse than the defect it replaced: an empty buster is a CONSTANT and never busts anything.
|
||||||
|
//
|
||||||
|
// Asserting the link EXISTS proves nothing. Assert it carries a value.
|
||||||
|
//
|
||||||
|
// RED-PROOF (REPORT.md): remove the addShellAssetData call from executeTemplate -> this fails with
|
||||||
|
// an empty tag on every dashboard page. Reverted.
|
||||||
|
func TestAssetTag_ReachesTheRenderedPage(t *testing.T) {
|
||||||
|
s := appPageHarness(t)
|
||||||
|
re := regexp.MustCompile(`/static/style\.css\?v=([^"']*)`)
|
||||||
|
for _, p := range []string{"/apps/adventurelog", "/apps/adventurelog/data", "/apps/grocy",
|
||||||
|
"/apps/grocy/install", "/stacks", "/dashboard"} {
|
||||||
|
rec := appGet(t, s, p)
|
||||||
|
if rec.Code != 200 {
|
||||||
|
continue // a page this harness cannot render is another test's problem
|
||||||
|
}
|
||||||
|
m := re.FindStringSubmatch(rec.Body.String())
|
||||||
|
if m == nil {
|
||||||
|
t.Errorf("%s: no stylesheet link at all", p)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if m[1] == "" {
|
||||||
|
t.Errorf("%s: the stylesheet buster is EMPTY (%q) — an empty buster is a constant and "+
|
||||||
|
"never busts anything", p, m[0])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if m[1] == "0.316.0" || strings.Contains(m[1], ".") {
|
||||||
|
t.Errorf("%s: the buster looks like a version (%q); it must be the per-build tag", p, m[1])
|
||||||
|
}
|
||||||
|
if len(m[1]) != 8 {
|
||||||
|
t.Errorf("%s: buster %q is %d chars, want the 8-hex tag", p, m[1], len(m[1]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestAssetTag_EveryShellUsesIt — the fix is only a fix if the shells ask for it. Before v0.316.0
|
// TestAssetTag_EveryShellUsesIt — the fix is only a fix if the shells ask for it. Before v0.316.0
|
||||||
// two stranger-facing pages used the tag and the other seven shells used `?v={{.Version}}`, which
|
// two stranger-facing pages used the tag and the other seven shells used `?v={{.Version}}`, which
|
||||||
// is exactly the address that did not change between the three 0.315.0 builds.
|
// is exactly the address that did not change between the three 0.315.0 builds.
|
||||||
|
|||||||
@@ -1093,6 +1093,12 @@ func (s *Server) executeTemplate(w http.ResponseWriter, r *http.Request, name st
|
|||||||
// fence for the guest share page, which has no admin session.
|
// fence for the guest share page, which has no admin session.
|
||||||
s.addEscrowBanner(data, r)
|
s.addEscrowBanner(data, r)
|
||||||
s.addMissedBackupBanner(data, r) // R-871 (decision 110)
|
s.addMissedBackupBanner(data, r) // R-871 (decision 110)
|
||||||
|
// The stylesheet cache-buster, for the DASHBOARD shell. executeTemplateLang has called this for
|
||||||
|
// the stranger-facing pages since v0.255.0; this path did not need it while layout.html asked for
|
||||||
|
// `?v={{.Version}}`, which baseData supplies. v0.316.0 moved it to `{{.AssetTag}}` and the first
|
||||||
|
// live load rendered `?v=` — a constant, which is worse than the version it replaced. Both render
|
||||||
|
// paths now go through the one function, which is what v0.255.0's own comment asked for.
|
||||||
|
s.addShellAssetData(data)
|
||||||
lang := s.langFor(r)
|
lang := s.langFor(r)
|
||||||
s.addLanguageData(data, r, lang)
|
s.addLanguageData(data, r, lang)
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|||||||
Reference in new issue
Block a user