oficina / memoria Public

The footer walk skipped seven routes silently; now it cannot

TestTheFooterStatesTheModelSwitch, in the previous commit, claimed a page
could not skip the egress claim because it walks every declared route.
It could: the walk dropped every route that returned non-200 or had no
footer, and under AppForTest — no sign-in wiring, no Home — seven
declared GET routes 404. Among them /signed-out, /signin/local and
/account/home, which ARE layout pages in production when Home is
configured. The gate was blind to them and said nothing.

The code was right: every one renders through renderHome or sets
ModelOn directly, including the Home library's confirm page (its Bridge
is built with Render: a.renderHome). The GATE was what overclaimed.

Two changes. Every skip must now appear in noLayoutHere with its reason,
and an unlisted skip fails — removing /signed-out's reason goes red,
naming it. And the Home-only pages are rendered, both ways, through the
Home router fixture, where they exist: a renderHome that forgets
ModelOn goes red on /signed-out and /account/home.

Found by probing my own gate while the review of the previous commit ran,
because I had named it to the reviewer as the most likely hole and it
was cheaper to check than to wait.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev 5b1ac4ee2678737b1a596d7b5846957d065195ca parent a8287b5
2 files changed, +69 −0
  • internal/memoria/home_router_test.go +38 −0
  • internal/memoriatest/footer_model_test.go +31 −0

CI passed — run details

CI log
=== vet ===
go vet ./...
=== fmt ===
=== test ===
go test ./...
?   	amadan.net/oficina/memoria/cmd/memoria	[no test files]
ok  	amadan.net/oficina/memoria/internal/memoria	1.204s
ok  	amadan.net/oficina/memoria/internal/memoria/chunk	(cached)
ok  	amadan.net/oficina/memoria/internal/memoria/fact	0.522s
?   	amadan.net/oficina/memoria/internal/memoria/icons	[no test files]
ok  	amadan.net/oficina/memoria/internal/memoria/index	(cached)
ok  	amadan.net/oficina/memoria/internal/memoria/notion	(cached)
ok  	amadan.net/oficina/memoria/internal/memoria/provider	1.128s
ok  	amadan.net/oficina/memoria/internal/memoria/query	(cached)
ok  	amadan.net/oficina/memoria/internal/memoria/seal	(cached)
ok  	amadan.net/oficina/memoria/internal/memoria/sibling	(cached)
ok  	amadan.net/oficina/memoria/internal/memoriatest	1.623s
?   	amadan.net/oficina/memoria/tools/bench	[no test files]
?   	amadan.net/oficina/memoria/tools/drive	[no test files]
?   	amadan.net/oficina/memoria/tools/seed	[no test files]
?   	amadan.net/oficina/memoria/tools/vendorassets	[no test files]
=== migration-check ===
go run github.com/carlosframework/rastrillo/cmd/rastrillo migration check
rastrillo migration check: models and migrations agree
diff --git a/internal/memoria/home_router_test.go b/internal/memoria/home_router_test.go
index 3cb83f9..1a326ad 100644
--- a/internal/memoria/home_router_test.go
+++ b/internal/memoria/home_router_test.go
@@ -300,3 +300,41 @@ func TestHomeSigninClearsOnlyDefinitivelyStaleSession(t *testing.T) {
t.Fatal("stale cookie prevented Home sign-in", target)
}
}
+
+// The footer's egress claim on the pages that exist only when Home is
+// configured. TestTheFooterStatesTheModelSwitch (memoriatest) walks every
+// declared route, but its harness does not configure Home, so these 404
+// there and cannot be checked — this is where they are. They render
+// through renderHome, the Render callback the Home library is given.
+func TestHomePagesStateTheModelSwitch(t *testing.T) {
+ for _, on := range []bool{true, false} {
+ f := newHomeRouterFixture(t)
+ if on {
+ f.app.store.extractor = &recorder{}
+ }
+ f.local(t)
+ checked := 0
+ for _, path := range []string{"/signed-out", "/account/home", "/signin/local"} {
+ w := f.do("GET", path, "")
+ b := w.Body.String()
+ i := strings.Index(b, "<footer")
+ if w.Code != 200 || i < 0 {
+ continue
+ }
+ foot := strings.Join(strings.Fields(b[i:]), " ")
+ if !strings.Contains(foot, "leaves this instance") {
+ continue
+ }
+ checked++
+ if on && (strings.Contains(foot, "no document ever") || !strings.Contains(foot, "TensorX")) {
+ t.Errorf("AI on, %s: footer does not disclose TensorX: %q", path, foot)
+ }
+ if !on && (!strings.Contains(foot, "no document ever") || strings.Contains(foot, "TensorX")) {
+ t.Errorf("AI off, %s: footer does not make the true claim: %q", path, foot)
+ }
+ }
+ if checked == 0 {
+ t.Fatalf("AI on=%v: no Home page rendered a footer with a claim; this proves nothing", on)
+ }
+ }
+}
diff --git a/internal/memoriatest/footer_model_test.go b/internal/memoriatest/footer_model_test.go
index b2adacb..f4f1242 100644
--- a/internal/memoriatest/footer_model_test.go
+++ b/internal/memoriatest/footer_model_test.go
@@ -16,6 +16,25 @@ import (
"amadan.net/oficina/memoria/internal/memoria/provider"
)
+// noLayoutHere is every declared GET route that renders no page layout
+// under this harness, and why. A route missing from here that renders no
+// footer fails the walk.
+var noLayoutHere = map[string]string{
+ "GET /search": "the results fragment, swapped into a page by search.js — no layout",
+ "GET /api/native/session": "JSON for the native client",
+ "GET /native/start": "native sign-in redirect; not wired by AppForTest",
+ "GET /native/authorize": "native sign-in redirect; not wired by AppForTest",
+ "GET /auth/callback": "sign-in redirect; auth is not wired by AppForTest",
+ "GET /auth/verify": "sign-in redirect; auth is not wired by AppForTest",
+ "GET /auth/start": "Home sign-in redirect; Home is not configured here",
+ "GET /auth/finish": "Home sign-in redirect; Home is not configured here",
+ "GET /auth/local/complete": "Home sign-in redirect; Home is not configured here",
+ "GET /signin/local": "Home-only page — covered by memoria.TestHomePagesStateTheModelSwitch",
+ "GET /signed-out": "Home-only page — covered by memoria.TestHomePagesStateTheModelSwitch",
+ "GET /account/home": "Home-only page — covered by memoria.TestHomePagesStateTheModelSwitch",
+ "GET /account/home/confirm": "Home library's own confirm page, rendered through renderHome — covered there",
+}
+
// countingModel is a stand-in model that counts calls and points at any
// "address: " line, as a compliant model would.
type countingModel struct{ calls int }
@@ -80,6 +99,18 @@ func footers(t *testing.T, h http.Handler, docID int64) map[string]string {
body := rec.Body.String()
i := strings.Index(body, "<footer")
if rec.Code != http.StatusOK || i < 0 {
+ // **A skip has to be explained**, or the walk proves less than
+ // it says. Every route below renders no layout under this
+ // harness, for the reason given; anything else that fails to
+ // render a footer is a page this gate cannot see, and it fails
+ // rather than passing quietly. (The first version skipped
+ // silently, and seven routes went unchecked.)
+ if why, ok := noLayoutHere[route]; !ok {
+ t.Errorf("%s returned %d with no footer, and is not a known non-page route; "+
+ "the footer check cannot see it", route, rec.Code)
+ } else if why == "" {
+ t.Errorf("%s: skipped without a reason", route)
+ }
continue
}
// Whitespace collapsed, as a browser renders it: the template wraps