Skip to content

fix(client-runtime): take shell values for fields the detail stream never delivers - #151

Merged
QuinRiva merged 1 commit into
mainfrom
t3code/fix-missing-thread-metadata
Jul 29, 2026
Merged

fix(client-runtime): take shell values for fields the detail stream never delivers#151
QuinRiva merged 1 commit into
mainfrom
t3code/fix-missing-thread-metadata

Conversation

@QuinRiva

Copy link
Copy Markdown
Owner

A thread whose goal was attached after creation showed the "Goal tasks"
right-panel surface greyed out ("only available for threads linked to a goal")
even though the goal and its task tree existed in the database.

isThreadDetailEvent (apps/server/src/ws.ts) deliberately delivers only the
message/activity/session event set to a thread's detail subscription, so
thread.meta-updated never reaches it and detail.goalId stays at whatever it
was when the detail snapshot was taken — null for the normal path, where a goal
is attached seconds after the thread is created. The shell subscription does
carry the update, but mergeEnvironmentThread took only a whitelist of fields
from the shell and goalId was not on it, so activeThread.goalId read null
for the whole session and tasksAvailable stayed false.

Take goalId, role, purpose and kickoffBriefPath from the shell. The whitelist
was exhaustive when written upstream (pingdotgg#2978); it drifted as the fork added
thread fields without a test or exhaustiveness check tying it to the server-side
event predicate.

thread.kickoff-brief-set is shell-only for the same reason, so the staged-brief
preview (ChatView reads activeThread.kickoffBriefPath) had the identical
staleness — the reducer branch claiming it "live-updates out of the
awaiting-brief state" was unreachable. Fields written only by thread.created
(parentThreadId, forkFromThreadId, brief) cannot go stale and stay on the
detail; a second test pins that bound so they are not over-swept.

…ever delivers

A thread whose goal was attached after creation showed the "Goal tasks"
right-panel surface greyed out ("only available for threads linked to a goal")
even though the goal and its task tree existed in the database.

`isThreadDetailEvent` (apps/server/src/ws.ts) deliberately delivers only the
message/activity/session event set to a thread's detail subscription, so
`thread.meta-updated` never reaches it and `detail.goalId` stays at whatever it
was when the detail snapshot was taken — null for the normal path, where a goal
is attached seconds after the thread is created. The shell subscription does
carry the update, but `mergeEnvironmentThread` took only a whitelist of fields
from the shell and `goalId` was not on it, so `activeThread.goalId` read null
for the whole session and `tasksAvailable` stayed false.

Take goalId, role, purpose and kickoffBriefPath from the shell. The whitelist
was exhaustive when written upstream (pingdotgg#2978); it drifted as the fork added
thread fields without a test or exhaustiveness check tying it to the server-side
event predicate.

`thread.kickoff-brief-set` is shell-only for the same reason, so the staged-brief
preview (ChatView reads activeThread.kickoffBriefPath) had the identical
staleness — the reducer branch claiming it "live-updates out of the
awaiting-brief state" was unreachable. Fields written only by `thread.created`
(parentThreadId, forkFromThreadId, brief) cannot go stale and stay on the
detail; a second test pins that bound so they are not over-swept.
@QuinRiva
QuinRiva merged commit 5ffd4c6 into main Jul 29, 2026
@QuinRiva
QuinRiva deleted the t3code/fix-missing-thread-metadata branch July 29, 2026 06:42
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:S labels Jul 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant