State after the 2026-08-12 round.
") assert.Contains(t, body, "Owner is frequently on metered mobile internet.
") assert.NotContains(t, body, `\n`) // Stored text is text: it is escaped, never rendered as markup. assert.NotContains(t, body, "otherwise") assert.Contains(t, body, "<b>otherwise</b>") // The freshness line the beads family shares. assert.Contains(t, body, `class="beads-freshness"`) assert.Contains(t, body, "main · last commit") } // The stale? marker is a question asked at exactly 60 days, and it is a constant // rather than a per-request knob: the only way to move it is to edit it. func TestMemoryStaleMarkerAtTheBoundary(t *testing.T) { render := func(t *testing.T, midAge time.Duration) string { t.Helper() pinClock(t, testNow) h := newHarness(t) h.store.add(&core.Repo{Name: "db", OwnerID: 1, OwnerName: "alice", Path: "/d", Visibility: core.VisibilityPublic}) h.browse.sess = memoryFixture(midAge) rec := h.do("GET", "/~alice/db/view/memory?key=metered-link-calibration", nil, nil) require.Equal(t, http.StatusOK, rec.Code, "memory view: %s", rec.Body.String()) return rec.Body.String() } exactly := render(t, 60*24*time.Hour) assert.Contains(t, exactly, "metered-link-calibration") assert.NotContains(t, exactly, "stale?", "at the mark itself the question is not asked") past := render(t, 60*24*time.Hour+time.Second) assert.Contains(t, past, "stale?") assert.Contains(t, past, "60 days ago") fresh := render(t, 3*time.Hour) assert.NotContains(t, fresh, "stale?") assert.Contains(t, fresh, "3 hours ago") } // ?key= renders one memory and not the rest; an unknown slug says so rather than // falling back to the whole list. func TestMemorySingleKey(t *testing.T) { pinClock(t, testNow) h := newHarness(t) h.store.add(&core.Repo{Name: "db", OwnerID: 1, OwnerName: "alice", Path: "/d", Visibility: core.VisibilityPublic}) h.browse.sess = memoryFixture(71 * 24 * time.Hour) one := h.do("GET", "/~alice/db/view/memory?key=handoff-2026-08-12", nil, nil) require.Equal(t, http.StatusOK, one.Code) assert.Contains(t, one.Body.String(), "State after the 2026-08-12 round.") assert.NotContains(t, one.Body.String(), "metered mobile internet") missing := h.do("GET", "/~alice/db/view/memory?key=nosuch", nil, nil) require.Equal(t, http.StatusOK, missing.Code) assert.Contains(t, missing.Body.String(), "No memory named") assert.NotContains(t, missing.Body.String(), "State after the 2026-08-12 round.") } // A tracker whose config holds no memory still gets the tab (Applies sees shapes // and never rows) and renders an empty state that says what writes one. func TestMemoryEmptyState(t *testing.T) { pinClock(t, testNow) h := newHarness(t) h.store.add(&core.Repo{Name: "db", OwnerID: 1, OwnerName: "alice", Path: "/d", Visibility: core.VisibilityPublic}) sess := memoryFixture(71 * 24 * time.Hour) sess.rowsByRef["main"] = map[string]*browse.RowPage{"config": { Columns: []string{"key", "value"}, Rows: [][]string{{"issue_prefix", "demo"}}, Total: 1, }} h.browse.sess = sess rec := h.do("GET", "/~alice/db/view/memory", nil, nil) require.Equal(t, http.StatusOK, rec.Code, "memory view: %s", rec.Body.String()) body := rec.Body.String() assert.Contains(t, body, "No memories.") assert.Contains(t, body, "bd remember") assert.Contains(t, body, "0 entries") // The tab is there either way, and so is the freshness line. assert.Contains(t, body, "/view/memory\"") assert.Contains(t, body, `class="beads-freshness"`) } // The sort toggle is a link that keeps the rest of the query, and the review // queue is oldest first. func TestMemorySortToggle(t *testing.T) { pinClock(t, testNow) h := newHarness(t) h.store.add(&core.Repo{Name: "db", OwnerID: 1, OwnerName: "alice", Path: "/d", Visibility: core.VisibilityPublic}) h.browse.sess = memoryFixture(71 * 24 * time.Hour) bySlug := h.do("GET", "/~alice/db/view/memory?ref=main", nil, nil) require.Equal(t, http.StatusOK, bySlug.Code) assert.Contains(t, bySlug.Body.String(), "/view/memory?ref=main&sort=age", "the toggle keeps ?ref= rather than re-listing the parameters it knows") byAge := h.do("GET", "/~alice/db/view/memory?sort=age", nil, nil) require.Equal(t, http.StatusOK, byAge.Code) body := byAge.Body.String() assert.Less(t, strings.Index(body, "metered-link-calibration"), strings.Index(body, "handoff-2026-08-12"), "age order is oldest first") } // agoDays is the Memory page's spelling of a duration: the same ladder as ago up // to a day, and then days all the way — "71 days ago", never "2 months ago", // because 60 days is the number this page marks memories at. func TestAgoDaysStopsAtDays(t *testing.T) { pinClock(t, testNow) cases := []struct { name string d time.Duration want string }{ {"the instant itself", 0, "just now"}, {"seconds", 45 * time.Second, "just now"}, {"exactly a minute", time.Minute, "1 minute ago"}, {"minutes", 4 * time.Minute, "4 minutes ago"}, {"exactly an hour", time.Hour, "1 hour ago"}, {"hours", 3 * time.Hour, "3 hours ago"}, {"one second short of a day", 24*time.Hour - time.Second, "23 hours ago"}, {"exactly a day", 24 * time.Hour, "1 day ago"}, {"the stale mark", 60 * 24 * time.Hour, "60 days ago"}, {"where ago says two months", 71 * 24 * time.Hour, "71 days ago"}, {"where ago says a year", 365 * 24 * time.Hour, "365 days ago"}, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { assert.Equal(t, c.want, agoDays(testNow.Add(-c.d))) }) } // A commit stamped ahead of this host's clock is skew, not a scheduled event. assert.Equal(t, "just now", agoDays(testNow.Add(48*time.Hour))) }