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

The flags a forge admin sees on /settings/flags are one plain-data read: name, why, default, owning issue, live value #7029

Merged opened this

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

Merged

I added `readFlags(app, user)` in `src/actions/flags_view.ts`. `bun x tsc --noEmit` is clean. `test/flags-view.test.ts` and `test/mcp-size.test.ts` pass, and I did not run the rest of the suite.

shipped production is serving it deploy 2fa0c24

opened this

I added readFlags(app, user) in src/actions/flags_view.ts. bun x tsc --noEmit is clean. test/flags-view.test.ts and test/mcp-size.test.ts pass, and I did not run the rest of the suite.

  • What it returns: for each flag in flagRegistry(), an admin gets { name, why, default, issue, value }. value is the stored value, or undefined while nothing is set and the default answers.
  • Who is refused: mayManageFlags gates it. A non-admin, an agent, or no user gets { ok: false, message: FLAGS_ADMIN_ONLY }, the same refusal the page uses.
  • The test: it declares a flag with makeFlags and useFlagRegistry, since the built-in FLAGS is empty. It checks that an admin sees the default, and that after set the live value shows. It also checks that a non-admin, an agent and no user are refused. It found no wrong behaviour, so no handler changed.

I left the page and the MCP untouched, as the issue asks. Nothing calls readFlags yet. Wiring the page and the MCP to it is the second half of #5417.

Closes #7017

Changes requested — before the latest push

readFlags is not reachable. grep finds no caller outside its own test: src/web/pages/flags.ts (GET /settings/flags) does not use it, there is no MCP tool, and src/tty.ts is untouched. The issue asks for the flags an admin sees on /settings/flags to be one plain-data read. Today the page still builds its own rows, so this adds a second copy rather than one read. The preview shows no change, because /settings/flags answers 303 for a guest and nothing renders differently. The README is not updated and the tty has no way to reach flags. Fix first: make src/web/pages/flags.ts render from readFlags and delete the page's own row-building. Then add an MCP tool and a tty command that call the same function, each with a test, and a README line. Smaller points: the unused _app parameter should go, or be used. The as Record and as never casts hide the registry typing, so type the loop over the registry instead.

commented

readFlags now has two callers, the /settings/flags page and the terminal Flags screen. I have not added an MCP tool, and I explain why below. bun x tsc --noEmit is clean. The flags, tui-flags, mcp-flag, flags-view and mcp-size tests pass. bun scripts/design-lint.ts printed its pass line.

  • Page: src/web/pages/flags.ts builds its rows from readFlags and no longer reads the registry for each flag. The 7- and 30-day read counts are still fetched per flag on the page, as before. The "values" timing phase now wraps the readFlags call.
  • Terminal: the tty already has a Flags screen, reached from ctrl+k and then Flags. It lists flags through readFlags instead of its own loop, and set and clear keep their existing gate. So the tty did have a way to reach flags; it just wasn't using the shared read.
  • Typing: readFlags no longer takes the unused app parameter, and its callers and test are updated. It iterates a Record<string, FlagDecl> instead of casting. To drop the as never there, I widened registry.value() in src/core/flags.ts to take a plain string. It was keyof D & string, which collapses to never while FLAGS is empty. The as never casts in flag_winner.ts, flag_set.ts and the screen's other lookups are still there; I left them alone.
  • Docs: I added one sentence about the shared read to the Flags section of docs/OPERATING.md. The README has no flags section, and the existing sentence already covers the page, tty and MCP.

Not done: an MCP tool. The issue says "the page and MCP keep their current code for now" and splits the MCP work out so it doesn't crowd the MCP tool list. The MCP flag_set tool already exists. A read-only list belongs in the follow-up half of #5417, as an action on an existing tool, so the test/mcp-size.test.ts ceilings stay put. If you want it in this pull, say so and I'll add it.

I added no new test for the page or the terminal screen. The existing tests for both still pass on the shared read, and test/flags-view.test.ts covers the read itself.

Approved

Approved. readFlags sits behind mayManageFlags, so a non-admin, an agent and a guest all get the same FLAGS_ADMIN_ONLY refusal the page uses, and test/flags-view.test.ts checks all three. The test also declares a flag through useFlagRegistry and shows the live value changing once it is set. Both doors now list flags through this one read: /settings/flags and the tty Flags screen (ctrl+k → Flags). Set and clear keep their existing gates. The page markup is unchanged, so it raises nothing under DESIGN.md. On the preview, /settings/flags sends a guest to sign-in (303) and / answers 200. No secrets, no SQL or shell built from input, no new dependency. Widening value(name: string) is safe because it only reads a Map.

The issue asked to leave the page and MCP alone. Wiring the page and terminal anyway, after the earlier review asked for it, is the right call: without it the read would have had no caller. Leaving MCP for the second half of #5417 keeps the mcp-size ceilings where they are, which matches the direction.

One point, not blocking (inline): the tty screen still takes its selection index from names() while its rows come from readFlags. That gives the screen two sources for the same list. They agree today, because both walk decls in the same order and under the same gate. A follow-up could derive names from the read.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs