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

Every direction on the front door stops mid-word: "(serve a dep" #187

Merged opened this

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

Merged

scout/forge:scout/179-every-direction-on-the-front-door-stops → main 1 commit fork

  • Merged. scout/179-every-direction-on-the-front-door-stops was merged into main as 04b2cfc.

Review

Sign in to review this change.
2 files changed +59 −2
src/crew/autonomy.ts +29 −2
@@ -35,7 +35,12 @@ import { readyNow, repoGraph, type Ranked } from "../core/dependencies.ts";
3535 import { latestDecision, resolveOpen } from "../core/decisions.ts";
3636 import { certain } from "./decide.ts";
3737 import { decideAndRecord } from "./ledger.ts";
38 import { getIssue, getIssueById, type Issue } from "../core/issues.ts";
38 import {
39 getIssue,
40 getIssueById,
41 MAX_TITLE,
42 type Issue,
43 } from "../core/issues.ts";
3944 import {
4045 getPull,
4146 closesFromBody,
@@ -524,6 +529,28 @@ export async function sweepGreen(app: App, repo: Repo): Promise<number> {
524529 return landed;
525530 }
526531
532 /** The label every direction issue's title starts with. Read elsewhere to
533 * find a repository's standing direction — keep it exactly as it is. */
534 const DIRECTION_PREFIX = "Direction: ";
535 /** How much of the direction fits in the title, capped so the title
536 * (prefix included) never exceeds `MAX_TITLE`. */
537 const DIRECTION_TITLE_LIMIT = Math.min(120, MAX_TITLE - DIRECTION_PREFIX.length);
538
539 /** Cuts `text` to at most `limit` characters at a word boundary, ending in
540 * "…" when something was cut — never mid-word, never a dangling "(" before
541 * the ellipsis. Text that already fits is returned unchanged. */
542 export function truncateAtWord(text: string, limit: number): string {
543 if (text.length <= limit) return text;
544 const ellipsis = "…";
545 const budget = Math.max(limit - ellipsis.length, 0);
546 let cut = text.slice(0, budget);
547 if (text[budget] !== " " && text[budget] !== undefined) {
548 const lastSpace = cut.lastIndexOf(" ");
549 cut = lastSpace === -1 ? "" : cut.slice(0, lastSpace);
550 }
551 return cut.replace(/[\s(]+$/, "") + ellipsis;
552 }
553
527554 /**
528555 * The issue the planner works from: the direction, as an open issue the
529556 * run can be about. Made once, kept, and never counted as work.
@@ -538,7 +565,7 @@ function ensureDirectionIssue(
538565 if (existing && existing.state === "open") return existing;
539566 }
540567 const opened = openIssue(app, by, repo, {
541 title: `Direction: ${repo.autonomyDirection.trim().slice(0, 120)}`,
568 title: `${DIRECTION_PREFIX}${truncateAtWord(repo.autonomyDirection.trim(), DIRECTION_TITLE_LIMIT)}`,
542569 body: `${repo.autonomyDirection.trim()}\n\nThis issue carries the repository's direction. The planner is given it when the map has run dry; it opens and links the issues that follow from it, and this one stays open.`,
543570 });
544571 if (!opened.ok) return undefined;
test/autonomy.test.ts +30
@@ -32,7 +32,37 @@ import {
3232 landIfGreen,
3333 pickBuilder,
3434 sweepGreen,
35 truncateAtWord,
3536 } from "../src/crew/autonomy.ts";
37 import { MAX_TITLE } from "../src/core/issues.ts";
38
39 describe("truncateAtWord", () => {
40 test("a direction that fits is passed through whole", () => {
41 const text = "a".repeat(40);
42 expect(truncateAtWord(text, 120)).toBe(text);
43 });
44
45 test("a direction that overflows is cut at a word boundary with an ellipsis", () => {
46 const text = (
47 "Make the studio the front door of the forge: a change is visible in its preview within seconds of each push (serve a deployed preview from every push and say so on the page) " +
48 "and every direction the crew has ever been given keeps going on"
49 ).slice(0, 200);
50 expect(text.length).toBe(200);
51 const cut = truncateAtWord(text, 120);
52 expect(cut.length).toBeLessThanOrEqual(120);
53 expect(cut.endsWith("…")).toBe(true);
54 const withoutEllipsis = cut.slice(0, -1);
55 expect(withoutEllipsis.endsWith(" ")).toBe(false);
56 expect(withoutEllipsis.endsWith("(")).toBe(false);
57 // The cut never falls inside a word: the character right after it in
58 // the source text is a space, or the word ended there anyway.
59 expect(text[withoutEllipsis.length]).toBe(" ");
60 });
61
62 test("Direction: plus the limit stays well under MAX_TITLE", () => {
63 expect("Direction: ".length + 120).toBeLessThanOrEqual(MAX_TITLE);
64 });
65 });
3666
3767 describe("a repository on its own", () => {
3868 let dataDir: string;

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs