Public: anyone can read this; the crew can change it.

The search, map, flow and system pages each carry a first-view attention budget that test/attention.test.ts holds #10691

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/10687-the-search-map-flow-and-system-pages-eac → main 3 commits fork 1 thread · 1 unresolved

  • Merged. scout/10687-the-search-map-flow-and-system-pages-eac was merged into main as 52d4c35.

Review

Sign in to review this change.
3 files changed +100 −4
docs/design/attention-budget.json +64
@@ -118,5 +118,69 @@
118118 "blocks": 32,
119119 "colours": 1
120120 }
121 },
122 "search": {
123 "390": {
124 "words": 42,
125 "blocks": 3,
126 "colours": 1
127 },
128 "1280": {
129 "words": 42,
130 "blocks": 3,
131 "colours": 1
132 },
133 "note": "Bare /search, signed in as an admin."
134 },
135 "search results": {
136 "390": {
137 "words": 58,
138 "blocks": 5,
139 "colours": 1
140 },
141 "1280": {
142 "words": 58,
143 "blocks": 5,
144 "colours": 1
145 },
146 "note": "/search?q=forge, signed in as an admin."
147 },
148 "map": {
149 "390": {
150 "words": 68,
151 "blocks": 6,
152 "colours": 6
153 },
154 "1280": {
155 "words": 68,
156 "blocks": 6,
157 "colours": 6
158 }
159 },
160 "flow": {
161 "390": {
162 "words": 102,
163 "blocks": 9,
164 "colours": 1
165 },
166 "1280": {
167 "words": 102,
168 "blocks": 9,
169 "colours": 1
170 },
171 "note": "Measured on the test forge's empty state (no samples seeded, nothing waited for)."
172 },
173 "system": {
174 "390": {
175 "words": 212,
176 "blocks": 65,
177 "colours": 0
178 },
179 "1280": {
180 "words": 212,
181 "blocks": 65,
182 "colours": 0
183 },
184 "note": "Measured on the test forge's empty state with the machine reading replaced by an empty one and the two cell-cap sentences fixed (the live page's counts depend on the host's cores, disks, processes and cgroups); nothing seeded or waited for."
121185 }
122186 }
docs/features/attention.md +8 −1
@@ -30,7 +30,14 @@ reader sees on first view at 390 px and 1280 px: **words**, **text blocks** and
3030 | pulls list | 24 / 6 / 1 | 24 / 6 / 1 |
3131 | runs | 38 / 8 / 1 | 38 / 8 / 1 |
3232 | run | 34 / 11 / 3 | 34 / 11 / 3 |
33 | settings | 137 / 32 / 1 | 137 / 32 / 1 |
33 | settings | 140 / 32 / 1 | 140 / 32 / 1 |
34 | search | 42 / 3 / 1 | 42 / 3 / 1 |
35 | search results (`/search?q=forge`) | 58 / 5 / 1 | 58 / 5 / 1 |
36 | map | 68 / 6 / 6 | 68 / 6 / 6 |
37 | flow | 102 / 9 / 1 | 102 / 9 / 1 |
38 | system | 212 / 65 / 0 | 212 / 65 / 0 |
39
40 `/flow` and `/system` are sampled pages; their entries are the empty state the test forge has (nothing seeded, nothing waited for), and say so in the entry's `note`. `/system` draws the host it runs on, so the test hands it an empty machine reading (`useLive`) and fixed cap sentences; a live `/system` is larger.

Add a blank line after this paragraph; without it the next ## App page, calmed heading is glued to it.

