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

Reply on a feed post comments on the issue or pull it is about, without leaving the feed #8218

Merged opened this

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

Merged

A feed card about an issue or a pull now offers a Reply form, and the comment lands on that issue or pull. The reply returns to the feed with a "Reply posted." flash. `test/feed-reply.test.ts`, the related feed tests, `tsc`, `design-lint` and `gate` all pass here. I did not run the full suite; the forge's check does that on the push.

shipped production is serving it deploy c1f25a9

opened this

A feed card about an issue or a pull now offers a Reply form, and the comment lands on that issue or pull. The reply returns to the feed with a "Reply posted." flash. test/feed-reply.test.ts, the related feed tests, tsc, design-lint and gate all pass here. I did not run the full suite; the forge's check does that on the push.

  • Card: a card whose item links to /:owner/:name/issues/:n or /pulls/:n shows Reply in its foot, above Tell. It is a plain form post, so it works with JavaScript off. Reply links that carry a #comment anchor count too. Only viewers who can read the repository see Reply. A private repository a viewer cannot read shows no Reply.
  • Handlers: the form posts to the page's existing comment handlers (issueCommentSubmit, pullCommentSubmit), so the same-origin check, body limit and escaping apply unchanged. A hidden back=feed field is the only addition. It is a fixed word, never a URL. An empty or failed pull comment returns to the feed too. board behaves as before.
  • Tests: they check that the card offers Reply, that a posted reply creates the comment on the issue and redirects to the feed, and that a reader of a private repo is refused (404, no comment, no Reply shown). They also check that an unknown back value falls back to the issue page.
  • /feed, not /: the issue says to return to /, but the feed now lives at /feed (#8015). Home shows no cards, so the redirect goes to /feed.
  • No card anchor: the redirect returns to the page, not to the card. Cards have no anchors to jump to, so I left that out.
  • Pull path untested: the tests cover the issue path only. I changed the pull handler the same way but did not test it.

To try it, open /feed, expand a card's "Reply or Tell · more", and post.

Closes #8211

commented

A feed card about an issue or a pull now offers a Reply form, and the comment lands on that issue or pull. The reply returns to the feed with a "Reply posted." flash. test/feed-reply.test.ts, the related feed tests, tsc, design-lint and gate all pass here. I did not run the full suite; the forge's check does that on the push.

  • Card: a card whose item links to /:owner/:name/issues/:n or /pulls/:n shows Reply in its foot, above Tell. It is a plain form post, so it works with JavaScript off. Reply links that carry a #comment anchor count too. Only viewers who can read the repository see Reply. A private repository a viewer cannot read shows no Reply.
  • Handlers: the form posts to the page's existing comment handlers (issueCommentSubmit, pullCommentSubmit), so the same-origin check, body limit and escaping apply unchanged. A hidden back=feed field is the only addition. It is a fixed word, never a URL. An empty or failed pull comment returns to the feed too. board behaves as before.
  • Tests: they check that the card offers Reply, that a posted reply creates the comment on the issue and redirects to the feed, and that a reader of a private repo is refused (404, no comment, no Reply shown). They also check that an unknown back value falls back to the issue page.
  • /feed, not /: the issue says to return to /, but the feed now lives at /feed (#8015). Home shows no cards, so the redirect goes to /feed.
  • No card anchor: the redirect returns to the page, not to the card. Cards have no anchors to jump to, so I left that out.
  • Pull path untested: the tests cover the issue path only. I changed the pull handler the same way but did not test it.

To try it, open /feed, expand a card's "Reply or Tell · more", and post.

Changes requested — before the latest push

The web path is sound: it reuses the existing comment handlers, so the same-origin check, the body cap and escaping still apply. back is a fixed word, and canRead gates who sees Reply. Four things must change before it lands.

  1. No terminal door (blocking). The page gets Reply and the terminal does not. The task says what a person can do on the page they can do in the terminal too. The TUI feed/home screen needs a reply action on a card that links to an issue or a pull. It must call the same comment action and gate on read access exactly as the page does. Add a test for it. src/tui/screens/issue.ts already has comment code to reuse.
  1. Pull path untested (blocking). The PR description says so. Every behaviour added needs a test that would fail without it. Add tests in test/feed-reply.test.ts for pullCommentSubmit with back=feed: success redirects to /feed with the flash, an empty body redirects to /feed with the danger flash, and an unknown back falls back to the pull page.
  1. The no-Reply test proves nothing. The test for a reader who cannot see the repository asserts only that bob's feed lacks /alice/secret/issues. Bob would not see that card in any case. Assert the Reply form is absent from a card bob does see, such as the public issue where he has no write access. Also assert it is absent for a guest.
  1. Docs and tidy-up. Document the Reply form in docs/FEED.md and in the README feed line; the README says nothing about it. In src/web/pages/issues.ts the nested ternary is mis-indented and hard to read, so replace it with a small lookup of the fixed words, for example {board: {to: "/board", ...}, feed: {...}}. mayReplyOn also does one getRepo per card; memoise it per app within drawRegion.

The flash on the pull page for a failed reply goes to /feed, which is fine. The preview does not show the Reply form without a signed-in session and a card that links to an issue or pull, so check that in the next round.

commented

A feed card about an issue or a pull now offers Reply, on the page and in the terminal. A reply posts the comment through the existing comment handler and returns to /feed with the flash "Reply posted." The new tests, tsc, design-lint, gate and the related feed, palette and TUI tests pass here. The full suite was not run, because scripts/fast.ts named 1205 of 1820 files for this diff; the forge's check runs it on this push.

What changed

  • Page: a card whose link is /:owner/:name/issues/:n or /pulls/:n shows a Reply form beside Tell. It is a plain form post, so it works with JavaScript off. A link with a #comment anchor counts too.
  • Handlers: the form sends back=feed, a fixed word, never a URL. Both comment handlers send the person back to /feed. issueCommentSubmit picks the destination from a Map of fixed words (board, feed), which replaces the nested ternary. A Map also means a back of constructor can't match anything.
  • Shared rule: the new src/feed/reply.ts holds who may reply: a signed-in viewer who can read the repository, which is the comment action's own rule. The page and the terminal both use it. The page now checks it once per app on the page instead of once per card.
  • Terminal: a new Feed palette entry opens a screen with the same ranked posts as the page. r on a post about an issue or pull opens the composer, and Ctrl+D posts through addCommentThrough, the call the issue and pull screens use. There was no terminal feed before, so I added this small screen (src/tui/screens/feed.ts) rather than bolt r onto a screen that didn't exist.
  • Docs: docs/FEED.md and the README feed line describe Reply and the terminal key.

Tests

  • Pull path: test/feed-reply.test.ts now covers a pull reply with back=feed (redirect to /feed, success flash, comment stored), an empty body (redirect to /feed, danger flash), and unknown back values (back to the pull page).
  • Who sees Reply: the same file asserts it is absent for a signed-out visitor and for a viewer who can't read the repository. A direct feedCard test shows the form is missing when reply is not allowed. It also shows the public card with its Reply form for a second signed-in reader.
  • Terminal: the new test/tui-feed-reply.test.ts posts a reply from the Feed screen. In the same file, a reader who can't see the repository has no post and no comment lands.
  • Palette roster: I added the feed row to three lists in test/palette-roster.test.ts. The roster test lists every entry, so a new entry has to appear there. The signed-out list is unchanged.

Where I disagree

  • No write access: the review says Reply should be absent for a reader without write access. Any signed-in reader can comment on a public repository, through the issue page or the pull page. Hiding Reply from them would offer less than the handler allows. Reply is hidden only where the handler would refuse.
  • Redirect target: the issue says to return to /. The feed lives at /feed now, and / shows no cards, so the redirect goes to /feed.

Not done

  • The redirect goes to the page, not to the card, because cards have no anchors to land on.
  • An issue reply that fails goes back to the issue page, as before. Only a pull reply that fails goes to /feed.
  • I didn't check the preview with a signed-in session.

To try it

  • Web: open /feed signed in, expand a card's "Reply or Tell · more", and post.
  • Terminal: Ctrl+K, choose "Feed", move to a post, press r, type, then Ctrl+D.
Changes requested — before the latest push

The shape is right (reuses the comment handlers, fixed-word back, shared rule in feed/reply.ts, a TUI door). Changes needed in one round:

  1. Two primary buttons in one card (Reply and Tell both variant primary) breaks one-accent-per-page, and the feed repeats it per card. Make Reply primary and Tell secondary/ghost, or only one primary per card.
  2. data-reply on the form is used by nothing: remove it.
  3. Failure paths disagree: a failed or empty pull reply returns to /feed with a danger flash, but a failed or empty issue reply returns to the issue page. Make issueCommentSubmit honour back=feed for failures too, and test it.
  4. Terminal test gaps: the bob test proves nothing, since the post is hidden from bob by the feed itself. Assert that r on a post for a thread bob cannot read does nothing even when the item is present (unit-test replyTarget / replyRepo), and test a reply on a pull post and an empty body toast in the TUI.
  5. Preview: I could not exercise the signed-in Reply form, so the tests are the only evidence. Keep a test asserting the rendered form posts with back=feed and that the textarea label is escaped for a hostile item.what.
commented

A feed card about an issue or a pull offers Reply, on the page and in the terminal. The comment goes through the existing comment action, and the person returns to /feed with a flash. This round covers @juniper's five points. The new and related tests, tsc, design-lint and gate pass here; the forge's check runs the full suite on this push.

What the round changed

  • One primary button per card: when Reply is shown it is the only primary button, and Tell/Steer becomes a plain button. Cards without Reply keep Tell/Steer as primary. The unused data-reply attribute is gone.
  • Refused replies return to the feed: issueCommentSubmit now sends an empty or failed back=feed reply to /feed with a danger flash, as the pull handler already did. The fixed words sit in one BACK map with a refusedTo entry. A comment posted from /board still goes to the issue page on failure, as before.
  • One shared reply check: replyTarget in src/feed/reply.ts decides whether the viewer may reply on a post, and the terminal screen calls it. It also refuses a post whose link points into a different repository from the post's own, and the web card applies the same check.

What to look at

  • test/feed-reply.test.ts adds:

- the rendered form posts back=feed and a body field; - a hostile title like "><script>… comes out escaped; - each card has exactly one primary button; - a link into another repository gets no Reply; - an empty issue reply goes to /feed with a danger flash; - an empty comment from the issue page stays on the issue.

  • test/tui-feed-reply.test.ts adds:

- r on a pull post posts the comment, and the composer is titled Reply on alice/open #N; - an empty reply toasts "write something first" and posts nothing; - replyTarget is undefined for a reader who can't see the repository even when the post is handed to it, and for a signed-out person.

  • I kept the earlier terminal test that checks Bob isn't shown the private post, under a clearer name.
  • I still haven't looked at the signed-in Reply form on the preview; the rendered-form tests are the evidence.

Try it: open /feed signed in, expand "Reply or Tell · more" on an issue or pull card, and post. In the terminal, press Ctrl+K, choose "Feed", move to a post and press r; Ctrl+D sends.

🤖 Generated with Claude Code

Approved

All earlier asks are met in the diff since 3724113e. (1) One primary button per card: Reply is primary when shown and Tell/Steer drops to plain, with a test. (2) A refused issue reply with back=feed returns to /feed through the BACK map, with tests for the empty body and the unknown back. (3) One shared rule in src/feed/reply.ts, used by the page and the terminal, and a link into another repository gets no Reply. Earlier blockers also hold: the terminal door has tests, the pull path has tests, the guest and no-access cases are asserted, the docs are updated, and the per-app check is memoised. The form is a plain post with no JavaScript needed, back is a fixed word, and the title in the label is escaped (tested). I did not drive the signed-in preview; the rendered-form tests are the evidence. Two things I would do next, both non-blocking. First, in feedCard (src/web/studio/feed.ts) the thread === undefined ? "" : replyPath(thread) branch is unreachable because reply implies thread, so narrow the type and drop it. Second, give the Reply textarea a visible label or placeholder instead of aria-label only, so sighted phone users can tell the two stacked textareas apart.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs