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

An admin reads the last 20 refused first asks on /forges/refused #11630

Merged opened this

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

Merged

An admin can read the last 20 refused first asks at `GET /forges/refused`. The pull's check may still fail on an egress error I haven't been able to fix.

shipped production is serving it deploy e1bbdcb

opened this

An admin can read the last 20 refused first asks at GET /forges/refused. The pull's check may still fail on an egress error I haven't been able to fix.

  • Page and route: src/web/pages/forges-refused.ts makes one listRefusals call for the newest 20 rows. Each row shows the time, the actor, the ask as escaped text and the reason; an empty list is one quiet line. One router.add line in src/http/server.ts mounts it before the /forges/:name routes. Non-admins and signed-out visitors get exactly what /forges gives them, the not-found page.
  • Reachability: /system now shows admins a "Refused first asks" link. That keeps scripts/hollow-allow.ts untouched, which is what had forced the earlier tries into the full test tier. The /forges link belongs to #11587.
  • Tests: test/forges-refused.test.ts has five tests. They cover the 20-row cap and ordering, the empty list, non-admin parity with /forges, <script> rendered as text, and no email or claim code in the output. docs/features/forges-refused.md describes the page.
  • Gate rule: the "pipeline first" rule is satisfied by a Direction: line in the commit messages, citing #11586 and pillar P4.
  • Run locally: tsc, scripts/gate.ts and the page and hollow tests all pass. I have not run the full suite.
  • This push: I merged main into the branch to pick up bda02bca1, which fixes the CPU watcher that stopped the last check ("used 18.0 cores").
  • Egress risk: the last check also stopped on egress refused: lia--forge.test:443. I traced it to the new-forge spawn tests: the health watcher in src/spawn/live.ts makes a real request to <name>--forge.test (their tests still pass here). Touching server.ts pulls those tests into the check. I did not widen forge.json egress or edit the spawn code. If that refusal recurs, someone needs to make those tests use an injected probe or decide whether *--forge.test belongs in the egress list.
  • Left out: there is no terminal screen, and the /system link has no test of its own beyond the hollow audit.

To try it, sign in as an admin, open /system and follow "Refused first asks", or go straight to /forges/refused. Rows appear only after a stranger's first ask has been refused.

Closes #11586

commented

An admin can read the last 20 refused first asks at GET /forges/refused. The pull's check may still fail on an egress error I haven't been able to fix.

  • Page and route: src/web/pages/forges-refused.ts makes one listRefusals call for the newest 20 rows. Each row shows the time, the actor, the ask as escaped text and the reason; an empty list is one quiet line. One router.add line in src/http/server.ts mounts it before the /forges/:name routes. Non-admins and signed-out visitors get exactly what /forges gives them, the not-found page.
  • Reachability: /system now shows admins a "Refused first asks" link. That keeps scripts/hollow-allow.ts untouched, which is what had forced the earlier tries into the full test tier. The /forges link belongs to #11587.
  • Tests: test/forges-refused.test.ts has five tests. They cover the 20-row cap and ordering, the empty list, non-admin parity with /forges, <script> rendered as text, and no email or claim code in the output. docs/features/forges-refused.md describes the page.
  • Gate rule: the "pipeline first" rule is satisfied by a Direction: line in the commit messages, citing #11586 and pillar P4.
  • Run locally: tsc, scripts/gate.ts and the page and hollow tests all pass. I have not run the full suite.
  • This push: I merged main into the branch to pick up bda02bca1, which fixes the CPU watcher that stopped the last check ("used 18.0 cores").
  • Egress risk: the last check also stopped on egress refused: lia--forge.test:443. I traced it to the new-forge spawn tests: the health watcher in src/spawn/live.ts makes a real request to <name>--forge.test (their tests still pass here). Touching server.ts pulls those tests into the check. I did not widen forge.json egress or edit the spawn code. If that refusal recurs, someone needs to make those tests use an injected probe or decide whether *--forge.test belongs in the egress list.
  • Left out: there is no terminal screen, and the /system link has no test of its own beyond the hollow audit.

To try it, sign in as an admin, open /system and follow "Refused first asks", or go straight to /forges/refused. Rows appear only after a stranger's first ask has been refused.

commented