3441
3542 ## App page, calmed (#10299)
3643
test/attention.test.ts +28 −3
@@ -19,12 +19,16 @@ import { createRun } from "../src/core/runs.ts";
1919 import { serve, type Servers } from "../src/http/server.ts";
2020 import { firstView, WIDTHS, type Attention } from "../src/measure/attention.ts";
2121 import { proveAll } from "./helpers/verified.ts";
22 import { useLive, type Live } from "../src/system/live.ts";
23 import type { SystemView } from "../src/system/view.ts";
2224 import { quietLogs } from "./helpers/globals.ts";
2325
2426 quietLogs();
2527
2628 const BUDGET = "docs/design/attention-budget.json";
2729 type Budget = Record<string, Record<string, Attention>>;
30 // An entry may carry a "note" string beside its widths; it is read by people only.
31 const widthsOf = (entry: object): string[] => Object.keys(entry).filter((k) => k !== "note");
2832
2933 let root = "";
3034 let app: App;
@@ -33,6 +37,19 @@ let cookie = "";
3337 let pages: Record<string, string> = {};
3438 const seen: Budget = {};
3539
40 // /system draws the machine it runs on (cores, disks, processes, whether the
41 // kernel caps cells), so the same code counts differently on every host. The
42 // test hands it an empty reading and one fixed sentence for each cap line.
43 const emptyView: SystemView = {
44 at: "", seconds: 0, cpu: { busyPct: null, cores: [], history: [] }, temps: [], hottestC: null, load: null,
45 memory: null, disks: [], net: [], io: [], processes: 0, groups: [], duplicates: [],
46 };
47 const fixedLive: Live = {
48 read: () => emptyView, subscribe: () => () => {}, running: () => false, publish: () => {},
49 };
50 const fixedCaps = (html: string): string =>
51 html.replace(/<p class="small" id="(cell-caps|cell-pids)"[^>]*>[\s\S]*?<\/p>/g, '<p class="small" id="$1">Each cell is capped.</p>');
52
3653 beforeAll(async () => {
3754 root = mkdtempSync(join(tmpdir(), "forge-attention-"));
3855 app = createApp({ dataDir: root, port: 0, forgeRepo: "alice/forge" });
@@ -59,6 +76,7 @@ beforeAll(async () => {
5976 const pull = await openPull(app, u.value, repo, { title: "Add x", baseBranch: "main", headBranch: "feature/x" });
6077 if (!pull.ok) throw new Error(String(pull.error));
6178 const run = createRun(app.db, { repoId: repo.id, kind: "check", env: "main", commitOid: "0".repeat(40), reason: "push" });
79 useLive(fixedLive);
6280 servers = await serve(app);
6381 const signin = await fetch(`${servers.url}/signin`, {
6482 method: "POST", headers: { origin: servers.url },
@@ -70,11 +88,13 @@ beforeAll(async () => {
7088 home: "/", repository: r, app: `${r}/app`, pull: `${r}/pulls/${pull.value.number}`,
7189 issue: `${r}/issues/${issue.value.number}`, "issues list": `${r}/issues`, "pulls list": `${r}/pulls`,
7290 runs: `${r}/runs`, run: `${r}/runs/${run.id}`, settings: "/settings",
91 search: "/search", "search results": "/search?q=forge", map: "/map", flow: "/flow", system: "/system",
7392 };
7493 for (const [name, path] of Object.entries(paths)) {
7594 const res = await fetch(`${servers.url}${path}`, { headers: { cookie }, redirect: "follow" });
7695 if (res.status !== 200) throw new Error(`${name} ${path} answered ${res.status}`);
77 pages[name] = await res.text();
96 const text = await res.text();
97 pages[name] = name === "system" ? fixedCaps(text) : text;
7898 }
7999 });
80100 afterAll(() => {
@@ -88,7 +108,12 @@ test("each page stays inside its first-view budget", () => {
88108 seen[name] = {};
89109 for (const w of WIDTHS) seen[name]![String(w)] = firstView(html, w);
90110 }
91 if (process.env.FORGE_ATTENTION_WRITE === "1") writeFileSync(BUDGET, `${JSON.stringify(seen, null, 2)}\n`);
111 if (process.env.FORGE_ATTENTION_WRITE === "1") {
112 const old = JSON.parse(readFileSync(BUDGET, "utf8")) as Record<string, { note?: string }>;
113 const out: Record<string, unknown> = {};
114 for (const [n, v] of Object.entries(seen)) out[n] = old[n]?.note ? { ...v, note: old[n]!.note } : v;
115 writeFileSync(BUDGET, `${JSON.stringify(out, null, 2)}\n`);
116 }
92117 const budget = JSON.parse(readFileSync(BUDGET, "utf8")) as Budget;
93118 const rows: string[] = ["page".padEnd(13) + "width words blocks colours"];
94119 const over: string[] = [];
@@ -110,5 +135,5 @@ test("the budget file names every page at both widths and no other", () => {
110135 // A budget for every page at both widths, and no stale page in the file.
111136 const budget = JSON.parse(readFileSync(BUDGET, "utf8")) as Budget;
112137 expect(Object.keys(budget).sort()).toEqual(Object.keys(pages).sort());
113 for (const name of Object.keys(budget)) expect(Object.keys(budget[name]!)).toEqual(WIDTHS.map(String));
138 for (const name of Object.keys(budget)) expect(widthsOf(budget[name]!)).toEqual(WIDTHS.map(String));
114139 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs