Public: anyone can read this; the crew can change it.
The feed leaves out what happened in an archived repository #3484
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/3477-the-feed-leaves-out-what-happened-in-an → main 1 commit fork 1 thread · 1 unresolved
2 files
changed +30
−2
src/feed/items.ts +15 −1
| @@ -304,7 +304,21 @@ export function candidatesFor( | ||
| 304 | 304 | urgency: 0, |
| 305 | 305 | }); |
| 306 | 306 | } |
| 307 | return out; | |
| 307 | return awake(db, out, repos); | |
| 308 | } | |
| 309 | ||
| 310 | /** | |
| 311 | * Archived things are hidden, not gone (#1838): whatever a sleeping | |
| 312 | * repository did stays out of the feed until it is woken, with no other step. | |
| 313 | */ | |
| 314 | function awake( | |
| 315 | db: Database, | |
| 316 | candidates: Candidate[], | |
| 317 | known: ReadonlyMap<string, Repo>, | |
| 318 | ): Candidate[] { | |
| 319 | const unknown = candidates.map((c) => c.repoId).filter((id) => !known.has(id)); | |
| 320 | const all = new Map([...known, ...getReposByIds(db, unknown)]); | |
| 321 | return candidates.filter((c) => all.get(c.repoId)?.archivedAt == null); | |
| 308 | 322 | } |
| 309 | 323 | |
| 310 | 324 | type Partial = Omit<Candidate, "actor">; |
test/feed.test.ts +15 −1
| @@ -12,7 +12,7 @@ import { createRepo } from "../src/actions/repos.ts"; | ||
| 12 | 12 | import { createSession } from "../src/core/sessions.ts"; |
| 13 | 13 | import { createToken } from "../src/core/tokens.ts"; |
| 14 | 14 | import { recordInteraction } from "../src/core/interactions.ts"; |
| 15 | import type { Repo } from "../src/core/repos.ts"; | |
| 15 | import { moveArchived, type Repo } from "../src/core/repos.ts"; | |
| 16 | 16 | import { createUser, type User } from "../src/core/users.ts"; |
| 17 | 17 | import { serve, type Servers } from "../src/http/server.ts"; |
| 18 | 18 | import { Affinity, affinityFor } from "../src/feed/affinity.ts"; |
| @@ -185,6 +185,20 @@ describe("the feed of a forge", () => { | ||
| 185 | 185 | expect(theirs.map((i) => i.kind).sort()).toEqual(["map", "run"]); |
| 186 | 186 | }); |
| 187 | 187 | |
| 188 | test("an archived repository's news leaves the feed, and returns when woken", async () => { | |
| 189 | const apps = (v: User) => new Set(readFeed(app.db, v).items.map((i) => i.app)); | |
| 190 | expect(apps(bob).has("alice/open")).toBe(true); | |
| 191 | expect(apps(alice).has("alice/secret")).toBe(true); | |
| 192 | expect(moveArchived(app.db, openRepo.id, true)).toBe(true); | |
| 193 | expect(apps(bob).has("alice/open")).toBe(false); | |
| 194 | expect(apps(alice).has("alice/open")).toBe(false); | |
| 195 | expect(apps(alice).has("alice/secret")).toBe(true); | |
| 196 | // Hidden, not gone: its page still answers. | |
| 197 | expect((await api(bobToken, "/alice/open")).status).toBe(200); | |
| 198 | expect(moveArchived(app.db, openRepo.id, false)).toBe(true); | |
| 199 | expect(apps(bob).has("alice/open")).toBe(true); | |
| 200 | }); | |
| 201 | ||
| 188 | 202 | test("items are plain data with a reason and a link", () => { |
| 189 | 203 | for (const i of readFeed(app.db, alice).items) { |
| 190 | 204 | expect(i.id).toMatch(/^[a-z]+:/); |
new above
offline
Correct and small. Later, push this into listEventsVisibleTo so archived events never take window slots. Also note in the README archive section that the feed hides them.