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

Remove isSettingFinding, closeSettingFindings and the sentinel_kept table once #2505 is closed #3664

Merged opened this

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

Merged

mason/forge:mason/3488-remove-issettingfinding-closesettingfind → main 1 commit fork

  • Merged. mason/3488-remove-issettingfinding-closesettingfind was merged into main as c616e57.

Review

Sign in to review this change.
9 files changed +10 −118
README.md +4 −6
@@ -1315,12 +1315,10 @@ until the value is back at the default; nothing else reminds anyone. The
13151315 JSON API and MCP carry the same fact: a setting away from its default has a
13161316 `changed` field (`at`, `by`) in the capacity listing (`listCapacity`).
13171317
1318 A `setting:<key>` finding filed before that is closed on the next pass with a
1319 comment pointing at the capacity page (`closeSettingFindings` in
1320 `crew/setting_finding.ts`). Until it closes it is never a crew run: not
1321 assigned, and left out of the crew's ready list (`isSettingFinding`). It raises
1322 no ask; the capacity page's Put back is the one answer. Both helpers go once no
1323 open setting finding is left, with the unused `sentinel_kept` table.
1318 The `setting:<key>` findings filed before that are all closed; none raises an
1319 ask, and the capacity page's Put back is the one answer. The `sentinel_kept`
1320 table they once used is unread; a migration drops it once the additive rule
1321 (`src/core/releases.json`) allows a drop.
13241322
13251323 - **Board:** a site admin's forge strip shows the open findings and the last
13261324 hunt; a guest or member sees nothing.
src/crew/held.ts −4
@@ -19,7 +19,6 @@
1919 * - `run_cap`: it has used its runs for the day (`guard.ts`).
2020 * - `parked_twice`: the crew parked it twice; it is the planner's (`parks.ts`).
2121 * - `red_fix`: a fix for a red main already covers it (`red_fix.ts`).
22 * - `setting`: a setting's finding, a person's to answer (`setting_finding.ts`).
2322 *
2423 * The direction issue is the planner's standing issue and never a
2524 * builder's; it is left out, not counted.
@@ -40,7 +39,6 @@ import { capReached, runCapOf } from "./guard.ts";
4039 import { interruptionOf } from "./interrupted.ts";
4140 import { PARK_STRIKES, parkedCount } from "./parks.ts";
4241 import { coveredByRedFix } from "./red_fix.ts";
43 import { isSettingFinding } from "./setting_finding.ts";
4442
4543 export const HOLDS = [
4644 "running",
@@ -52,7 +50,6 @@ export const HOLDS = [
5250 "run_cap",
5351 "parked_twice",
5452 "red_fix",
55 "setting",
5653 ] as const;
5754
5855 export type HoldName = (typeof HOLDS)[number];
@@ -131,7 +128,6 @@ export function heldBy(
131128 if (atRunCap(app, repo, issue)) return "run_cap";
132129 if (parkedCount(app.db, repo, issue.id) >= PARK_STRIKES) return "parked_twice";
133130 if (coveredByRedFix(app.db, repo.id, issue)) return "red_fix";
134 if (isSettingFinding(app.db, issue.id)) return "setting";
135131 return null;
136132 };
137133 const by = Object.fromEntries(HOLDS.map((h) => [h, [] as Issue[]])) as Record<
src/crew/sentinel.ts +1 −4
@@ -29,7 +29,6 @@ import { spans } from "../kernel/degraded_history.ts";
2929 import { QUEUE_WAIT_MAX_MS } from "../kernel/vitals.ts";
3030 import { STALE_AFTER_MS } from "../runs/lease.ts";
3131 import { isOutageSummary } from "./network.ts";
32 import { closeSettingFindings } from "./setting_finding.ts";
3332
3433 const log = createLog("sentinel");
3534
@@ -712,10 +711,8 @@ export function hunt(
712711 }
713712 }
714713 }
715 if (repo !== undefined && actor !== undefined) {
714 if (repo !== undefined && actor !== undefined)
716715 closeHeld(app, repo, actor, new Set(findings.map((f) => f.key)), now);
717 closeSettingFindings(app, repo, actor);
718 }
719716 // A hunt with nowhere to file is recorded as such, never as a quiet one.
720717 const unfiled = repo === undefined || actor === undefined;
721718 app.db
src/crew/setting_finding.ts deleted −56
@@ -1,56 +0,0 @@
1 /**
2 * A setting the sentinel found away from its default is the owner's ask
3 * (#2029), never a crew run. The finding is filed by a crew member, so the
4 * autonomy clock would otherwise count it ready and hand it to a builder.
5 */
6
7 import type { Database } from "bun:sqlite";
8 import type { App } from "../app.ts";
9 import { addComment, setIssueState } from "../actions/issues.ts";
10 import { getIssueById } from "../core/issues.ts";
11 import type { Repo } from "../core/repos.ts";
12 import type { User } from "../core/users.ts";
13 import { createLog } from "../kernel/log.ts";
14
15 const log = createLog("sentinel");
16
17 /** Whether this issue is the open finding of a `setting:<key>` the sentinel reported. */
18 export function isSettingFinding(db: Database, issueId: string): boolean {
19 return (
20 db
21 .query<{ n: number }, [string]>(
22 "SELECT 1 AS n FROM sentinel_finding WHERE issue_id = ?1 AND key LIKE 'setting:%'",
23 )
24 .get(issueId) !== null
25 );
26 }
27
28 /**
29 * A setting away from its default is a line on the capacity page, not an
30 * issue (#3269). Findings filed before that are closed, with a pointer.
31 */
32 export function closeSettingFindings(app: App, repo: Repo, actor: User): void {
33 const open = app.db
34 .query<{ issue_id: string }, []>(
35 `SELECT DISTINCT t.issue_id FROM sentinel_finding t JOIN issue i ON i.id = t.issue_id
36 WHERE i.state = 'open' AND t.key LIKE 'setting:%'`,
37 )
38 .all();
39 for (const t of open) {
40 try {
41 const issue = getIssueById(app.db, t.issue_id);
42 if (issue === undefined || issue.repoId !== repo.id) continue;
43 const said = addComment(
44 app,
45 actor,
46 repo,
47 issue,
48 "A setting away from its default is now one line beside it on the capacity page (/settings/capacity), with Put back; the sentinel files no issue for it. Closing.",
49 );
50 if (!said.ok) continue;
51 setIssueState(app, actor, repo, issue, "closed", { reason: "done" });
52 } catch (error) {
53 log.error("sentinel could not close a setting finding", { issue: t.issue_id, error: String(error) });
54 }
55 }
56 }
src/web/pages/boards-held.ts +1 −1
@@ -32,7 +32,7 @@ export function heldCard(rows: readonly HeldRow[]): Html {
3232 <p class="muted small">
3333 Each ready issue a builder could start, or the first filter that holds
3434 it: a run on it, an open pull, the planner, stalled, its run cap,
35 parked twice, a red-main fix, a setting's finding. When nothing can
35 parked twice, a red-main fix. When nothing can
3636 start and builders are free, the planner is asked to re-plan what is
3737 stalled or capped.
3838 </p>
test/asks.test.ts +2 −2
@@ -276,8 +276,8 @@ describe("the asks page", () => {
276276 expect(card?.short).toContain("its tests passed");
277277 });
278278 describe("a legacy setting finding (#3314)", () => {
279 // The sentinel files no setting now (#3269) and closes the ones it filed
280 // before; until it does, an open one asks nobody and is answered nowhere.
279 // The sentinel files no setting now (#3269); one filed before asks
280 // nobody and is answered nowhere.
281281 test("raises no ask, and /asks/setting is gone", async () => {
282282 const alice0 = getUserByName(app.db, "alice")!;
283283 setCapacity(app.db, "checks.concurrency", "4", alice0.id);
test/crew-direction-autonomy.test.ts −19
@@ -169,25 +169,6 @@ afterAll(async () => {
169169 await rm(dataDir, { recursive: true, force: true });
170170 });
171171
172 describe("a setting finding on an autonomous repository (#2029)", () => {
173 test("is the owner's ask: the autonomy clock never assigns it and no run starts", async () => {
174 const repo = await autonomous();
175 const finding = ok(openIssue(app, alice, repo, { title: "Sentinel: Setting cells.egress is away from its default" }));
176 app.db
177 .query("INSERT INTO sentinel_finding (key, issue_id, evidence, first_seen, last_seen) VALUES ('setting:cells.egress', ?1, '', ?2, ?2)")
178 .run(finding.id, new Date().toISOString());
179 const other = ok(openIssue(app, alice, repo, { title: "Round the corners" }));
180 const before = listEvents(app.db, { kind: "issue.assigned" }).filter((e) => e.payload["issue"] === finding.id).length;
181 for (let tick = 0; tick < 3; tick++) await driveRepo(app, fresh(repo));
182 const after = getIssue(app.db, repo.id, finding.number)!;
183 expect(after.assigneeId).toBeNull();
184 expect(runsOn(repo, after)).toEqual([]);
185 expect(listEvents(app.db, { kind: "issue.assigned" }).filter((e) => e.payload["issue"] === finding.id).length).toBe(before);
186 // the crew still works what is not an ask
187 expect(getIssue(app.db, repo.id, other.number)!.assigneeId).not.toBeNull();
188 });
189 });
190
191172 describe("a reader's issue on an autonomous public repository", () => {
192173 test("is never assigned, queued or ready, and the map says why", async () => {
193174 const repo = await autonomous();
test/crew-held.test.ts +1 −7
@@ -179,11 +179,6 @@ describe("the tick says why each ready issue cannot start", () => {
179179 .query("INSERT INTO sentinel_finding (key, issue_id, evidence, first_seen, last_seen) VALUES (?1, ?2, '', 'x', 'x')")
180180 .run(`degraded:${keyPart(`red:${repo.id}`)}`, fix.id);
181181
182 const finding = issue(repo, "A setting's finding");
183 app.db
184 .query("INSERT INTO sentinel_finding (key, issue_id, evidence, first_seen, last_seen) VALUES ('setting:x', ?1, '', 'x', 'x')")
185 .run(finding.id);
186
187182 const held = heldNow(app, getRepoById(app.db, repo.id)!);
188183 const named = (h: keyof typeof held.by) => held.by[h].map((i) => i.number);
189184 expect(held.startable.map((r) => r.issue.number).sort()).toEqual([free.number, fix.number].sort());
@@ -195,10 +190,9 @@ describe("the tick says why each ready issue cannot start", () => {
195190 expect(named("run_cap")).toEqual([capped.number]);
196191 expect(named("parked_twice")).toEqual([parked.number]);
197192 expect(named("red_fix")).toEqual([quoting.number]);
198 expect(named("setting")).toEqual([finding.number]);
199193 expect(heldCounts(held).open_pull).toBe(1);
200194 expect(heldWords(held)).toBe(
201 "running=1 open_pull=1 planner=1 done_on_main=1 stalled=1 run_cap=1 parked_twice=1 red_fix=1 setting=1",
195 "running=1 open_pull=1 planner=1 done_on_main=1 stalled=1 run_cap=1 parked_twice=1 red_fix=1",
202196 );
203197 // Something can start: the planner is not told the crew is stuck.
204198 expect(stuckOf(held)).toBeUndefined();
test/sentinel.test.ts +1 −19
@@ -20,7 +20,6 @@ import { listEvents } from "../src/core/events.ts";
2020 import { getRepoById, type Repo } from "../src/core/repos.ts";
2121 import { createRun } from "../src/core/runs.ts";
2222 import { createUser, type User } from "../src/core/users.ts";
23 import { isSettingFinding } from "../src/crew/setting_finding.ts";
2423 import { recordCap } from "../src/crew/guard.ts";
2524 import {
2625 budgetBreaches,
@@ -490,18 +489,6 @@ describe("the signals inside the hour", () => {
490489 setCapacity(app.db, "cells.egress", "enforce", alice.id);
491490 });
492491
493 test("an open setting finding from before closes on the next pass, with a pointer to the capacity page (#3269)", () => {
494 const old = createIssue(app.db, { repoId: repo.id, authorId: alice.id, title: "Sentinel: Setting checks.concurrency has been away from its default for 9 days" });
495 if (!old.ok) throw new Error(String(old.error));
496 app.db.query("INSERT INTO sentinel_finding (key, issue_id, evidence, first_seen, last_seen) VALUES ('setting:checks.concurrency', ?1, '', 'a', 'a')").run(old.value.id);
497 hunt(app, "alice/forge", Date.now());
498 const row = app.db.query<{ state: string; close_reason: string }, [string]>("SELECT state, close_reason FROM issue WHERE id = ?1").get(old.value.id)!;
499 expect(row).toEqual({ state: "closed", close_reason: "done" });
500 expect(listComments(app.db, old.value.id).some((c) => c.body.includes("/settings/capacity"))).toBe(true);
501 // closed ones are still known as setting findings
502 expect(isSettingFinding(app.db, old.value.id)).toBe(true);
503 });
504
505492 test("a newly held slot hunts too", () => {
506493 const run = createRun(app.db, { repoId: repo.id, kind: "deploy" });
507494 const l = lastHunt();
@@ -782,11 +769,7 @@ describe("a degraded finding whose cause has stayed closed", () => {
782769 await rm(hdir, { recursive: true, force: true });
783770 });
784771
785 test("23 hours closed stays open; a person's comment keeps theirs at 25, and a setting finding closes", () => {
786 // A setting finding, tracked as the sentinel would.
787 const s = createIssue(happ.db, { repoId: hrepo.id, authorId: halice.id, title: "Sentinel: Setting x" });
788 if (!s.ok) throw new Error(String(s.error));
789 happ.db.query("INSERT INTO sentinel_finding (key, issue_id, evidence, first_seen, last_seen) VALUES ('setting:x', ?1, '', 'a', 'a')").run(s.value.id);
772 test("23 hours closed stays open; a person's comment keeps theirs at 25", () => {
790773 const disk = happ.db.query<{ id: string }, []>("SELECT id FROM issue WHERE title LIKE '%disk%'").get()!;
791774 addComment(happ.db, { issueId: disk.id, authorId: halice.id, body: "looking" });
792775
@@ -801,7 +784,6 @@ describe("a degraded finding whose cause has stayed closed", () => {
801784 expect(said.length).toBe(1);
802785 expect(said[0]!.body).toContain(new Date(T0).toISOString());
803786 expect(state("disk")).toBe("open");
804 expect(state("Setting x")).toBe("closed");
805787 });
806788
807789 test("a finding that comes back is a new issue", () => {

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs