fix(sandbox): THREAD_SANDBOX_START resolves the repository before creating a chat
What is this contribution about?
Without a threadId, THREAD_SANDBOX_START (#8434) created the chat first and only then looked up repository. An unknown or ambiguous repository (deco sandbox new --repo owner/typo) failed after the chat existed, which left an empty "New chat" in the organization's chat list.
The repository is now resolved, along with the default-agent rule and the user check, before the chat is created, so every refusal comes first and leaves nothing behind. Behavior for valid input is unchanged.
How did you verify your code works?
apps/api/src/tools/sandbox/thread-start.test.ts: new case "refuses an unlinked repository before creating a chat". It asserts the create is never called. It fails on main (create called once) and passes with this change. The existing cases (creates on the default agent, refuses a repository for a project, rejectsthreadId+virtualMcpId) still pass.tsc --noEmit(api),oxlint,knipclean.- Found while testing 4.568.0 end to end against production with an internal organization:
new --repo,exec(exit code, stderr, argv quoting),chat(agent wrote a file,execread it back), and the tool withoutthreadIdall worked. Only the unknown-repository case left an orphan chat. The test chats were deleted afterwards.
How to Test
deco sandbox new --org <slug> --repo <owner>/does-not-exist→ fails and lists the linked repositories.deco tools call COLLECTION_THREADS_LIST --org <slug> -d '{"limit":3}'→ no new empty chat.
Review Checklist
- PR title is clear and descriptive
- Changes are tested and working
- Documentation is updated (if needed)
- No breaking changes
Summary by cubic
Fixes THREAD_SANDBOX_START leaving an empty "New chat" behind when the supplied repository doesn't exist or is ambiguous. The repository, user ID, and default-agent rule are now resolved before the chat is created, so every refusal happens first and nothing is saved. Behavior for valid input is unchanged. A new test asserts the chat create is never called for an unlinked repository.