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

docs/design/audit.md says, for every top-level page, what it is for and what is wrong with it against DESIGN.md #2725

Merged opened this

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

Merged

scout/forge:scout/2709-docs-design-audit-md-says-for-every-top → main 2 commits fork 2 threads · 2 unresolved

  • Merged. scout/2709-docs-design-audit-md-says-for-every-top was merged into main as c0bfd83.

Review

Sign in to review this change.
2 files changed +170 −17
docs/design/audit.md +119 −17
@@ -33,34 +33,136 @@ their own vocabulary instead of composing the named one.
3333
3434 ## Finding 2 — the pages, and what each is for
3535
36 Judged by the question "what would the owner do here that they cannot do
37 elsewhere?". Page sizes are source lines, a rough proxy for how much each
38 invented.
36 There are 59 top-level pages, one entry each: every static `GET` route in `src/http/server.ts`
37 that returns a page (`test/design-audit.test.ts` holds this list to the router,
38 both ways). Each entry reads `route` — module · what it is for · what
39 duplicates it · what breaks `docs/DESIGN.md`. "Breaks" counts colour literals
40 (§2) and off-scale `font-size`s (§3) in the module as of
41 `docs/design/baseline.json`; "none seen" means the lint finds nothing, not that
42 the page was looked at (no screenshots here). Page-local classes are not
43 repeated per page: the module's share of the 619 is the stylesheet it uses.
3944
40 | page | for | verdict |
41 | ------------------ | ----------------------------------------------- | ------------------------------------------------------------------- |
42 | `/` (studio home) | where I am, what needs me | keep; redo as KPIs the owner pins, not a to-do list (#2665) |
43 | `/boards` | saved queries as panels | keep; selectors unusable (#2666); becomes the home's panel source |
44 | `/system` | realtime machine state (btop) | keep; redo on the system (#2678 plan item 4) |
45 | `/flow` | pipeline and bottleneck (topbar button, admin) | overlaps `/system` and boards: merge as a board panel set |
46 | `/settings/usage`, `/settings/capacity`, `/settings/telemetry`, spend | four pages about "how much is being used" | one page, tabs by `tabs()` — usage and spend are the same question |
47 | `/settings/model`, `/settings/cloud`, `/settings/backups`, `/settings/resilience` | machine/provider/recovery configuration | keep as settings sections; resilience (51 lines) folds into backups |
48 | `/map` | 1,806 lines, 12 off-scale sizes, own colours | the largest private vocabulary; review what it shows that `/boards` and the issue dependency list do not |
49 | `/audit`, `waves`, `variants`, `looks`, `returns`, `chain` | operator views of the crew's work | each needs a stated reason to be a page rather than a board panel |
50 | `/settings/*` rest | account, keys, tokens, origins, crew | fine as one settings shell (`settingsLayout()`); no change |
45 Machine routes are not pages and have no entry: `/audit.csv`,
46 `/fleet/graph/live`, `/fleet/graph.csv`, `/settings/origins/callback`.
5147
52 Duplication to resolve: three places answer "what is the forge doing right now"
53 (home, `/flow`, `/system`); four answer "what does it cost / how full is it".
48 ### Home, work and the crew
49
50 - `/` — `pages/site.ts` (`home`, studio mode in `studio/home.ts`) · where I am, what needs me · `/front` (same page for anyone), `/board`, `/asks` · colours 3 in `site.ts`, 7 in `studio/home.ts`.
51 - `/front` — `studio/home.ts` (`studioDoor`) · the signed-out door, and the site admin's controls over it · `/` for a signed-out reader · colours 7.
52 - `/explore` — `studio/explore.ts` · browse what the forge holds · `/search`, `/apps` · colours 2.
53 - `/board` — `pages/board.ts` (1,231 lines) · every app the viewer can see, with a wall mode · `/boards` (saved queries as panels), `/flow`, `/` · colour 1, sizes 6.
54 - `/board/returns` — `pages/returns.ts` · what the window's dollars bought · `/settings/subscriptions` spend tables, `/settings/usage` · none seen.
55 - `/big` — `pages/board.ts` (`bigRedirect`) · a redirect kept for old addresses into the board's wall mode · it is `/board` · none (no page of its own).
56 - `/boards` — `pages/boards-view.ts` · saved queries as panels · `/board` · none seen.
57 - `/boards/data` — `pages/boards.ts` · the boards' query/data surface · `/board` · none seen.
58 - `/asks` — `studio/asks_page.ts` · what the crew is waiting on me for · `/` "needs me" list · colours 2.
59 - `/asked` — `studio/asked_page.ts` · what I answered, as a record · `/asks` · none seen.
60 - `/flow` — `pages/flow.ts` · the pipeline from ready issue to live deploy, and the bottleneck · `/system`, `/board`, `/` · none seen. A topbar button points here.
61 - `/map` — `pages/map.ts` (1,806 lines) · the dependency map of work across the forge · `/board`, issue dependency lists, `/:owner/:name/map` · colours 3, sizes 12: the largest private vocabulary.
62 - `/audit` — `pages/audit.ts` · every app's contract, who can do what · the app page's one-line policy · none seen. Names the audit of apps, not this document.
63 - `/releases` — `pages/releases.ts` · the forge's kept releases and rollback · `/settings/backups` (both are "go back") · none seen.
64 - `/contribute` — `pages/contribute.ts` · what this forge is and where outside work is welcome, open to anyone · `/llms.txt`, MCP `contribute` tool · none seen.
65 - `/search` — `pages/search.ts` · find across what I can read · the palette (`palette.ts`) · none seen.
66 - `/-/confirm` — `pages/search.ts` (`confirmPage`) · the "are you sure" step for a destructive action · none · none seen.
67
68 ### Making things
69
70 - `/new` — `pages/site.ts` (`newRepoPage`) · make a repository · `/apps/new`, `/migrate` · colours 3 (file).
71 - `/apps` — `pages/apps.ts` · the apps the forge runs · `/audit`, `/explore` · colour 1.
72 - `/apps/new` — `pages/apps.ts` (`newAppPage`) · make an app from the template · `/new` · colour 1.
73 - `/apps/open` — `pages/apps.ts` (`appsOpen`) · a door from a name to a running app · `/apps` · colour 1.
74 - `/organizations/new` — `pages/org.ts` · make an organization · none · none seen.
75 - `/migrate` — `pages/migrate.ts` · bring a repository in from elsewhere · `/settings/origins` (mirror jobs) · none seen.
76
77 ### Forges (the family)
78
79 - `/forges` — `pages/forges.ts` · the forges this one sent, as a client list · `/family` · colour 1.
80 - `/forges/new` — `pages/new-forge.ts` · send a new forge · none · colour 1.
81 - `/family` — `pages/family.ts` · parent, this forge and children as a tree · `/forges` (the same children) · colour 1.
82 - `/claim` — `pages/claim.ts` · claim a forge that was sent to me · none · colour 1.
83 - `/first-admin` — `pages/first-admin.ts` · the first person becomes admin · none · none seen.
84 - `/fleet/graph` — `pages/fleet-graph.ts` · the fleet as a graph · `/family`, `/forges` · none seen.
85
86 ### Machine and operation (admin)
87
88 - `/system` — `pages/system.ts` · the machine as it is now: cores, load, memory, processes · `/flow`, `/` · none seen; its own refresh script.
89 - `/resilience` — `pages/resilience.ts` · each protection in `docs/THREATS.md` against the last gate's tests · `/settings/resilience` (similar name, different content) · none seen.
90 - `/admin/limits` — `pages/admin-limits.ts` · every limit with value, default and reason · `/settings/capacity` (also a numbers-you-can-change page) · none seen.
91 - `/settings/capacity` — `pages/capacity.ts` · how many runs and checks go at once · `/admin/limits`, `/settings/usage` · none seen.
92 - `/settings/usage` — `pages/usage.ts` · route patterns by use, unused first · `/settings/telemetry`, `/board/returns` · none seen. Not about cost, despite the name.
93 - `/settings/telemetry` — `pages/telemetry.ts` · which agents may read telemetry · `/settings/crew` (agent grants) · none seen.
94 - `/settings/resilience` — `pages/domains.ts` · failure domains and their last drill · `/resilience` · none seen.
95 - `/settings/backups` — `pages/backups.ts` (621 lines) · backups and restore · `/settings/resilience`, `/releases` · none seen.
96 - `/settings/flags` — `pages/flags.ts` · the forge's switches · none · none seen.
97 - `/settings/model` — `pages/model.ts` · which model the crew runs on · `/settings/crew` · none seen.
98 - `/settings/cloud` — `pages/cloud.ts` · cloud provider connection · none · none seen.
99 - `/settings/cloud/audit` — `pages/cloud.ts` · what the cloud connection did · `/audit` (different subject, same word) · none seen.
100 - `/settings/access` — `pages/access.ts` · who may reach the forge · `/settings/people`, `/settings/accounts` · none seen.
101
102 ### Sign-in and account
103
104 - `/signin` — `pages/site.ts` · sign in · `/signin/parent` · colours 3 (file).
105 - `/signin/parent` — `http/rp.ts` · sign in with the forge that sent this one · `/signin` · no page (redirect).
106 - `/signin/parent/callback` — `http/rp.ts` · the return leg of that sign-in · none · no page (redirect).
107 - `/signup` — `pages/site.ts` · make an account · `/signup` passkey flow (`signup-passkey.ts`) · colours 3 (file).
108 - `/verify` — `pages/site.ts` · confirm an email address · none · colours 3 (file).
109 - `/recover` — `pages/passkeys.ts` · get back in without a password · `/settings/passkeys` · none seen.
110 - `/settings` — `pages/account.ts` · my account · the rest of settings · colour 1.
111 - `/settings/password` — `pages/account.ts` · change password · `/settings/passkeys` · colour 1.
112 - `/settings/tokens` — `pages/account.ts` · my API tokens · `/settings/keys` (credentials of two kinds on two pages) · colour 1.
113 - `/settings/keys` — `pages/account.ts` · my SSH keys · `/settings/tokens` · colour 1.
114 - `/settings/passkeys` — `pages/passkeys.ts` · my passkeys · `/settings/password` · none seen.
115 - `/settings/secrets` — `pages/secrets.ts` · secrets apps may read · none · none seen.
116 - `/settings/subscriptions` — `pages/subscriptions.ts` (624 lines) · the model subscriptions the crew spends from, with spend tables (`pages/spend.ts`) · `/board/returns` · none seen.
117 - `/settings/accounts` — `pages/accounts.ts` · every account on the forge · `/settings/people` · none seen.
118 - `/settings/people` — `pages/people.ts` · people and their roles · `/settings/accounts`, `/settings/crew` · none seen.
119 - `/settings/crew` — `pages/crew.ts` · the named agents and what each may do · `/settings/model`, `/settings/telemetry` · none seen.
120 - `/settings/origins` — `pages/origins.ts` (1,497 lines) · other forges this one reads and mirrors from · `/migrate` · none seen.
121
122 ## Finding 2b — what the pages do wrong, in sum
123
124 - Four pages answer "how full / what does it cost": `/settings/usage` (request
125 use), `/settings/capacity`, `/settings/subscriptions` (spend), `/board/returns`.
126 Two answer "what is the forge doing now": `/flow`, `/system`, plus `/`.
127 - Two pages are named "resilience" and mean different things (`/resilience`,
128 `/settings/resilience`); two are named "audit" (`/audit`, `/settings/cloud/audit`).
129 - Two pages hold the same lists under different names: `/settings/accounts` and
130 `/settings/people`; `/forges` and `/family`.
131 - The module that invents most: `pages/map.ts` (colours 3, sizes 12), then
132 `pages/board.ts` (colour 1, sizes 6); the colour literals are spread thin over
133 the studio and the site pages (see the table above).
134 - Repository pages (`/:owner/:name/*`) are not listed: the repo header and tabs
135 already unify them.
54136
55137 ## Finding 3 — what the clean app template does better
56138
57139 - One page, one purpose, one primary action. The forge's top bar carries
58140 Flow, search, help, theme, New, user — six controls before the page begins.
59 - It has no page-local CSS. Every forge page file that carries colour or size
141 - It has no page-local CSS. Its stylesheet uses only token words
142 (`font-size: var(--text-sm)`, no literal) and is linked by content hash and
143 cached for a year. Every forge page file that carries colour or size
60144 literals (list above) is a page that reinvented a token.
61145 - First paint is the product. Several forge pages are tables of everything;
62146 the template shows three numbers and a list.
63147
148 ## Merge or retire
149
150 These match the filed issues; each is a decision for its pull, not done here.
151
152 - **#2692** — usage, capacity, subscriptions' spend and the telemetry switch
153 become one "Usage" page with `tabs()`. `/board/returns` stays: it is the
154 board's tokens line opened.
155 - **#2693** — `/flow` folds into the board as panels; the topbar Flow button goes.
156 - **#2694** — `/resilience` folds into `/settings/backups` with
157 `/settings/resilience`'s failure domains.
158 - **#2695** — `/map` is accounted for: keep only what `/board` and an issue's
159 dependency list cannot show; move its 12 sizes and 3 colours onto tokens.
160 - **#2696** — operator views (`/audit`, waves, variants, looks, returns,
161 following) each state why they are a page or become board panels.
162 - Not filed yet, noticed here: `/settings/people` into `/settings/accounts`;
163 `/family` into `/forges`; `/settings/tokens` and `/settings/keys` into one
164 credentials page; `/big` can be deleted once nothing links it.
165
64166 ## Not covered
outdated

Duplicate of Finding 3 (same title, same subject). Merge into Finding 3 and remove this section.

65167
66168 Screenshots, contrast measurement per palette, the TUI surface, and pages
test/design-audit.test.ts added +51
@@ -0,0 +1,51 @@
1 /**
2 * docs/design/audit.md has one entry for every top-level page, and names no
3 * route the router does not have (#2709). The router is read as text: the
4 * static GET paths in src/http/server.ts, less the ones that are not pages.
5 */
6 import { expect, test } from "bun:test";
7 import { readFileSync } from "node:fs";
8
9 const server = readFileSync("src/http/server.ts", "utf8");
10 const doc = readFileSync("docs/design/audit.md", "utf8");
11
12 /** Routes that answer a file, a fragment, a redirect hop or a callback. */
13 const NOT_PAGES =
14 /^\/(assets\/|\.well-known\/|icons\/|og\/|live\/|__forge\/|go\/|events$|sw\.js$|robots\.txt$|sitemap\.xml$|manifest\.webmanifest$|llms\.txt$|releases\.json$|audit\.csv$|fleet\/graph\/live$|fleet\/graph\.csv$|settings\/origins\/callback$|home\/archived\/)/;
15
16 const getRoutes = [
17 ...server.matchAll(/router\.add\(\s*"GET",\s*"([^"]+)"/g),
18 ].map((m) => m[1]!);
19
20 const pages = [
21 ...new Set(
22 getRoutes.filter((r) => !/[:*]/.test(r) && !NOT_PAGES.test(r)),
23 ),
24 ];
25
26 const entries = [...doc.matchAll(/^- `(\/[^`]*)`/gm)].map((m) => m[1]!);
27
28 test("every top-level page has an entry in the audit", () => {

> 40 does not hold the doc's "65 top-level pages" claim. Compare against the number the prose states, or remove the number from the prose.

29 const stated = /There are (\d+) top-level pages/.exec(doc)?.[1];
30 expect(pages.length).toBe(Number(stated));
31 expect(entries.length).toBe(pages.length);
32 expect(pages.filter((p) => !entries.includes(p))).toEqual([]);
33 });
34
35 test("the audit names no route that does not exist", () => {
36 const known = new Set(getRoutes);
37 const named = [...doc.matchAll(/`(\/[a-z0-9\-/._:]*)`/g)].map((m) => m[1]!);
38 const ghosts = named.filter(
39 (r) =>
40 !known.has(r) &&
41 // a path inside a repository, a file, or a prefix, not a route
42 !/^\/(:owner|\.|src|docs)/.test(r) &&
43 !/^\/(llms\.txt|tokens\.css)/.test(r),
44 );
45 expect(ghosts).toEqual([]);
46 expect(entries.filter((e) => !known.has(e))).toEqual([]);
47 });
48
49 test("each entry is written once", () => {
50 expect(entries.length).toBe(new Set(entries).size);
51 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs