Repository navigation
feat(operator): promote the room to a column on jobs [D-646] - #237
Merged
Merged
Conversation
… [D-646] A job's room existed only inside the opaque talk_binding blob, so every reader parsed JSON to get at it and GET /jobs could not return it at all. Migration 0008 adds room_token and room_name and recovers them for every job already recorded; SetJobTalkBinding keeps them in step on every write, deriving them from the same JSON the migration read so the two cannot disagree. The name is resolved asynchronously and arrives on a second write, so a blank value means "nothing to say" and never "set to empty" — the rule setMeetingBundleFields already documents. Without it every job whose name lookup was slow, or failed, would have its name blanked by its own re-persist. The token gets a column but not the API. For a public conversation the token is also the link that joins it, so what leaves the operator stays a one-way derivation of it and never the token itself (D-622) — the same reason talk_binding has always been withheld. The two migration-count assertions now compare against the embedded migration set instead of a hand-written list, so they assert what they mean and do not have to be edited by every migration that follows.
Every row in the job list read "Call a1b2c3d4" — the last path segment of the request URL, which tells an operator nothing about which conversation it was. Now that the room name reaches GET /jobs, the row and the detail heading use it, and keep the token as the fallback for a non-Talk job, a job whose room-name lookup never completed, and every job recorded before the column existed. meetingLabel and requestUrlLabel move into viewState.ts on the way, so the preference is covered by a test rather than living untested inside the markup.
… [D-646] Every hop from Talk to catalog.json was unit-tested and no two had been run in sequence. The chain has broken here before: the exporter re-derives a catalog entry's room from the file on every republish, so a room that reached the catalog once could be silently dropped by the next re-seal (D-640). The roundtrip already creates a conversation with a known token and name and already drives record → build → seal → publish, so the assertion is the cheapest place to close the gap. roomId is recomputed here from the token rather than read back, which is the point: it proves the whole token → id → catalog path instead of proving that some string round-tripped. The catalog needs its own wait — the local sink writes it after the .opus that phase 7 polls for, so the existing poll does not imply it is on disk.
delasous
marked this pull request as ready for review
September 3, 2026 15:34
D-711 landed on main while this branch was open and rebuilt the same two label helpers, so the conflict is a real overlap rather than a textual one. Main's shape wins: parseRequestJSON / requestUrlLabel / meetingLabel exported from Operator.svelte's module script and covered by Operator.test.ts. It labels a Talk-triggered job `Call <roomToken>` instead of the generic "Recording" this branch was written against, and it also fixes the Meeting URL field and the red error banner — none of which this branch touched. So this branch drops its own extraction of the two helpers into viewState.ts and adds only what D-711 cannot know: an optional room name, preferred over every token-derived label. `Call <roomToken>` says which call; the conversation's own name says which conversation. The changelog fragment is restated against the new baseline — the panel labelled a recording by its token, not "Recording".
This was referenced Sep 4, 2026
|
Merging this PR using merge would make these currently mergeable PRs conflict: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of D-646. Takes the two pieces with a named consumer; the rest is deferred with reasons on the ticket.
What changes
The room becomes a real column. Migration 0008 adds
room_tokenandroom_nametojobsand recovers them fromtalk_bindingfor every job already recorded.SetJobTalkBindingderives them from the same JSON on every write, so the blob and the columns cannot disagree. A blank value means "nothing to say", never "set to empty" — the room name arrives on a second write, so without that rule every job whose name lookup was slow or failed would have its name blanked by its own re-persist.GET /jobsreturnsroom_name.room_tokengets a column but is left out of the response, for the same reasontalk_bindingis. Note this is consistency, not a new boundary: the token is already reachable on this endpoint insiderequest_json, which has always been returned.The control panel names a recording after its conversation. As of D-711 a recording is labelled by its room token,
Call 3qbs6123vxx— which identifies the call but not which conversation it was. Rows and the detail heading now prefer the conversation's display name where the operator has it, and D-711's labels remain the fallback. This adds a third optional argument to D-711'smeetingLabel; the tests live beside its own inOperator.test.ts.The roundtrip e2e asserts the published catalog carries the room. Every hop was unit-tested and no two had been run in sequence; the chain has broken here before (D-640: a catalog room silently dropped by the next re-seal).
roomIdis recomputed from the token rather than read back, so the assertion proves the whole token → id → catalog path. The catalog needs its own wait — the local sink writes it after the.opusphase 7 polls for.Relationship to D-711
D-711 landed on main (#253) while this branch was open and rebuilt the same two helpers, so the merge conflict was a real overlap. Main's shape won:
parseRequestJSON/requestUrlLabel/meetingLabelexported fromOperator.svelte's module script and covered byOperator.test.ts. This branch dropped its own extraction of those helpers intoviewState.tsand now adds only what D-711 cannot know — the conversation's name, preferred over any token-derived label.Not in this PR
talkRoomState.Owneris the identity the operator impersonates to read the room name and list participants, and both already work offtalk_binding. No screen, query or user wants it as a field.Verification
go vetandgo test ./...incassini-operator;npm test(90) andnpm run build:allincassini-app;bash -nandshellcheck -x --severity=styleon the roundtrip script. The e2e assertion's derivation was checked against the Go implementation for the same token, and against catalogs with a wrong name, a wrong id, no room fields, no meetings and two meetings.Upgrade path checked end to end against a database built by the pre-change binary: seeded with a Talk job carrying a resolved room name, one without, and a non-Talk job; the new binary applied 0008, backfilled both room columns, and
GET /jobsreturnedroom_namefor the first andnullfor the other two, withroom_token,talk_binding,backend_urlandownerall absent from the response.The roundtrip itself does not run on an ordinary PR — it needs the
full-cilabel (self-hosted GPU, ~25 min).Migration 0008 applies on operator start (
OpenStore→ensureSchema, one transaction). No manual step, no script to run, and no change to any already-published catalog.