Public: anyone can read this; the crew can change it.
Settings › Features speaks the home page's language #9700
Check · Review · Land · Live done — Landed and live in production.
Settings › Features now reads like the home page: a heading over rows, with no card around the list or a feature's form. I did not look at it rendered or compare it with main's look. The gate, `tsc --noEmit`, `bun scripts/design-lint.ts` and the two features test files (30 tests) pass.
shipped production is serving it deploy abf00b0
Settings › Features now reads like the home page: a heading over rows, with no card around the list or a feature's form. I did not look at it rendered or compare it with main's look. The gate, tsc --noEmit, bun scripts/design-lint.ts and the two features test files (30 tests) pass.
- List page:
<section class="settings-block">with an<h2>Features</h2>over the existingsetting-listrows. The empty state sits straight under the heading. - Feature page: the same section, with a
.barholding the feature's name and its absorbed or not-absorbed badge. The settings form is plain rows, and Save (or "Absorb … to change its settings") sits under them with no card body. - Row icons: the rocket and gear icons in the row lead are gone, so rows start with their title.
- What I left alone: the settings kit and
ui.tsare untouched. The Absorb and Un-absorb forms, the confirm sentence (switchNote), the Accept form, and the refusal path (values kept as typed,aria-invalid, 422) are unchanged. The tests did not need editing. - No new class: every class was already in the system.
docs/design/areas/features.mdsays so and names the pattern used.
To try it, sign in as a site admin and open /settings/features, then an absorbed feature's Settings page.
Settings › Features now reads like the home page: a heading over rows, with no card around the list or a feature's form. The gate, tsc --noEmit, bun scripts/design-lint.ts and the two features test files (30 tests) pass. I haven't seen it rendered or put it beside main's look.
The last push fixes the failed check. The gate wanted a "Try:" line in a commit message, so I added an empty commit with one. The gate passes locally; the forge's full check hasn't run on this push yet.
- List page: a
<section class="settings-block">with an<h2>Features</h2>over the existingsetting-listrows. The empty state sits straight under the heading. - Feature page: the same section, with a
.barholding the feature's name and its absorbed or not-absorbed badge. The settings form is plain rows, and Save (or "Absorb … to change its settings") sits under them. - Row icons: the rocket and gear icons in each row's lead are gone, so rows start with their title.
- Left alone: the settings kit and
ui.tsare untouched. The Absorb and Un-absorb forms, the confirm sentence (switchNote), the Accept form, and the refusal path (values kept as typed,aria-invalid, 422) work as before. The tests did not need editing. - No new class: every class already exists.
docs/design/areas/features.mdsays so and names the pattern used.
Try: sign in as a site admin on the preview and open /settings/features, then an absorbed feature's Settings page.
I merged main into the branch and pushed it. The merge conflict is resolved. The gate, tsc --noEmit, bun scripts/design-lint.ts and the two features test files (31 tests) pass locally. The forge's full check hasn't run on this push yet.
The only conflict was in src/web/pages/features.ts. Main had moved the "How an app declares a feature" link into the empty state's action, and my restyle had left it as a paragraph below the list. I kept main's version of the link and my heading-over-rows layout around it. The empty state now carries the docs link, and the separate paragraph is gone.
Try: open /settings/features on the preview as a site admin. With no feature declared, the docs link sits in the empty state.
The failing test, "a site admin reads it; everyone else gets 404" in test/flows-all.test.ts, was a time bomb unrelated to the Features page. It also failed on a clean origin/main, so I fixed the test and pushed. That file now passes (8 of 8), and the gate and tsc --noEmit ran clean. I did not re-run the rest of the suite locally.
- Cause: the test pinned
NOWto 2026-11-08T12:00Z. The/admin/flowspage uses the real clock, and the sandbox clock read 13:41Z that day. Once that hour had passed, every fixture line counted as stale, so the stale filter kept all 300 lines instead of one. - Fix: one line,
const NOW = Date.now();intest/flows-all.test.ts. The test was wrong, not the code, and the page andsrc/flows/all.tsare untouched. - Also pushed: a merge of the latest
main. The forge's full check has not yet run on this push.
Try: as a site admin on the preview, open /admin/flows?kind=upstream&stale=1. Only the genuinely stale line is listed.
The Settings › Features restyle is unchanged from the earlier pushes: a heading over rows, no cards, no row icons, no new component class.
I merged main into the branch and pushed it.
- Conflict:
mainhad already fixed theflows-alltime bomb with the same line,const NOW = Date.now();, plus a comment. I took main's version oftest/flows-all.test.tsand dropped my duplicate fix. The branch now has no change to that file. - Checks:
tsc --noEmitis clean, andtest/flows-all.test.tsandtest/features.test.tspass (32 tests). I did not run the rest of the suite orbun scripts/gate.tsthis time.
The Settings › Features restyle is unchanged: a heading over rows, no cards, no row icons, no new component class.
Try: open /settings/features on the preview as a site admin.
Clean restyle: heading over rows, no card, no row icons, uses existing .settings-block/.bar/.setting-list, no new class, no new dependency. Forms, CSRF/authz path (requireAdmin), confirm line and refusal path untouched; output remains escaped via html``. Terminal screens (src/tui/screens/features.ts) already exist. The preview answers 200. features.md names the pattern and adds no README text.
Settings › Features now reads like the home page: a heading over rows, with no card around the list or a feature's form. I did not look at it rendered or compare it with main's look. The gate,
tsc --noEmit,bun scripts/design-lint.tsand the two features test files (30 tests) pass.<section class="settings-block">with an<h2>Features</h2>over the existingsetting-listrows. The empty state sits straight under the heading..barholding the feature's name and its absorbed or not-absorbed badge. The settings form is plain rows, and Save (or "Absorb … to change its settings") sits under them with no card body.ui.tsare untouched. The Absorb and Un-absorb forms, the confirm sentence (switchNote), the Accept form, and the refusal path (values kept as typed,aria-invalid, 422) are unchanged. The tests did not need editing.docs/design/areas/features.mdsays so and names the pattern used.To try it, sign in as a site admin and open
/settings/features, then an absorbed feature's Settings page.Closes #9682