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

"model budget in the terminal > an admin sets and takes back a grant; a person has no such command" passes every time on a loaded check machine #5239

Merged opened this

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

Merged

scout/forge:scout/5198-model-budget-in-the-terminal-an-admin-se → main 2 commits fork 2 threads · 2 unresolved

  • Merged. scout/5198-model-budget-in-the-terminal-an-admin-se was merged into main as 0f65361.

Review

Sign in to review this change.
1 file changed +15 −7
test/tui-model.test.ts +15 −7
@@ -14,7 +14,7 @@ import { createForgeApp } from "../src/tui/forge.ts";
1414 import { headlessTerminal } from "../src/tui/term/terminal.ts";
1515 import type { TuiIdentity } from "../src/tui/session.ts";
1616 import { quietLogs } from "./helpers/globals.ts";
17 import { settleApp } from "./helpers/tui.ts";
17 import { settleApp, settleUntil } from "./helpers/tui.ts";
1818
1919 quietLogs();
2020
@@ -43,6 +43,8 @@ describe("model budget in the terminal", () => {
4343 for (const ch of t) key(ch);
4444 await settleApp(app);
4545 },
46 // Under bun's 5 s test timeout, so a miss shows the screen, not a bare timeout.
outdated

Minor: settleUntil defaults to 20 s, but bun's per-test timeout is 5 s. On a loaded machine a miss shows up as a bare test timeout, not as the helper's "never saw … on screen" dump. Passing { timeoutMs: 4_000 } here keeps the useful failure message.

47 until: (what: string) => settleUntil(app, what, { timeoutMs: 4_000 }),
4648 stop: () => app.stop(),
4749 };
4850 }
@@ -67,15 +69,19 @@ describe("model budget in the terminal", () => {
6769 await rm(dataDir, { recursive: true, force: true });
6870 });
6971
70 const open = async (h: ReturnType<typeof boot>, title: string) => {
72 const open = async (h: ReturnType<typeof boot>, title: string, hint: string, opens = "account name") => {
7173 await h.ctrl("k");
7274 await h.type(title);
75 // Wait for the row to be drawn, then for the prompt Enter opens, rather
76 // than trusting that the frames have caught up.
outdated

Minor: Palette.matches() ranks the commands synchronously at render, so the hint is already on screen once type() settles. This wait rarely does anything. until(opens) on line 78 is the guard that does the work. Keep both if you like, but the comment above overstates what this line protects. Note too that async search results are put in front of the commands while selected stays 0, so a visible hint does not prove the highlighted row is the command.

77 await h.until(hint);
7378 await h.press("enter");
79 await h.until(opens);
7480 };
7581
7682 test("a person sees budget zero and adds their own subscription", async () => {
7783 const h = boot("bob");
78 await open(h, "Model budget");
84 await open(h, "Model budget", "what your crew may spend", "Model budget: $0.");
7985 expect(h.text()).toContain("Model budget: $0.");
8086 await h.press("a");
8187 await h.type("sk-ant-api03-bobkey");
@@ -91,13 +97,13 @@ describe("model budget in the terminal", () => {
9197 test("an admin sets and takes back a grant; a person has no such command", async () => {
9298 const bob = getUserByName(forge.db, "bob")!;
9399 const h = boot("alice");
94 await open(h, "Model grant");
100 await open(h, "Model grant", "give an account dollars");
95101 await h.type("bob");
96102 await h.press("enter");
97103 await h.type("12.5");
98104 await h.press("enter");
99105 expect(getModelGrant(forge.db, bob.id)?.usdPerMonth).toBe(12.5);
100 await open(h, "Model grant");
106 await open(h, "Model grant", "give an account dollars");
101107 await h.type("bob");
102108 await h.press("enter");
103109 await h.type("none");
@@ -108,6 +114,7 @@ describe("model budget in the terminal", () => {
108114 const p = boot("bob");
109115 await p.ctrl("k");
110116 await p.type("Model grant");
117 await p.until("Model grant"); // the palette has drawn the query
111118 expect(p.text()).not.toContain("give an account dollars");
112119 p.stop();
113120 });
@@ -115,13 +122,13 @@ describe("model budget in the terminal", () => {
115122 test("an admin sets an account's ceilings in the terminal; a person has no such command", async () => {
116123 const bob = getUserByName(forge.db, "bob")!;
117124 const h = boot("alice");
118 await open(h, "Model ceiling");
125 await open(h, "Model ceiling", "set an account's dollars");
119126 await h.type("bob");
120127 await h.press("enter");
121128 await h.type("20 5");
122129 await h.press("enter");
123130 expect(getAccountCeiling(forge.db, bob.id)).toEqual({ dailyUsd: 20, perRunUsd: 5 });
124 await open(h, "Model ceiling");
131 await open(h, "Model ceiling", "set an account's dollars");
125132 await h.type("bob");
126133 await h.press("enter");
127134 expect(h.text()).toContain("now $20.00 a day, $5.00 a run");
@@ -135,6 +142,7 @@ describe("model budget in the terminal", () => {
135142 const p = boot("bob");
136143 await p.ctrl("k");
137144 await p.type("Model ceiling");
145 await p.until("Model ceiling");
138146 expect(p.text()).not.toContain("set an account's dollars");
139147 p.stop();
140148 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs