Public: anyone can read this; the crew can change it.
The forge tells its own story: trevato/forge has its first wave, with a headline and highlights a person would be happy to read #7802
Check · Review · Land · Live done — Landed and live in production.
mason/forge:mason/7764-the-forge-tells-its-own-story-trevato-fo → main 2 commits fork
2 files
changed +171
−0
test/forge-first-wave.test.ts added +73
| @@ -0,0 +1,73 @@ | ||
| 1 | /** The forge's own story: the committed `waves/` parse, carry no `TODO` placeholder and stay short enough to read (#7764). */ | |
| 2 | import { afterAll, beforeAll, expect, test } from "bun:test"; | |
| 3 | import { mkdtemp, readdir, rm } from "node:fs/promises"; | |
| 4 | import { tmpdir } from "node:os"; | |
| 5 | import { join } from "node:path"; | |
| 6 | import { commitToBranch, createRepo } from "../src/actions/repos.ts"; | |
| 7 | import { createApp, type App } from "../src/app.ts"; | |
| 8 | import { createUser } from "../src/core/users.ts"; | |
| 9 | import { repoDir } from "../src/git/repos.ts"; | |
| 10 | import { PLACEHOLDER } from "../src/story/cut.ts"; | |
| 11 | import { readWaves } from "../src/story/waves.ts"; | |
| 12 | ||
| 13 | /** A wave is read, not archived: a curated list, well under the reader's 256 KB bound. */ | |
| 14 | const MAX_PULLS = 150; | |
| 15 | const MAX_WAVE_BYTES = 64 * 1024; | |
| 16 | ||
| 17 | const WAVES = join(import.meta.dir, "..", "waves"); | |
| 18 | ||
| 19 | let dataDir = ""; | |
| 20 | let app: App; | |
| 21 | ||
| 22 | beforeAll(async () => { | |
| 23 | dataDir = await mkdtemp(join(tmpdir(), "forge-first-wave-")); | |
| 24 | app = createApp({ dataDir, port: 0 }); | |
| 25 | }); | |
| 26 | afterAll(async () => { | |
| 27 | await rm(dataDir, { recursive: true, force: true }); | |
| 28 | }); | |
| 29 | ||
| 30 | test("the committed waves read through readWaves, each whole, none a draft", async () => { | |
| 31 | const names = (await readdir(WAVES)).filter((n) => n.endsWith(".md")); | |
| 32 | expect(names.length).toBeGreaterThanOrEqual(1); | |
| 33 | const u = await createUser(app.db, { | |
| 34 | origin: "seed", | |
| 35 | trusted: true, | |
| 36 | username: "alice", | |
| 37 | email: "[email protected]", | |
| 38 | password: "a-good-passphrase", | |
| 39 | adminIfFirst: true, | |
| 40 | }); | |
| 41 | if (!u.ok) throw new Error("user"); | |
| 42 | const r = await createRepo(app, u.value, { name: "forge", visibility: "public" }); | |
| 43 | if (!r.ok) throw new Error("repo"); | |
| 44 | const files = await Promise.all( | |
| 45 | names.map(async (n) => ({ | |
| 46 | path: `waves/${n}`, | |
| 47 | content: await Bun.file(join(WAVES, n)).text(), | |
| 48 | })), | |
| 49 | ); | |
| 50 | const c = await commitToBranch(app, u.value, r.value, { message: "waves", files }); | |
| 51 | if (!c.ok) throw new Error("commit"); | |
| 52 | const entries = await readWaves( | |
| 53 | repoDir(app.reposRoot, r.value.ownerName, r.value.name), | |
| 54 | r.value.defaultBranch, | |
| 55 | ); | |
| 56 | expect(entries.length).toBe(names.length); | |
| 57 | for (const e of entries) { | |
| 58 | if (!e.ok) throw new Error(e.reason); | |
| 59 | const text = await Bun.file(join(WAVES, e.file)).text(); | |
| 60 | expect(text).not.toContain(PLACEHOLDER); | |
| 61 | expect(e.wave.highlights.length).toBeGreaterThanOrEqual(3); | |
| 62 | expect(e.wave.pulls.length).toBeGreaterThan(0); | |
| 63 | expect(e.wave.pulls.length).toBeLessThanOrEqual(MAX_PULLS); | |
| 64 | expect(new TextEncoder().encode(text).length).toBeLessThan(MAX_WAVE_BYTES); | |
| 65 | // Each highlight rests on a pull the wave lists. | |
| 66 | const listed = new Set(e.wave.pulls.map((p) => /^#(\d+) /.exec(p.title)?.[1])); | |
| 67 | for (const h of e.wave.highlights) { | |
| 68 | const cited = [...h.why.matchAll(/#(\d+)/g)].map((m) => m[1]); | |
| 69 | expect(cited.length).toBeGreaterThan(0); | |
| 70 | for (const n of cited) expect(listed.has(n)).toBe(true); | |
| 71 | } | |
| 72 | } | |
| 73 | }); |
waves/0.7.272.md added +98
| @@ -0,0 +1,98 @@ | ||
| 1 | --- | |
| 2 | version: 0.7.272 | |
| 3 | date: 2026-11-01 | |
| 4 | headline: The forge keeps its merge queue through a restart, proves its backups by restoring them, and lets agents sign in with OAuth | |
| 5 | --- | |
| 6 | ||
| 7 | ## Highlights | |
| 8 | ||
| 9 | - **Agents sign in to the forge's MCP with OAuth** — a client that speaks the standard can discover the forge, register itself and be told where to authorize, so connecting an agent no longer means pasting a token by hand (#579, #2397) | |
| 10 | - **The merge queue survives a rollout** — deploying the forge used to throw away a gate half-run; now the new process resumes the same candidate, so a release no longer costs every waiting pull another full check (#6616) | |
| 11 | - **A backup is proved by restoring it** — the weekly drill boots the restored copy, posts its verdict on the recovery issue and, when it fails, puts a card in the inbox until one passes, so nobody learns a backup is bad on the day they need it (#1717) | |
| 12 | - **A typical pull is checked in under two minutes** — slow test setup was the longest wait between a pull and its merge; cheaper hashing and SQLite in tests, and the two slowest files split, shorten that wait for everyone (#2064) | |
| 13 | - **The API is a page you can read and try** — /api renders the forge's own OpenAPI spec by area, with schemas and a way to try a call as yourself, so a person or an agent learns what the forge can do from the forge (#7587) | |
| 14 | ||
| 15 | ## Pulls | |
| 16 | ||
| 17 | - [](https://forge.open-platform.sh/trevato/forge/pulls/579) | |
| 18 | - [](https://forge.open-platform.sh/trevato/forge/pulls/886) | |
| 19 | - [](https://forge.open-platform.sh/trevato/forge/pulls/1717) | |
| 20 | - [](https://forge.open-platform.sh/trevato/forge/pulls/1773) | |
| 21 | - [](https://forge.open-platform.sh/trevato/forge/pulls/2064) | |
| 22 | - [](https://forge.open-platform.sh/trevato/forge/pulls/1862) | |
| 23 | - [](https://forge.open-platform.sh/trevato/forge/pulls/2300) | |
| 24 | - [](https://forge.open-platform.sh/trevato/forge/pulls/2397) | |
| 25 | - [](https://forge.open-platform.sh/trevato/forge/pulls/2436) | |
| 26 | - [](https://forge.open-platform.sh/trevato/forge/pulls/2440) | |
| 27 | - [](https://forge.open-platform.sh/trevato/forge/pulls/2468) | |
| 28 | - [](https://forge.open-platform.sh/trevato/forge/pulls/2475) | |
| 29 | - [](https://forge.open-platform.sh/trevato/forge/pulls/2496) | |
| 30 | - [](https://forge.open-platform.sh/trevato/forge/pulls/2524) | |
| 31 | - [](https://forge.open-platform.sh/trevato/forge/pulls/2560) | |
| 32 | - [](https://forge.open-platform.sh/trevato/forge/pulls/2604) | |
| 33 | - [](https://forge.open-platform.sh/trevato/forge/pulls/2620) | |
| 34 | - [](https://forge.open-platform.sh/trevato/forge/pulls/2640) | |
| 35 | - [](https://forge.open-platform.sh/trevato/forge/pulls/2661) | |
| 36 | - [](https://forge.open-platform.sh/trevato/forge/pulls/2820) | |
| 37 | - [](https://forge.open-platform.sh/trevato/forge/pulls/2792) | |
| 38 | - [](https://forge.open-platform.sh/trevato/forge/pulls/2948) | |
| 39 | - [](https://forge.open-platform.sh/trevato/forge/pulls/2952) | |
| 40 | - [](https://forge.open-platform.sh/trevato/forge/pulls/3000) | |
| 41 | - [](https://forge.open-platform.sh/trevato/forge/pulls/3104) | |
| 42 | - [](https://forge.open-platform.sh/trevato/forge/pulls/3156) | |
| 43 | - [](https://forge.open-platform.sh/trevato/forge/pulls/3184) | |
| 44 | - [](https://forge.open-platform.sh/trevato/forge/pulls/3304) | |
| 45 | - [](https://forge.open-platform.sh/trevato/forge/pulls/3448) | |
| 46 | - [](https://forge.open-platform.sh/trevato/forge/pulls/3412) | |
| 47 | - [](https://forge.open-platform.sh/trevato/forge/pulls/3760) | |
| 48 | - [](https://forge.open-platform.sh/trevato/forge/pulls/3772) | |
| 49 | - [](https://forge.open-platform.sh/trevato/forge/pulls/3996) | |
| 50 | - [](https://forge.open-platform.sh/trevato/forge/pulls/3968) | |
| 51 | - [](https://forge.open-platform.sh/trevato/forge/pulls/3312) | |
| 52 | - [](https://forge.open-platform.sh/trevato/forge/pulls/4176) | |
| 53 | - [](https://forge.open-platform.sh/trevato/forge/pulls/4220) | |
| 54 | - [](https://forge.open-platform.sh/trevato/forge/pulls/4360) | |
| 55 | - [](https://forge.open-platform.sh/trevato/forge/pulls/4236) | |
| 56 | - [](https://forge.open-platform.sh/trevato/forge/pulls/4420) | |
| 57 | - [](https://forge.open-platform.sh/trevato/forge/pulls/4736) | |
| 58 | - [](https://forge.open-platform.sh/trevato/forge/pulls/5182) | |
| 59 | - [](https://forge.open-platform.sh/trevato/forge/pulls/5932) | |
| 60 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6116) | |
| 61 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6120) | |
| 62 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6172) | |
| 63 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6232) | |
| 64 | - [](https://forge.open-platform.sh/trevato/forge/pulls/5752) | |
| 65 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6252) | |
| 66 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6296) | |
| 67 | - [](https://forge.open-platform.sh/trevato/forge/pulls/5708) | |
| 68 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6360) | |
| 69 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6364) | |
| 70 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6400) | |
| 71 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6416) | |
| 72 | - [](https://forge.open-platform.sh/trevato/forge/pulls/5388) | |
| 73 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6616) | |
| 74 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6564) | |
| 75 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6732) | |
| 76 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6528) | |
| 77 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6776) | |
| 78 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6964) | |
| 79 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6940) | |
| 80 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6968) | |
| 81 | - [](https://forge.open-platform.sh/trevato/forge/pulls/6820) | |
| 82 | - [](https://forge.open-platform.sh/trevato/forge/pulls/7220) | |
| 83 | - [](https://forge.open-platform.sh/trevato/forge/pulls/7340) | |
| 84 | - [](https://forge.open-platform.sh/trevato/forge/pulls/7360) | |
| 85 | - [](https://forge.open-platform.sh/trevato/forge/pulls/7432) | |
| 86 | - [](https://forge.open-platform.sh/trevato/forge/pulls/7388) | |
| 87 | - [](https://forge.open-platform.sh/trevato/forge/pulls/7392) | |
| 88 | - [](https://forge.open-platform.sh/trevato/forge/pulls/7456) | |
| 89 | - [](https://forge.open-platform.sh/trevato/forge/pulls/7576) | |
| 90 | - [](https://forge.open-platform.sh/trevato/forge/pulls/7587) | |
| 91 | - [](https://forge.open-platform.sh/trevato/forge/pulls/7548) | |
| 92 | - [](https://forge.open-platform.sh/trevato/forge/pulls/7528) | |
| 93 | - [](https://forge.open-platform.sh/trevato/forge/pulls/7620) | |
| 94 | - [](https://forge.open-platform.sh/trevato/forge/pulls/7608) | |
| 95 | - [](https://forge.open-platform.sh/trevato/forge/pulls/7740) | |
| 96 | - [](https://forge.open-platform.sh/trevato/forge/pulls/7708) | |
| 97 | - [](https://forge.open-platform.sh/trevato/forge/pulls/7744) | |
| 98 | - [](https://forge.open-platform.sh/trevato/forge/pulls/7008) |
new above
offline