ConversationMention.tsfeat: Current | Future agenda documents (design: agenda-current-future-restructure phases 3, 5, 6)
Three phases land together because they are interdependent — the markdown
grammar, the path cutover and the band reconciler all touch the same seam and
were built concurrently.
Phase 3 (client): retires conversationGroup. The load-bearing change is the
@-mention flow — selecting a conversation used to call promoteTaskToGroup,
which WRAPPED the task in a group; that single call produced the nesting this
redesign removes. It now inserts an inline conversationNode chip and still sets
the conversationId attr, which stays the owning FK. promote-task-to-group.ts
and ConversationGroupNode.tsx are deleted, conversation resolution in
agenda-task-walk reads attr -> inline chips -> nearest shallower row, and the
Tab / Shift-Tab cases that moved tasks in and out of a group container are gone
(nesting is indentLevel now). The markdown grammar drops the group token and
finally serializes dueDate, closing a data-loss bug that would otherwise have
collapsed every band in the Future view.
Phase 5: one agenda document per view instead of one per calendar day.
`user/agendas/{current,future}`; the rolling flag is gone because Current IS
the rolling doc by definition. Current holds everything due on or before today
with no lookback floor; Future holds everything after.
Phase 6: the Future document is divided into five relative bands derived from
each task's dueDate on every read. Because that membership drifts at midnight,
reflowBands moves rows between bands — the one place the reconciler is allowed
to reflow, deliberately against the daily reconciler's no-reflow rule.
Verified headlessly against this repo's server (port 8790) as
<email>: `agenda tree future` returns all five bands correctly
bucketed (07-22 tomorrow, 07-23 day-after, 07-24 next-week, Aug next-month,
Sep future) with inline chips and group subsections only where populated;
`agenda tree current` returns the group sections plus the __past__ lane.
222 server tests, 218 mail tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <<email>>Jul 21, 2026, 4:42 PMConversationMentionList.tsxrefactor: consolidate document code into documents/ + add {{ event mention
Frontend: move the editor primitive, file-link/, mention/, yjs/, and history/
under apps/mail/modules/documents/ so every doc-editor concern lives in one
place. Rename AgendaConversationMention -> ConversationMention and generalize
it to take an onSelect callback so the agenda keeps its task-promotion
dispatch while regular docs insert a plain conversationNode chip.
Backend: rename services/document-store/ -> services/documents/ and absorb
services/sse/doc-event-bus.ts + services/sse/doc-events-delta.ts alongside
their tests.
New: {{ event mention in documents. Custom Tiptap suggestion matcher requires
the literal {{ prefix; picker shows a type-icon, title, conversation context,
and relative time; selecting inserts an eventNode chip. New tRPC route
crm.searchEventsForMention runs a global search across the user's crm_events
(emails, slack, meetings, calls, notes, custom) joined to company info.
crm_conversation_updates lives in its own table and stays excluded by design.
Co-Authored-By: Claude Opus 4.7 (1M context) <<email>>May 26, 2026, 9:30 AMEventChip.tsxfeat: typed cells, live ref chips, and tables as first-class files (design: table-documents phases 6, 7)
Phase 6 — a cell chip and a prose chip are literally the same component. ConversationNode
and EventNode were split the way FileLinkChip already was (Content + the NodeViewProps
wrapper that mounts it), so behaviour stays identical by construction: same data hooks,
same click handler, same setSelectedArtifact path. The only PM-specific parts were
NodeViewWrapper and reading node.attrs, which is why the extraction is small.
Editing mounts a one-line TipTap instance for the focused cell ONLY, configured with the
EXISTING suggestion extensions — so typing `@` in a table cell runs the same extension,
the same search, and inserts the same node as typing `@` in a prose document, rather than
a parallel implementation that drifts. Exactly one editor is alive at a time, so the
descriptor-tree costs that rule out a ProseMirror grid never apply here.
Phase 7 — "New table" in the file-creation menu, a table graph-node kind, "N rows × M
columns" from the metadata the server hook already writes, the grid in the artifact panel
(discriminated inside FileArtifact on the FETCHED documentType, since the outer switch is
on ContextKind where a table is just a `file`), a read-only grid on the public share page,
resolveOpenDoc, and Download as Excel/CSV wired to documents.exportTable.
Also completes Phase 10's agent-facing half: the `table` tool's `create` now takes a
`from` clause, so an agent materializes rows from a real query instead of transcribing
them. The query runs BEFORE the document is provisioned, so an over-cap or malformed
filter leaves no half-built table behind, and truncation plus any binding error is
surfaced as a tool warning rather than silently yielding a short or empty column.
Three fixes found by running the suites rather than by reading:
- The tool description had grown to 2134 chars, past the 2048 limit Claude Code truncates
at — text past the cutoff is silently dropped for every caller. Trimmed to 2030 while
ADDING the `from` guidance, which is the part most worth having early.
- tableTool.test.ts enumerated its mock of the documents barrel, so every new import in
the tool broke the file with a mock error rather than a real failure. It now spreads the
real module.
- A cell-ref offset expectation was hand-counted one short (`[[conversation: 9f2e]]` is 22
chars, so end is 27). The implementation was right; the test now asserts by slicing the
value, since these offsets exist precisely so the grid can interleave text and chips.
Tests: 1787 server, 55 mail across the table/home/files suites. Both apps typecheck clean.
Co-Authored-By: Claude Opus 5 (1M context) <<email>>Aug 10, 2026, 5:04 PMEventMention.tsrefactor: consolidate document code into documents/ + add {{ event mention
Frontend: move the editor primitive, file-link/, mention/, yjs/, and history/
under apps/mail/modules/documents/ so every doc-editor concern lives in one
place. Rename AgendaConversationMention -> ConversationMention and generalize
it to take an onSelect callback so the agenda keeps its task-promotion
dispatch while regular docs insert a plain conversationNode chip.
Backend: rename services/document-store/ -> services/documents/ and absorb
services/sse/doc-event-bus.ts + services/sse/doc-events-delta.ts alongside
their tests.
New: {{ event mention in documents. Custom Tiptap suggestion matcher requires
the literal {{ prefix; picker shows a type-icon, title, conversation context,
and relative time; selecting inserts an eventNode chip. New tRPC route
crm.searchEventsForMention runs a global search across the user's crm_events
(emails, slack, meetings, calls, notes, custom) joined to company info.
crm_conversation_updates lives in its own table and stays excluded by design.
Co-Authored-By: Claude Opus 4.7 (1M context) <<email>>May 26, 2026, 9:30 AMEventMentionList.tsxrefactor: consolidate document code into documents/ + add {{ event mention
Frontend: move the editor primitive, file-link/, mention/, yjs/, and history/
under apps/mail/modules/documents/ so every doc-editor concern lives in one
place. Rename AgendaConversationMention -> ConversationMention and generalize
it to take an onSelect callback so the agenda keeps its task-promotion
dispatch while regular docs insert a plain conversationNode chip.
Backend: rename services/document-store/ -> services/documents/ and absorb
services/sse/doc-event-bus.ts + services/sse/doc-events-delta.ts alongside
their tests.
New: {{ event mention in documents. Custom Tiptap suggestion matcher requires
the literal {{ prefix; picker shows a type-icon, title, conversation context,
and relative time; selecting inserts an eventNode chip. New tRPC route
crm.searchEventsForMention runs a global search across the user's crm_events
(emails, slack, meetings, calls, notes, custom) joined to company info.
crm_conversation_updates lives in its own table and stays excluded by design.
Co-Authored-By: Claude Opus 4.7 (1M context) <<email>>May 26, 2026, 9:30 AMEventNode.tsxfeat: typed cells, live ref chips, and tables as first-class files (design: table-documents phases 6, 7)
Phase 6 — a cell chip and a prose chip are literally the same component. ConversationNode
and EventNode were split the way FileLinkChip already was (Content + the NodeViewProps
wrapper that mounts it), so behaviour stays identical by construction: same data hooks,
same click handler, same setSelectedArtifact path. The only PM-specific parts were
NodeViewWrapper and reading node.attrs, which is why the extraction is small.
Editing mounts a one-line TipTap instance for the focused cell ONLY, configured with the
EXISTING suggestion extensions — so typing `@` in a table cell runs the same extension,
the same search, and inserts the same node as typing `@` in a prose document, rather than
a parallel implementation that drifts. Exactly one editor is alive at a time, so the
descriptor-tree costs that rule out a ProseMirror grid never apply here.
Phase 7 — "New table" in the file-creation menu, a table graph-node kind, "N rows × M
columns" from the metadata the server hook already writes, the grid in the artifact panel
(discriminated inside FileArtifact on the FETCHED documentType, since the outer switch is
on ContextKind where a table is just a `file`), a read-only grid on the public share page,
resolveOpenDoc, and Download as Excel/CSV wired to documents.exportTable.
Also completes Phase 10's agent-facing half: the `table` tool's `create` now takes a
`from` clause, so an agent materializes rows from a real query instead of transcribing
them. The query runs BEFORE the document is provisioned, so an over-cap or malformed
filter leaves no half-built table behind, and truncation plus any binding error is
surfaced as a tool warning rather than silently yielding a short or empty column.
Three fixes found by running the suites rather than by reading:
- The tool description had grown to 2134 chars, past the 2048 limit Claude Code truncates
at — text past the cutoff is silently dropped for every caller. Trimmed to 2030 while
ADDING the `from` guidance, which is the part most worth having early.
- tableTool.test.ts enumerated its mock of the documents barrel, so every new import in
the tool broke the file with a mock error rather than a real failure. It now spreads the
real module.
- A cell-ref offset expectation was hand-counted one short (`[[conversation: 9f2e]]` is 22
chars, so end is 27). The implementation was right; the test now asserts by slicing the
value, since these offsets exist precisely so the grid can interleave text and chips.
Tests: 1787 server, 55 mail across the table/home/files suites. Both apps typecheck clean.
Co-Authored-By: Claude Opus 5 (1M context) <<email>>Aug 10, 2026, 5:04 PM