feat(session): offer to open the conversation a fork continues - #1031
Merged
Conversation
A `codex fork` session inherits its opening history from another conversation, and the server already names that parent in `meta.inherited_history.source_id`. The client received the field and discarded it during narrowing, so there was no way to reach the parent as it exists now — the stitched prefix only shows it up to the fork point. Carry `source_id` onto the divider seam and add an overflow-menu entry that navigates to it. The id is read off the conversation query the diffs feature already runs, so this adds no fetch: `inherited_history` rides on the same conversation's meta regardless of the byte budget. The entry is disabled rather than hidden when there is no parent to open, which covers all three ways that happens: a non-fork, a server too old to send the field, and an `unavailable` seam whose source file is gone and which therefore carries no id.
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.
Why
A
codex forksession continues an earlier conversation, and the streamer already serves the parent's messages ahead of the fork's own with a divider between them.But that stitched prefix only shows the parent up to the fork point. There was no way to reach the parent as it exists now, including everything that happened after the fork — two different questions, and only one was answerable.
The server already answers the second one:
meta.inherited_history.source_idnames the parent conversation, and it has been on the wire since the fork work landed.The client received it and threw it away during narrowing.
What changed
inheritedHistorySeam()carriessource_idonto thedividervariant, guarded the same way the other fields are — the file's own comment notes this is untrusted server input.app/session/[id].tsxgains one overflow-menu entry that pushes/conversation/<sourceId>?server=<serverId>, the established navigation pattern.No new fetch. The id is read off the conversation query the diffs feature already runs;
inherited_historyrides on that conversation's meta regardless of the byte budget, so this is a derived value rather than another request.Not offering a dead link
The entry is
disabledrather than hidden, and there are three ways there is nothing to open:source_idunavailable— the parent's file is gone (source_missing) — and carries no id at allAll three land on the same disabled state by construction rather than by a special case.
Tests
Four new cases on the seam:
source_idis carried; it is absent when the server omits it; a non-string or empty value is rejected rather than passed on; and theunavailableseam still has no id.One existing assertion was edited.
inheritedHistorySeamnow returns an extra field, which broke an exact-shapetoEqual.The expectation was updated to include
sourceIdrather than loosened toobjectContaining— the shape genuinely changed, so the test pinning it should change with it.Verification
tsc --noEmit— 0 errorseslinton the three touched source files — cleannpm run test:i18n— 460 passed, all four locales, including the unused-key gate (which passing also proves the analyzer sees the newt()call)SessionScreenintegration suites,--runInBand— 9 suites, 33 testsNote for reviewers
The SessionScreen suites need
--forceExit.Without it jest completes the work and then hangs on an open handle — observed at 8 hours elapsed against 46 seconds of CPU, with zero output, which is indistinguishable from a slow run.
This is pre-existing on
main(the i18n suites print the same force-exit warning) and is not introduced here, but it is worth its own fix.