Skip to content

fix(thread): render unresolvable task refs like the web - #4531

Merged
stamp-build[bot] merged 4 commits into
mainfrom
agent/lagoon/unresolvable-refs-web
Nov 10, 2026
Merged

stamp-build[bot] merged 4 commits into
mainfrom
agent/lagoon/unresolvable-refs-web

Conversation

@stamp-build

@stamp-build stamp-build Bot commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Lagoon from raft opened this pull request through Stamp
View in Stamp →


Task #proj-mobile:#107 — owner: "just align with web"; add-on: "我们自己乱猜的那个可以干掉".

Web truth (botiverse/slock origin/staging 194e5d30 / 37d47d70, packages/web/src/components/message/MessageItem.tsx)

Every unresolvable ref renders as plain text — no chip, no special style, no tap, no tooltip:

  • bare #123: chip only for a known task of the conversation being read (taskByChannelNumber), else plain (L884-897, then #channel L900-906 → plain). task #N keyword always links (not in mobile's dialect; unchanged here).
  • #channel: known channel only (L905).
  • #chan:#7 / dm:@peer:#7: plain when the conversation is unknown (L829, L838).
  • #chan:shortid / dm:@peer:shortid: plain when unknown (L793, L808-810).
  • #chan msg=…: <span> when unknown (L995, L1076-1077).
  • Task context: taskByChannelNumber = server tasks + channel tasks + the message's own linkedTask, looked up with taskContextChannelId = parentChannelId || message.channelId (L3823-3832); a task conversation passes parentChannelId: task.channelId (TaskConversationDialog.tsx:531). No write gate.
  • Task open: GET /tasks/channel/:id/number/:n only; a missing task is console.error, no toast (utils/openTaskRef.ts L27-50).

Mobile change

  • isKnownThreadMarkdownTag: a bare #N is valid only if it's a known task of the conversation (no list no longer means "every #N is a task"). Thread page / visual host fall back to the loaded task statuses.
  • threadMarkdownTaskStatusesByNumber: only the current channel's tasks (server tasks of other channels no longer count).
  • resolveSharedTaskReference: channel lookup only, like the web.
  • Task-ref NotFound: log only, no toast. A parse miss: log only. (Failed network errors still toast.)
  • Channel / thread / message / DM refs were already plain text when unresolvable; unchanged.

Review fixes (second commit)

  • Task conversations: a bare #N renders and opens against the task's HOST channel (markdownTaskContextChannelId, from the header's resolved parentChannelId), not the conversation's own channel. No context until the header resolves.
  • Read-only / resolving access: the ref context is not write-gated. taskChannelId (Tasks tab, task writes, convert-to-task) keeps its gate; when it is null the thread loads the context channel's tasks for its refs (shouldLoadMarkdownTaskContextTasks).
  • 404: in the task-ref open path a tasks_404 from GET /tasks/channel/:id/number/:n is NotFound (log only, no toast). Network / 5xx stay Failed and still toast.
  • Own linked task: RaftMarkdownOwnTaskStatusScope also hands the body a tag validity that knows the message's own task (withRaftMarkdownOwnTaskNumber), so its #N chips like on web.
  • Leftover guesses: no ?: true in RaftRichTextContract; defaultRaftMarkdownTagValidity / defaultThreadMarkdownTagIsValid know no tag. The surfaces using the defaults (forward bundle page, forward preview, announcements, attachment comments, file preview, feedback, settings) have no task context, so #N there is plain as on web; the forward note of a thread message now uses the thread's tag context (it is the message's own text), so a known task still chips there.

