Public: anyone can read this; the crew can change it.
test/livetriage.test.ts's per-tick caps pass every time on a loaded check machine #4623
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/4579-test-livetriage-test-ts-s-per-tick-caps → main 1 commit fork 1 thread · 1 unresolved
1 file
changed +27
−17
test/livetriage.test.ts +27 −17
| @@ -280,6 +280,8 @@ describe("live triage", () => { | ||
| 280 | 280 | const direction = () => getIssueById(app.db, fresh().directionIssueId!)!; |
| 281 | 281 | const lines = () => listComments(app.db, direction().id).map((c) => c.body); |
| 282 | 282 | const outsider = async () => { |
| 283 | const existing = getUserByName(app.db, "carol"); | |
| 284 | if (existing) return existing; | |
| 283 | 285 | const made = await createUser(app.db, { |
| 284 | 286 | origin: "seed", |
| 285 | 287 | trusted: true, |
| @@ -381,6 +383,9 @@ describe("live triage", () => { | ||
| 381 | 383 | }); |
| 382 | 384 | }); |
| 383 | 385 | |
| 386 | /** The one clock the filing tests age issues from and tick at, so no second read of the time can disagree. */ | |
| 387 | const CLOCK = new Date("2026-01-01T12:00:00.000Z"); | |
| 388 | ||
| 384 | 389 | describe("live triage files unplaced issues", () => { |
| 385 | 390 | let dir: string; |
| 386 | 391 | let app: App; |
| @@ -394,7 +399,7 @@ describe("live triage files unplaced issues", () => { | ||
| 394 | 399 | if (!opened.ok) throw new Error(String(opened.error)); |
| 395 | 400 | app.db |
| 396 | 401 | .query(`UPDATE issue SET created_at = ?2 WHERE id = ?1`) |
| 397 | .run(opened.value.id, new Date(Date.now() - age).toISOString()); | |
| 402 | .run(opened.value.id, new Date(CLOCK.getTime() - age).toISOString()); | |
| 398 | 403 | return getIssueById(app.db, opened.value.id)!; |
| 399 | 404 | }; |
| 400 | 405 | const waitsFor = (a: Issue, b: Issue) => |
| @@ -442,7 +447,7 @@ describe("live triage files unplaced issues", () => { | ||
| 442 | 447 | |
| 443 | 448 | test("an issue whose title names a pillar is filed under it, and counted", async () => { |
| 444 | 449 | const work = open("Harden P0 sessions"); |
| 445 | const did = await liveTriage(app, fresh()); | |
| 450 | const did = await liveTriage(app, fresh(), CLOCK); | |
| 446 | 451 | expect(did.labelled).toBe(1); |
| 447 | 452 | expect(waitsFor(umbrella, work)).toBe(true); |
| 448 | 453 | expect(labelsFor(app.db, work.id).map((l) => l.name)).toContain("P0 Trust"); |
| @@ -451,32 +456,32 @@ describe("live triage files unplaced issues", () => { | ||
| 451 | 456 | |
| 452 | 457 | test("a pillar named only in the body files it", async () => { |
| 453 | 458 | const work = open("Sessions", "This serves p0 trust."); |
| 454 | await liveTriage(app, fresh()); | |
| 459 | await liveTriage(app, fresh(), CLOCK); | |
| 455 | 460 | expect(waitsFor(umbrella, work)).toBe(true); |
| 456 | 461 | }); |
| 457 | 462 | |
| 458 | 463 | test("the title wins when title and body name different pillars", async () => { |
| 459 | 464 | const other = open("P1 Speed: be quick"); |
| 460 | 465 | const work = open("Cache P1 pages", "Also touches P0."); |
| 461 | await liveTriage(app, fresh()); | |
| 466 | await liveTriage(app, fresh(), CLOCK); | |
| 462 | 467 | expect(waitsFor(other, work)).toBe(true); |
| 463 | 468 | expect(waitsFor(umbrella, work)).toBe(false); |
| 464 | 469 | }); |
| 465 | 470 | |
| 466 | 471 | test("a bare pillar name in passing does not file it: it goes to Later", async () => { |
| 467 | 472 | const work = open("Tell the story of trust", "A story about trust, in passing."); |
| 468 | await liveTriage(app, fresh()); | |
| 473 | await liveTriage(app, fresh(), CLOCK); | |
| 469 | 474 | expect(waitsFor(umbrella, work)).toBe(false); |
| 470 | 475 | expect(waitsFor(work, gate)).toBe(true); |
| 471 | 476 | }); |
| 472 | 477 | |
| 473 | 478 | test("an issue naming none goes behind the Later gate with a comment, once", async () => { |
| 474 | 479 | const work = open("Add a colour picker"); |
| 475 | await liveTriage(app, fresh()); | |
| 480 | await liveTriage(app, fresh(), CLOCK); | |
| 476 | 481 | expect(waitsFor(work, gate)).toBe(true); |
| 477 | 482 | expect(labelsFor(app.db, work.id).map((l) => l.name)).toContain("Later"); |
| 478 | 483 | expect(notes(work)[0]!.body).toContain("Later gate"); |
| 479 | const again = await liveTriage(app, fresh()); | |
| 484 | const again = await liveTriage(app, fresh(), CLOCK); | |
| 480 | 485 | expect(again.labelled).toBe(0); |
| 481 | 486 | expect(again.missed).toBe(0); |
| 482 | 487 | expect(notes(work)).toHaveLength(1); |
| @@ -486,7 +491,7 @@ describe("live triage files unplaced issues", () => { | ||
| 486 | 491 | const young = open("Brand new idea", "", 60_000); |
| 487 | 492 | const placed = open("Already placed"); |
| 488 | 493 | link(placed); |
| 489 | await liveTriage(app, fresh()); | |
| 494 | await liveTriage(app, fresh(), CLOCK); | |
| 490 | 495 | expect(waitsFor(young, gate)).toBe(false); |
| 491 | 496 | expect(notes(young)).toHaveLength(0); |
| 492 | 497 | expect(notes(placed)).toHaveLength(0); |
| @@ -497,7 +502,7 @@ describe("live triage files unplaced issues", () => { | ||
| 497 | 502 | test("directions, umbrellas and the gate are skipped", async () => { |
| 498 | 503 | const direction = open("Direction: keep it small"); |
| 499 | 504 | app.db.query(`UPDATE repo SET direction_issue_id = ?2 WHERE id = ?1`).run(repo.id, direction.id); |
| 500 | await liveTriage(app, fresh()); | |
| 505 | await liveTriage(app, fresh(), CLOCK); | |
| 501 | 506 | for (const furniture of [direction, umbrella, gate]) expect(notes(furniture)).toHaveLength(0); |
| 502 | 507 | expect(waitsFor(direction, gate)).toBe(false); |
| 503 | 508 | expect(waitsFor(gate, gate)).toBe(false); |
| @@ -505,9 +510,9 @@ describe("live triage files unplaced issues", () => { | ||
| 505 | 510 | |
| 506 | 511 | test("a person who unlinks the gate is not overruled", async () => { |
| 507 | 512 | const work = open("Needs thought"); |
| 508 | await liveTriage(app, fresh()); | |
| 513 | await liveTriage(app, fresh(), CLOCK); | |
| 509 | 514 | app.db.query(`DELETE FROM issue_dependency WHERE issue_id = ?1`).run(work.id); |
| 510 | const did = await liveTriage(app, fresh()); | |
| 515 | const did = await liveTriage(app, fresh(), CLOCK); | |
| 511 | 516 | expect(waitsFor(work, gate)).toBe(false); |
| 512 | 517 | expect(did.labelled).toBe(0); |
| 513 | 518 | expect(did.missed).toBe(0); |
| @@ -549,7 +554,7 @@ describe("live triage where there is little to file under", () => { | ||
| 549 | 554 | }); |
| 550 | 555 | if (!set.ok) throw new Error(JSON.stringify(set.error)); |
| 551 | 556 | const repo = () => getRepoById(app.db, made.value.id)!; |
| 552 | const old = new Date(Date.now() - 2 * FILE_AFTER_MS).toISOString(); | |
| 557 | const old = new Date(CLOCK.getTime() - 2 * FILE_AFTER_MS).toISOString(); | |
| 553 | 558 | const open = (title: string): Issue => { |
| 554 | 559 | const o = openIssue(app, alice, repo(), { title }); |
| 555 | 560 | if (!o.ok) throw new Error(String(o.error)); |
| @@ -564,26 +569,31 @@ describe("live triage where there is little to file under", () => { | ||
| 564 | 569 | |
| 565 | 570 | test("pillars but no gate: an unnamed issue is left alone and counted as missed", async () => { |
| 566 | 571 | const w = await world("nogate", ["P0 Trust: be safe"], 1); |
| 567 | const did = await liveTriage(app, w.repo()); | |
| 572 | const did = await liveTriage(app, w.repo(), CLOCK); | |
| 568 | 573 | expect(did.labelled).toBe(0); |
| 569 | 574 | expect(did.missed).toBe(1); |
| 570 | 575 | expect(comments(w.work[0]!)).toBe(0); |
| 571 | 576 | expect(labelsFor(app.db, w.work[0]!.id)).toHaveLength(0); |
| 572 | expect(app.db.query<{ n: number }, []>(`SELECT COUNT(*) AS n FROM issue_dependency`).get()!.n).toBe(0); | |
| 577 | const links = app.db | |
| 578 | .query<{ n: number }, [string]>( | |
| 579 | `SELECT COUNT(*) AS n FROM issue_dependency d JOIN issue i ON i.id = d.issue_id WHERE i.repo_id = ?1`, | |
| 580 | ) | |
| 581 | .get(w.repo().id)!.n; | |
| 582 | expect(links).toBe(0); | |
| 573 | 583 | }); |
| 574 | 584 | |
| 575 | 585 | test("neither pillars nor gate: nothing is filed, counted or written", async () => { |
| 576 | 586 | const w = await world("plain", [], 2); |
| 577 | expect(await liveTriage(app, w.repo())).toEqual({ closed: 0, folded: 0, labelled: 0, missed: 0 }); | |
| 587 | expect(await liveTriage(app, w.repo(), CLOCK)).toEqual({ closed: 0, folded: 0, labelled: 0, missed: 0 }); | |
| 578 | 588 | for (const issue of w.work) expect(comments(issue)).toBe(0); |
| 579 | 589 | }); |
| 580 | 590 | |
| 581 | 591 | test("at most 25 issues are filed per tick; the rest are missed, then filed", async () => { |
| 582 | 592 | const w = await world("many", ["Later gate: not yet"], MOST_CHANGES + 1); |
| 583 | const first = await liveTriage(app, w.repo()); | |
| 593 | const first = await liveTriage(app, w.repo(), CLOCK); | |
| 584 | 594 | expect(first.labelled).toBe(MOST_CHANGES); |
| 585 | 595 | expect(first.missed).toBe(1); |
| 586 | const second = await liveTriage(app, w.repo()); | |
| 596 | const second = await liveTriage(app, w.repo(), CLOCK); | |
| 587 | 597 | expect(second.labelled).toBe(1); |
| 588 | 598 | expect(second.missed).toBe(0); |
| 589 | 599 | // Twenty-six issues are opened and two ticks run: a loaded check machine must not turn the 5 s default into the verdict. |
new above
offline
Good: one constant for aging and ticking. Consider reusing it in the earlier describes too, which still use real time.