Repository navigation
feat(web): a shared conversation shows who wrote what and who answered - #602
Jacksondr5 wants to merge 24 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
1326f8f to
a81ab45
Compare
a81ab45 to
8f32050
Compare
32fd505 to
d59a4dc
Compare
d59a4dc to
9531763
Compare
c698a84 to
dec7d20
Compare
|
@bryantderosier an update since my replies, after Jackson's read of the stack (2026-10-13):
A third security pass on the content change and a final live pass at 🤖 Generated with Claude Code |
…s cards Through the seam upstream's timeline already gives J5 for agent-to-agent deliveries: the note that tells the agent who can write is a one-line notice that opens, and a message the server records another person as having written is a card with their name and a guest or member tag. The card is a draft look. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nt's author line Upstream edit awaiting Jackson's approval: MessagesTimeline.tsx, one import, the entries prop renamed where it is read, and one hook call. The hook reads the server's record of who wrote what, takes the "[Message from …]" line off those messages, and keeps whose each is for J5's card. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n line Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d it Upstream edit awaiting Jackson's approval: MessagesTimeline.tsx, one import and one line after a settled prompt's answer. Upstream shows no answerer, so without it "shows who answered" (Shared conversations AC9) is not met for questions and approvals. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… with them A guest's client reads the rosters waiting on its thread (the list of every open proposal is a member's), shows each seat with no way to change it, and approves or declines as proposed when it holds Collaborate. The gate's card says who decided when the server names them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on a settled prompt The server records who is answering before a prompt settles, so the name is there by then. A prompt still open is no reason to read: an answer the provider goes on to refuse would put a name on it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s author line The record of who wrote what was asked for when a message's id first appeared. A person's own message appears at once from what they typed, before the server's copy and its author row exist, so that read came too early and no other followed: the message then showed its raw "[Message from …]" line. The record is now asked for when a message's text gains the line, which is when the server's copy arrives, and once more for any message a read missed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Whose a message is comes from the server's record, which is read when the message arrives, so for a few frames the raw "[Message from …]" line showed. While the record has not answered for a message that begins as an authored one does, the line is kept off the screen: the reader's own message stays their own bubble, anyone else's is a card with no name yet, and a queued one shows the typed words. A message the record turns out not to hold is shown as typed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An author line is matched exactly as the server writes it, so J5's older envelopes that also begin "[Message from" no longer make an unshared thread ask who wrote its messages. The queue keeps what a message's author typed apart from the name it shows, so a member who edits a guest's queued message sends back the guest's words and not the label. The second read for a message is gone: a read asked for while another is out is sent again and the earlier answer is never shown, which a test now holds, so one read after a message arrives settles whose it is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r code outside the timeline Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…composer as it was typed Upstream edit awaiting Jackson's approval: ChatView.tsx, one import and the one line that restores the composer's prompt. Revert took the stored text, author line and all, so sending it again put a typed "[Message from …]" line under the real one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A queued message is given a new id when its turn starts, so for the moment before the record was read for that id a person's own message showed as a card with no name, then moved back to their own side. The queue already knew whose it was; that is carried across by thread and typed words until the record answers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Its card had none of the controls upstream gives a person's own message. Copy gives the typed words. "Edit from here" is not offered on someone else's message. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… answers lose their author line The server now stores the note for the agent at the front of the message that carries it, and puts "[Answer from …]" on an answer to the agent's question. The functions that split a stored message and an answer are pure and live in the client runtime, where mobile can reach them. The web timeline shows a message as what its author typed, with the note it carried as a notice just before it, and an answer the record holds an answerer for as the person gave it. Copy, the queue, the queue's editor and "Edit from here" all take the typed words. Nothing draws a system message as a note any more. Two review fixes ride along. What the queue knew of a message's author is used only for a message stored with the platform's author line that the record has not answered for yet, is keyed by server, thread, that line and the typed words, and is dropped once the record answers: a plain message, or the same words from someone else, is never drawn as another person's. And the record is asked for when a prompt settles in a thread known to be shared, so who answered shows even when no one has sent a message yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A message's note can now be about who can write or about which approvals were answered, so the notice reads "The agent was given a note with this message" and leaves the words to the note itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e person A person's reply from the inbox now begins "[Message from Jackson (human:…)]", and in a shared conversation "[Message from Jackson (member) (human:…)]". The card took the whole header for the sender's id, so the reply was no longer the viewer's own or anyone's. The id is read from the trailing parenthesis, the name is shown, and a reply that carries only the id reads as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The map that carried a queued message's author across the start of its turn is gone. It rested on a queued message getting a new id when its turn starts; it does not. Probed live: the same message id before and after, the author row present from the moment it is queued, and with the map switched off no frame shows a nameless card or a raw line when queued messages start. So nothing is ever matched by a message's words. The regression tests for identical words from different people, and for a plain message after collaboration ends, now state that directly. A test also holds that the last answer stays readable while the record is being read again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…is known shared The record names who answered a moment after the answer itself arrives, and for that one frame the row read "[Answer from Priya (guest)] Dogs" on both screens. The line is now taken off by its shape when the thread is known to be shared, without waiting for the record. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Edit from here" on a message carrying a note put the whole stored text in the composer: the note, the author line and the words. The rewind takes the message out of the author record, and the words were read after it. They are now read first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main took case 74 and the server's case moved to 75, so this layer's case is 77. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…its link The card drew the stored words as plain text, so a mention read "[Replay fixture](t3-context://v1/thread/…)". The words are now drawn as upstream draws a person's own, and Copy gives a mention as its label, as upstream's Copy does. The note's comment no longer speaks of an approvals line, which the server no longer writes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ords Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…creen In a shared conversation the server leaves a member's message that begins with / as typed, with no author line and no record, so the agent can run it. On a guest's screen it was drawn as the guest's own bubble. The server stamps everything a guest sends, so an unstamped command that came from the server is a member's: it is now drawn as J5's card, naming "A member", since which member is not known. A member's screen keeps upstream's bubble. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Closed unmerged, by Jackson's decision (2026-10-17). The product was redefined from first principles in #631 (People and access, and a reworked Shared conversations), which reverses most of this stack's guest restrictions. The parts that still apply (the author line and note, the launch wrap, the answer records, the cards and notices) will be carried into a single rebuild PR against the new definitions, after the next upstream advance. The branch is kept for reference. 🤖 Generated with Claude Code |
Upstream edits, approved by Jackson (2026-10-13)
Four edits inside upstream's files, each its own commit.
04f1f39402MessagesTimeline.tsx, 1 import, 1 prop renamed where it is read, 1 hook call[Message from …]line; another person's message cannot be told from the reader's own658e068794MessagesTimeline.tsx, 1 import, 1 line7b3503ae92, thenab430f6235ChatView.tsx, 1 import, 2 lines[Message from …]line in the composer, and sending it again shows them91011056f6packages/client-runtime/package.json, 4 lines./j5/shared-conversationDecisions
/compact,/goal …and a provider's commands and skills work for a member. On a guest's screen such a message is drawn as a card naming "A member" (72872ebd51): the server stamps everything a guest sends, so an unstamped command from the server is a member's, though which member is not known. A member's screen keeps upstream's bubble for it.Known limits
331953bb1cit showed as a raw[label](t3-context://…)link.[Answer from …]for one frame.[Answer from Priya (guest)] Coffee: that is a tool's own output, which the client does not rewrite.Live testing of the final change
After the rebase onto #615 (#600 at
a1f88a47a7,72872ebd51), on a rebuilt test home: a guest who joined by an open link lands on the thread and sees cards and the notice, with no platform text; the same guest joins a second thread's open link as themselves. Nothing visible changed, so no new images.On #600 at
f59b9d9a12, a rebuilt test home, Claude Haiku and GPT-6-Luna, headless Chromium:t3-context://link and no platform text on either screen./compacton a Claude thread: sent as typed; compaction ran ("Context compacted 42.1K → 3.67K tokens"). The member sees their own bubble. The guest saw it as their own bubble ("You") before72872ebd51, and as a card naming "A member" after./goal …on a Codex thread (GPT-6-Luna): sent as typed; Codex took it as a goal ("Pursuing goal"), and the member then paused it. The guest sees a card naming "A member"./compact: the guest's own bubble shows/compact; the member sees the guest's card; no compaction ran.26263850b2): the card shows the thread's title, not the link.26263850b2): the words only (the limit above).Earlier runs are below, as they were written at the time.
Problem
In a shared conversation the server stores each person's message with a first line for the agent, and sends the agent its own notes about who can write. The client showed both raw, every message as "You", and never who answered a prompt (#533; Shared conversations AC9, AC17 to AC19).
What changed
Whose a message is comes from the server's record (
j5.sharing.listThreadAuthors), never from the text. It is asked for only when a thread holds a message that begins exactly as the server writes an author line (J5's older envelopes that also begin[Message fromdo not count; an ordinary thread holding one sent no request, counted live), and again when the server's copy of a person's message arrives (its text gains the author line) or a prompt settles. One read after a message arrives settles whose it is: a read asked for while another is out is sent again and the earlier answer is never shown, which a test holds. Who answered is shown only on a settled prompt: the server records the answerer before the prompt settles, and an open prompt is never read for one.Another person's message is a card with their name. The reader's own is drawn as before, without the author line.
The platform's note is a one-line notice, "The agent was told who can write to this thread", that opens to the text.
A settled prompt says who answered it.
The cards use the seam upstream's timeline already gives J5 for agent-to-agent deliveries, so they need no upstream edit.
A Crew roster for a guest (J5's own
j5/crewfiles, no upstream edit): a guest's client reads the rosters waiting on its thread (j5.crews.listThreadRosters), shows each seat's model and access with no way to change them, and approves or declines as proposed when it holds Collaborate. The gate's card says who decided ("· by Priya (guest)") when the server names them.Another person's message is J5's card. It carries Copy, which gives the typed words without the author line.
Not built, a product question for Jackson: "Edit from here" on someone else's message. It would hand one person's words to another's composer and rewind the thread from a message someone else sent.
Checked and clean: a browser or desktop notification and the in-app toast show a fixed title ("Thread completed", "Approval needed" and so on) and the thread's title, never message text; the page title is the app's name.
Known limit, as ruled: every member's connection is the one owner, so a second member sees the owner's messages as their own.
UI changes
Before is #601's tip and after is this PR's, on the same server data and the same conversation. The guest's first message carries the note for the agent, as the server now stores it:
From earlier runs, unchanged:
Live testing
On the reworked server, by the builder (
521e1ee6ebover #600 at48bc09fac8; rebuilt test home; a member and a guest added with the test script'sguestcommand; Claude Haiku; headless Chromium):[Message fromorj5_shared_conversation.After the server's fix for the missing answerer (
c7d99cacc7over #600 at9b380f8aea, rebuilt home, same setup):listThreadAuthorsbefore the thread was shared and one after.AskUserQuestion): the row read "Tea or coffee? / Coffee / · answered by Priya" for the member and "· answered by you" for the guest, with no[Answer from …]on it.Left as it is, by the build lead's ruling: where upstream's own tool row shows a tool call's result, an answer can still read
[Answer from Priya (guest)] Coffee. That is the answer with who gave it, which is true; the client does not rewrite a tool's output or edit upstream's row.Not exercised on this version: a question on Codex; a Crew roster; lowering and raising a level; a change note with a purpose line; an inbox reply's card; the queued start, frame-sampled.
Earlier runs, on the note as a message of its own. What they showed about cards, the queue, levels and Crew still holds; what they showed about the note's own row no longer applies.
On #600 at
b7678575d1(4db5235f0b, rebuilt test home, a member and a guest, Claude Haiku, headless Chromium):4db5235f0b): for one frame after a question was answered, both screens read[Answer from Priya (guest)] Dogs, because the answer arrives a moment before the record does. The line is now taken off by its shape once the thread is known to be shared. Frame-sampled again on both screens (936 and 961 frames): none shows it. Not covered: a member's screen for the very first prompt answered in a thread where nobody has yet sent a message since it was shared, which can still show it for that frame.On #600 at
bf9cab3f64(a6bfff17bf): rebased onto the newj5/main, FORK case renumbered to 77, no content change; typechecked and unit-tested, not run live again.On #600 at
31450e5ad3(then75fc1e0f9b): rebased only, typechecked and unit-tested, not run live again; the server change is wording in the note. Search results and a fork showing platform text are known limits (#612); the thread title gets no upstream edit.On #600 at
ccd862884d(thenb200532225, rebuilt test home, a guest collaborating on the project, Claude Haiku, headless Chromium):After the independent test of
3c2c3d02cf(the fix is now2c3fcdb22d, rebuilt test home, Claude Haiku, headless Chromium):2c3fcdb22d): "Edit from here" on a message carrying a note put the note, the author line and the words in the composer, and sending it drew all of it. Reproduced first, then fixed: the typed words are read before the rewind, which takes the message out of the author record. Seen on a note-carrying message and on a plain authored one: the composer holds only the typed words, and the resent message shows no platform text. No unit test: the change is the order of two lines inChatView.j5/main(79e53e8580), so it is not this stack's.Peer tester, #601 and #602 together (report:
test-reports/j5code/share-ui-5-shared-conversation.md, commit8f32050c64, Haiku and Luna turns). Verdict: fail, on three findings; all thirteen areas were exercised.c698a84b3b, which also keeps the line from flashing for a few frames while the record is read), re-run pending: a later message sometimes showed its raw[Message from …]line, and Copy then carried it. The record of who wrote what was read too early for a person's own message.b58c6f28a3), re-run pending: a View guest could click Dismiss on a dismissible question; the server refused it.The tester's final round (same report,
dec7d20416thena5424e6224): all pass. Frame-sampled on both screens through hold, queue, edit and release: no raw author line, no nameless card, no message on the wrong side. A member's edit of a guest's queued message is stored as the author line, with its "edited by", then exactly the typed words. "Edit from here" returns typed words. An unshared thread with an inbox-reply-shaped message sends no request; a typed look-alike sends one and stays as typed. A change note with a purpose line reads cleanly, and in-thread search shows no author line. Copy on the other person's card gives exactly their words, both ways, and there is no "Edit from here" on someone else's message. A rename while "Let … collaborate?" is open is caught on Save (see #601), with one caveat recorded there. Only these requested checks were re-run on the final commits; the full thirteen-item run is on8f32050c64.The tester's earlier re-run (same report, commit
c698a84b3b): the raw author line and Copy pass with zero frames showing the line on either screen, including on reopening; Dismiss as a View guest passes; a question answered by the member shows the member's name; a Crew seat beneath the Captain is read-only with no cards or notes; a held guest's queued message leaves both queues when they are lowered; a guest shared asJackson (member)reads "Jackson" tagged guest. One fail there: a person's own queued message showed as a card with no name for 60 to 300 ms when its turn started. Fixed since (ina5424e6224); the builder's frame sampling on the fix found none; the tester's re-check is pending.After the Opus review (nothing blocking), on
a5424e6224, seen live by the builder: an ordinary thread holding an inbox-reply-shaped message sends nolistThreadAuthors, and a typed look-alike line is asked about once and then shown as typed; a member who edits a guest's queued message is handed the guest's words, sends exactly the edited words, and the stored text is the author line then those words; "Edit from here" on a message of a shared conversation returns the typed words; in-thread search shows messages without the line; a guest lowered to View while editing their own queued message loses the item and the edit state with no error.The tester's targeted re-run (same report, commit
d59a4dcaf9):c698a84b3b, one commit later, keeps the line off the screen while the record is read; the builder's own per-frame sampling there found none. The tester's sampling on that commit is pending.8f32050c64; later commits got these targeted re-runs only.The builder's own runs:
By the builder, on the commits now at the tip, same setup as #601: the same conversation opened as the member and as the guest; the member sees the guest's card and the guest sees the member's; the note is a notice for both; after the guest approved a command, the member's expanded work log reads "· answered by Priya". A Crew, live: after the member allowed it, the guest asked for a Crew of two; the roster appeared above the guest's composer with Decline and "Approve 2 seats" and no Edit, Remove or Add; the guest approved; the gate left and the notice read "readme-note-crew · by Priya (guest)". The member's card for the same roster had the edit controls. One stray request seen: after approving, the card asked for one more runtime preview and was told the proposal is no longer open; nothing showed. The agent told the guest the roster was "waiting for approval in the app's inbox", which is the agent's own wording and not true for a guest. Not exercised live: a question prompt's answerer, a thread shared and later unshared, a long history.
Upstream impact
FORK.md case 77 (76 until main took case 74 and the server's case moved up) and the file-table row; a History line under D33.
Checklist
FORK.mdin this PRClaude Opus 5.5, Claude Code harness in J5 Code.
🤖 Generated with Claude Code