Removed (mobile-only guessing)

  • ?: true fallback in isKnownThreadMarkdownTag (every bare #N treated as a task).
  • Server-wide loadTasks fallback in fetchSharedTaskReference, SharedTaskReferenceResolution.Ambiguous, taskReferenceCandidates, NetworkServer source, channelQualified param.
  • The panel a tap opened: the "Open task #N / choose which #N task" dialog (ThreadPage.kt): ThreadMarkdownTaskCandidateModal, ThreadMarkdownTaskCandidateRow, ThreadMarkdownTaskCandidateModalState, markdownTaskCandidateModalState, threadMarkdownTaskCandidateHelperText / localized…, threadMarkdownTaskCandidateChannelLabel / localized…, threadMarkdownTaskCandidateDetail / localized…, threadMarkdownTaskCandidateListHeight, and MarkdownTaskNumberOpenResult.Ambiguous. It was the only app-specific panel a ref tap opened (checked every ThreadMarkdownTagKind tap path; no GitHub/PR guess or fuzzy ref matching exists). No files removed; symbols only.
  • Strings (all 8 locales): thread_open_task_number, thread_task_candidate_{none,open_match,choose,unknown_channel,current_conversation,tap_open,current,untitled}, thread_state_no_tasks, thread_members_refresh_detail.
  • Test markdownTaskNumberOpenShowsLoadedAmbiguousStoreWithoutNetwork → replaced by markdownTaskNumberOpenNeverOpensAnotherChannelsTaskOfThatNumber.

Tests

  • RaftMarkdownTaskRefTest.unresolvableBareTaskRefIsPlainTextLikeTheWeb: #4442 → no token, no action; #7 and #triage:#169 still chip.
  • ThreadMarkdownTaskStatusesTest.anotherChannelsTaskIsNotThisConversationsTask.
  • Resolver tests updated.
  • ThreadMarkdownTaskStatusesTest.taskConversationBareRefsNameTheHostChannelsTasks, .readOnlyReaderKeepsTheTaskContext.
  • ThreadPayloadTest.taskConversationTaskRefOpensTheHostChannelsTask; markdownTaskNumberOpenNeverOpensAnotherChannelsTaskOfThatNumber pinned to a real 404 → NotFound; markdownTaskNumberOpenServerErrorIsAFailureNotAMiss (500/503 → Failed).
  • RaftMarkdownTaskRefTest.ownLinkedTaskChipsInItsOwnBody, .noTagContextKnowsNoTask.
  • Fixtures that relied on "every #N is a task" now pass their task context explicitly (markdown/rich-text tests, InlineChipWrapScreenshotTest, ThreadMessageRefPillPaddingScreenshotTest, RaftMarkdownTaskRefChipTest).
  • Re-recorded members.agent-activity.{app-events,overview}{,.dark}.png: the summary's botiverse/stamp #1592 (a PR number) no longer draws a fake task chip; it is plain text, as on web.
    Validation at 72c4317 (rebased on origin/main 8598def): local :shared:testDebugUnitTest for ThreadPayloadTest, ThreadMarkdownTaskStatusesTest, RaftMarkdownTaskRefTest, RaftMarkdownTest, RaftRichTextContractTest, SharedReplyThreadParentFailurePolicyTest and the markdown / chip / ref screenshot tests: all green (agent activity goldens re-recorded, above). Hosted PR CI and a scope=ios dispatch on this head.

Changeset: change-logs/1.24.0/changesets/unresolvable-refs-like-web.md.

🤖 Generated with Claude Code

Lagoon and others added 3 commits November 10, 2026 19:27
A bare `#4442` that is no known task of the conversation being read is
plain text (Web MessageItem bare task ref matcher), not a tappable chip
that toasts "can't open". Remove the mobile-only guesses behind it:

- "no known task list" no longer means "every #N is a task"
- the bare-ref task status map only holds the current channel's tasks
- opening a task ref asks only the conversation's channel (Web
  openTaskByChannelNumber): no server-wide task-list fallback, no
  "Ambiguous" candidate picker; a miss opens nothing and says nothing

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review fixes for #4531 (Web MessageItem `taskContextChannelId`):

- A task conversation's bare `#N` renders and opens against the task's
  host channel (TaskConversationDialog `parentChannelId: task.channelId`),
  not the conversation's own channel.
- The ref context is not gated on write access: a read-only reader, or one
  whose access is still resolving, keeps task chips and taps. The write
  gate stays on the Tasks tab and task writes; the refs load the context
  channel's tasks when nothing else does.
- A 404 from `GET /tasks/channel/:id/number/:n` is NotFound (log only, no
  toast), as `openTaskByChannelNumber`; network / 5xx stay Failed.
- The message's own linked task counts as known for its body's `#N`.
- No `?: true` in the rich-text validator; the default tag validities know
  no tag. The forward note uses the thread's tag context like the body.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@stamp-build
stamp-build Bot force-pushed the agent/lagoon/unresolvable-refs-web branch from 9325fca to a656d0c Compare November 10, 2026 19:51
With no tag context a bare `#N` is plain text, so the agent activity
summaries' `botiverse/stamp #1592` (a PR number, never a task) no longer
draws a fake task chip; its four goldens are re-recorded. The task chip
tests pass the known-task validity they render with.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@stamp-build
stamp-build Bot merged commit dc9d2cb into main Nov 10, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants