Context that came with a turn is a row of its own #69
No reviewers
Labels
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
iterative-works/claude-code-query!69
Loading…
Reference in a new issue
No description provided.
Delete branch "cc-chat"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Slice — cc-chat/05-procedures-worker-chat
Goal: do a real piece of worker-session work in the
proceduresdashboard through<cc-chat>, with procedures' own worker chat deleted rather than beside it.Fit test (close gate): Michal opens a Matter he cares about, works a worker session through the migrated dashboard, and would put the live system on it — nothing missing, nothing foreign, no second generation left in the tree.
Fit passed on the offline harness, 2026-08-30, against real Claude sessions.
This PR carries this repository's half. The migration itself lands in
proceduresoncc-chat-worker-chat(907e4d08), on its own PR there. Slices 01–04 of this effort already shipped as #64, #67 and #68.What is in it
Context that came with a turn is a row of its own (CC-D4)
UserInputcarries three things — what a person typed, what the application attached, and the channel that composed it. The Claude Code adapter decoded all three and kept one. So a brief the dashboard wrote and a prompt reacting to an event both reached the page asTranscriptEntry.UserMessage, documented "what the person typed".The vendor cannot tell them apart for us. Across 780 entries
procedureswrote — 508 reactive, 166 interactive, 106matter-brief— every one carriespromptSource: "sdk"andentrypoint: "sdk-cli": the vendor marks the transport, not the origin. The Messages API offers no field for injected content, and the CLI dropsmessage.metadata, a top-levelsourceand a top-levelattachmentsoutright (probed on 2.1.251).TranscriptEntry.Context(at, name, prose)— a seventh row kind.UserMessagecarries the channel that composed it, absent when somebody typed it.TranscriptMarkuprenders<cc-context name="…">as a folded row and putschanneloncc-message.TranscriptCodecround-trips both, tolerantly in each direction.cc-chat.cssdraws the row and says how a host takes one off the page.The split of knowledge is the point: the SDK knows that a block is context, its name and its body, and renders the shape; the consumer knows what the name means and how it should look, in
cc-chat.css. Nothing here learns any host's vocabulary.A conversation opened at its oldest row
TranscriptScroll.scrollersearched from the parent, so a host that put the scrolling overflow oncc-transcriptitself — the box every host reaches for — was walked past and the element scrolled the page instead. Its own documentation already said the transcript counts. Found by the migration; fixed with a test.Warnings stop this build
SharedModule.scalacOptionsappends-Werror. The sharedmill-iw-supportbaseline reports warnings without failing on them, and__.compiledoes not compile test sources at all — so an inexhaustive match introduced by the new enum case sat in the tree with every gate green. The tree was already clean under-Werroron the first compile; the flag is what makes a green gate evidence.Review
Six reviewers (style, testing, security, scala3, composition, architecture): 1 critical, 5 warnings, 12 suggestions. The critical was the inexhaustive match above, found by the scala3 review rather than by the build — fixed, and the build now refuses it. Every warning was acted on; the suggestions taken and not taken are recorded with reasons in
review-slice-20260830-145701.md.Two findings worth surfacing:
display: none, and hidden context is still in the document, the source and the accessibility tree. The model, the renderer and the sheet now say so, and say that anything a viewer must not have is left off the message rather than styled away.Channel.Interactiveis fail-open. Forget to name a channel and the turn renders as a person's words. Documented onChannelitself as what the sender declared, never an authenticated signal. Making omission a compile-time decision is parked — it breaks every caller.Security review confirmed no attribute injection (scalatags escapes every attribute value) and no widened rendering trust boundary (context prose goes through the same
Markdown.prosesanitiser message prose already did:escapeHtml, allow-listed URL schemes, no image fetching).Gates
__.test915 ·__.checkFormat·__.fix --check· every main and test source compiles warning-free under-Werror.Verified end to end on the offline harness against a real Claude session: the worker read the brief out of its context block and oriented correctly (7 tool calls, 17 s); the opening line is marked with the channel that composed it; a message Michal typed carries none.
Follow-ups (parked, flushed to the effort map)
LookEvery = 250 mspoll after the CLI writes the file. Fast today on a warm local CLI; nothing in the contract makes it so.proceduresreads vendor-first and falls back to~/.claude/transcript-archive— that directory does not exist, and nothing writes it, becausearchivedefaults toNoneand installsSessionArchiveHook.none. The machinery all exists and is opt-in, defaults to nothing, and fails silently. Every consumer will get this wrong the same way.Channel.Interactivedefault;ContextItem.Viewing(url)going through the markdown parser; the global chat generation.🤖 Generated with Claude Code
https://claude.ai/code/session_01DS9XLuXRvpbEuV9ZE3Whn1