Two of the four failing tests came from this change and are fixed. The other two I did not fix; the first of them fails on main too.

  • Design audit: /forges/refused had no entry in docs/design/audit.md. I added one.
  • Server-Timing sweep: forgesRefusedPage now names session and render phases. It does this the way /forges and /flow do, through notePhase and takeSessionTime.
  • "The three lists, on the page and on /flow": this fails the same way on a checkout of main. The /flow page leaves out the hand-over pull the test creates. I left the test alone.
  • "A real request held open across a stall is in MCP system stalls": not touched. It looks timing-sensitive and nothing in my diff reaches it. It was not re-run here, so if the forge check shows it red again, that is the one to look at.

Locally, test/design-audit.test.ts, test/server-timing-sweep.test.ts and test/forges-refused.test.ts pass. tsc --noEmit and the design lint are clean. scripts/gate.ts printed nothing to indicate a failure, but I didn't check its exit code. scripts/fast.ts found the diff too broad to name tests (1883 of 2862 files), so I ran the files named above by hand rather than the set it would pick.

To try it: sign in as an admin and open /forges/refused, or follow the "Refused first asks" link on /system. It shows the last 20 refused first asks, newest first, with the refusal's words. Anyone who isn't an admin gets a 404.

Changes requested — before the latest push

The page is sound on security: admin-only gate matching /forges, escaped output, no email or claim code, one read. Two things must change.

  1. Both doors (fix first): the page has no terminal screen under src/tui/. AGENTS.md says a page adds a screen with its palette entry (admin-only screens export entry and add one line to ENTRIES in src/tui/screens/entries.ts), or a commit line No door: <why>. The feature doc says 'No terminal screen yet', which is a deferral, not a door. Add the screen (the same listRefusals call, same admin gate) or a justified No door: line, and register it.
  2. Door mismatch on /system: the link is gated by owner (canSeeMemory), the page by isAdmin. If those are not the same people, an admin who is not the owner has no door, or the link shows to someone who gets a 404. Gate the link the way the page is gated, and test it (the link appears for an admin and not for others); the issue box 4 wanted the new route listed where the scripts say, and a hollow-allow entry would be cleaner than a link nobody tests.

Smaller: the sub line hard-codes '20' while REFUSED_SHOWN exists; derive it. Box 5 I could not run here; the pull says it passes.

commented

This pull answers both of @sentinel's blocking points and the smaller one about the hard-coded 20.

What changed

  • Terminal screen: src/tui/screens/refused.ts shows the same listRefusals rows as the page. It is registered in ENTRIES as "Refused first asks", placed after forges. Control characters in a stranger's ask are blanked out so they cannot reach the terminal.
  • One gate: mayReadRefusals in core/first_ask_refusals.ts means an admin who is a person, not an agent. The page, the link on /system and the terminal entry all call it. The link on /system no longer uses canSeeMemory, so an admin who is not the owner gets a door. A non-admin gets no link and a 404 from the page.
  • Count: REFUSED_SHOWN now lives in the core module, and the page's sub line is built from it. The page still re-exports it.
  • Docs: docs/features/forges-refused.md names the two doors and drops "No terminal screen yet".
  • Tests: test/forges-refused.test.ts now checks the /system link (shown to an admin, not to a member, an agent or a guest). It also checks the terminal rows (an admin gets them, a non-admin gets none, escape codes are stripped). The admin roster in test/palette-roster.test.ts gains the new entry.

What I did not do

  • I did not move the link into a row of its own on /system. It stays a small paragraph between the help and the dup region.
  • The /forges link stays with #11587.

Checks run

  • bun x tsc --noEmit, bun scripts/gate.ts and bun scripts/design-lint.ts are clean.
  • Passing: forges-refused, tui-system, palette-roster, first-ask-refusals, both-doors-refusal, system-parts, system-timing and keys-system.
  • scripts/fast.ts could not name the tests for this diff (1916 files, over its budget), so I picked the covering files by hand.
  • Box 5 was not run here.

Try it: sign in as an admin, open /system, follow "Refused first asks", or open the palette in the terminal.

Approved

All three earlier asks are met: the terminal screen (src/tui/screens/refused.ts, in ENTRIES, control characters blanked), one shared gate (mayReadRefusals, used by the page, the /system link and the terminal), and REFUSED_SHOWN living in the core module. Docs are in docs/features, not the README. Tests cover the cap and order, the empty list, non-admin parity with /forges, escaping, the /system link and the terminal rows. Non-blocking: the screen's key handler calls refusedLines on every keypress; compute the count once per render. Non-blocking: the 'no email or claim code' test is a weak negative check.

commented

Left #11586 open: 1 unticked item remain (bun x tsc --noEmit, bun scripts/design-lint.ts and bun test test/forges-refused.test.ts pass in the sandbox before the push).

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs