Skip to content

chore: sync with upstream/main (339179f50) - #66

Merged
Fryuni merged 22 commits into
mainfrom
fryuni/sync-upstream-main-6
Oct 15, 2026
Merged

Fryuni merged 22 commits into
mainfrom
fryuni/sync-upstream-main-6

Conversation

@Fryuni

@Fryuni Fryuni commented Oct 15, 2026

Copy link
Copy Markdown
Owner

Problem

The fork is 21 commits behind upstream/main. This sync has to keep the features recorded in docs/adr while using upstream's implementations wherever it can.

Change

Merged pingdotgg/t3code main at 339179f50a84dc599cce373dbb48f172f182f44e into the fork. None of the 21 commits implement a fork feature, so every ADR stays accepted and none needs an "implemented upstream" note.

git show --remerge-diff 13e4715c2 shows the whole fork-side resolution: the ADR bumps and the one import line.

Verification

  • Typecheck is clean for contracts, shared, client-runtime, source-control-forgejo, server, web and mobile.
  • Ran all 89 test files that differ from upstream: 87 pass. The 15 failures are all in GitManager.test.ts and GitVcsDriverCore.test.ts, and this sync does not change apps/server/src/git or apps/server/src/vcs. They come from the local environment: the five known GitManager own-name tests, nine tag tests that fail because the global git config sets tag.gpgsign (they pass with it overridden), and one rename-preview test that fails the same way on fork main. CI is the source of truth for these.

Model: Claude Opus 5.5; harness: Claude Code in T3 Code.

🤖 Generated with Claude Code

maria-rcks and others added 22 commits October 14, 2026 22:25
…es (pingdotgg#19631)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ingdotgg#19630)

A delegated subagent waiting on an approval or question now shows on its parent thread: Working section, status badge, notifications, snooze, and the composer banner on web and mobile. Takes over pingdotgg#19614.

Co-authored-by: lovelycodemonkey <ghassemimahyad@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
)

Co-authored-by: Victor Vogel <263261067+only21mil@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
… command (pingdotgg#19635)

After "Always allow this session", the Codex adapter answers later command (or file change) approvals in that thread for the rest of the session. A turn in another runtime mode, or the thread unloading, ends it. Takes over pingdotgg#19598.

Co-authored-by: lovelycodemonkey <ghassemimahyad@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…dows again (pingdotgg#19656)

Windows PowerShell started with detached: true exits 0 without running its command. Native Windows PowerShell launches (reveal and browser) now start attached, unref'd, with ignored stdio.

Takes over pingdotgg#10387. Fixes pingdotgg#11780.

Co-authored-by: doubletwisted <118005273+doubletwisted@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ingdotgg#19103)

Co-authored-by: PR Batch Tester <agent@local.test>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ished tool nodes (pingdotgg#19675)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…g#10984)

Co-authored-by: RealDoc06 <73218979+RealDoc06@users.noreply.github.com>
Co-authored-by: Theo Browne <me@t3.gg>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
)

Co-authored-by: t3-code[bot] <269035359+t3-code[bot]@users.noreply.github.com>
…uestion (pingdotgg#18459)

Co-authored-by: maria-rcks <maria@kuuro.net>
Co-authored-by: maria-rcks <maria@kuuro.net>
Merge 21 upstream commits into the fork.

- contracts/settings.test.ts conflicted only on import order; it takes
  upstream's import and keeps the fork's default base branch tests
  (ADR 0009).
- Upstream's delete-branch PR action, settled-worktree cleanup, delegated
  task questions, and composer vertical caret stops merged beside the fork's
  Forgejo, existing-branch, schedule-tool, and dead-key changes without
  adaptation. None of them implements a fork ADR's feature.
- No upstream workflow changes; the release define is intact (ADR 0011).
- ADRs compare against 339179f.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Fryuni

Fryuni commented Oct 15, 2026

Copy link
Copy Markdown
Owner Author

@fryuni-s-proval Please review this upstream sync at 13e4715c2 and give an explicit approve or request-changes recommendation.

This is a maintainer-requested sync, not a feature PR. Its parents are fork main d5ab41dbb and upstream main 339179f50. Almost every file comes straight from upstream. Problems that already exist on either parent are out of scope. Please review how the upstream changes integrate with the fork's ADR features, not upstream's own implementation.

Review units (git show --remerge-diff 13e4715c2 shows the manual resolutions):

  1. Contracts test conflict (ADR 0009). packages/contracts/src/settings.test.ts takes upstream's import { type CommandId, ProjectId } and keeps the fork's "project default thread base branch" tests beside upstream's new worktreeSettledAfterDays tests.
  2. Delete-branch PR action (ADRs 0002–0004). Upstream adds delete-branch and capabilities.deleteBranch. The Forgejo provider declares neither, so PullRequestService refuses the action for Forgejo, the same as GitLab and Azure DevOps. The fork's Forgejo identity and PR-opening changes are untouched.
  3. Auto-merged overlaps. These files changed on both sides and merged without conflict: OrchestratorMcpService.ts and tools.ts (delegated task questions next to the fork's schedule-tool target, ADR 0016), ComposerPromptEditorTiptap.tsx (vertical caret stops next to the dead-key guards, ADR 0018), Sidebar.tsx (waiting icon next to the project-PR menu, ADR 0014), settings.ts/projectSettings.ts (settled-worktree retention next to defaultThreadBaseBranch, ADR 0009), and environment.ts/ServerEnvironment.ts (new settledWorktreeCleanup capability next to existingBranchWorktree and releaseRepository, ADRs 0008 and 0011).
  4. CI (ADR 0011). Upstream did not change .github; only ci.yml and server-linux-release.yml remain, and the release define is intact.
  5. ADR updates in docs/adr/ (comparison SHA only).

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-15T10:21:22.774507Z 13e4715 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@fryuni-s-proval

Copy link
Copy Markdown

@Fryuni

I recommend approving. I found nothing that needs changing in how the upstream changes fit with the fork's ADR features. I can only post comments, not submit a formal GitHub review, so treat this as the recommendation.

I can't run git, so I couldn't run git show --remerge-diff. Instead I read the diff between the merge target and this head for each file you listed and checked the result on head.

1. Contracts test conflict (ADR 0009): OK

  • packages/contracts/src/settings.test.ts:4 uses upstream's import { type CommandId, ProjectId }.
  • Upstream's worktreeSettledAfterDays tests were added: the default, the patch, the custom-rule decode, and the invalid-value it.each.
  • The fork's defaultThreadBaseBranch tests are still there at L200–222, and so are the shared tests in packages/shared/src/projectSettings.test.ts:356–369.

2. Delete-branch action and Forgejo (ADRs 0002–0004): OK. Forgejo can't reach the action anywhere:

  • packages/source-control-forgejo/src/client/definition.ts:112: changeRequestActions is still merge/close/reopen/update-branch.
  • ForgejoPullRequestProvider.ts:38–56: CAPABILITIES doesn't set deleteBranch. permissions() at L179 filters CAPABILITIES.actions, so delete-branch never shows up in the viewer's permissions either.
  • Server: PullRequestService.ts (around L2030) refuses unless capabilities.deleteBranch === true, and does this before the permission lookup.
  • Clients hide the button too: web pullRequestDetail.logic.ts:1360–1362 and mobile pullRequestActions.ts:92–93 both require deleteBranch === true.
  • No fork code has an exhaustive Record<PullRequestAction, …> that the new literal would break; the only one is ACTION_ACCESS_REFUSALS, which gained the key.

3. Files changed on both sides: OK

  • MCP (ADR 0016): The tools.ts change only updates the delegate_task description. OrchestratorMcpService.ts adds runtime-request.updated to TASK_WAKE_EVENTS, adds runtimeRequests to the child record read, and adds hasPendingQuestion. None of this touches the schedule tool's target.
  • Composer (ADR 0018): Up/Down is added to the arrow branch (L1224–1257), and that branch still checks !event.isComposing. The Enter-during-IME guard (L1296) and handleTextInput → surroundComposerSelection (L1389–1391) are unchanged, and composer-selection-surround isn't in the diff. For Up/Down, the styled-edge step runs only at the edges of the document, and the chip-skip runs only for Left/Right.
  • Sidebar (ADR 0014): The changes are limited to the waiting status icon and its timer. The project-PR menu code isn't touched.
  • Settings (ADR 0009): worktreeSettledAfterDays is added to WorktreeCleanupRules with a default of null, to StorageCleanupSettings and to both patch schemas. It's also passed through in resolveWorktreeCleanup. defaultThreadBaseBranch (settings.ts:1024) is untouched.
  • Environment (ADRs 0008/0011): settledWorktreeCleanup sits next to existingBranchWorktree (environment.ts:123, ServerEnvironment.ts:232). releaseRepository is unchanged (environment.ts:240, ServerEnvironment.ts:220).
  • Worktree cleanup (ADR 0012): storageCleanup.ts also changed. The new settled-age rule and the 60s settle-script grace both run after localChangesReason(...), so the fork's keep-when rules for local and ignored files still protect worktrees before the new rule can remove one.

4. CI (ADR 0011): Partly checked. .github/workflows has only ci.yml and server-linux-release.yml, and .github isn't in the diff. I didn't open the workflow files, so I haven't checked the release define myself; since the directory is unchanged, it can't have been touched by this sync.

5. ADRs: OK. The docs/adr/ changes I looked at, for example 0018, only update the "Compared with upstream" SHA to 339179f50.

Not checked: I didn't run tests or typecheck. The GitManager/GitVcsDriverCore failures you put down to your local setup are in directories this PR doesn't change, so CI will settle those. The Codex review on this head was still running when I checked.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 13e4715c28

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

runPullRequestAction: (input) => {
if (input.action === "delete-branch") {
return Effect.gen(function* () {
if (input.stackNumber !== undefined) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Block stacked branch deletion for ordinary action calls

When a merged or closed pull request belongs to a stack, the web and mobile delete controls invoke runAction without stackNumber, so this condition is never true on the user-visible path. The mutation therefore deletes a stacked branch despite explicitly treating stack deletion as unsupported, potentially removing the base branch of remaining stack layers; determine stack membership before mutating, or pass it from the clients and suppress the action.

Useful? React with 👍 / 👎.

@Fryuni Fryuni Oct 15, 2026 •

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of scope for this sync. GitHubPullRequestApi.ts is byte-identical to upstream/main (git diff upstream/main HEAD -- packages/source-control-github/src/server/GitHubPullRequestApi.ts is empty), and this stack-membership behavior comes from upstream's own delete-branch feature (pingdotgg#19257). The fork does not change GitHub PR actions or their clients, so this is upstream behavior rather than an integration problem. Per the maintainer's instructions, problems already present on either parent are not fixed in the sync PR.

);
const getThreadTranscript = Effect.fn("orchestrationV2.threadManagement.getThreadTranscript")(
function* (threadId: ThreadId) {
const { projection } = yield* getThreadSnapshot(threadId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Bound transcript loading before materializing the snapshot

For a long thread, this loads the complete projection—including historical runs, nodes, messages, and turn items—before the subsequent 50 MB transcript check. A dropped oversized thread can therefore force a very large database decode and allocation only to return an error, potentially stalling the environment; read only the transcript rows and stop once the byte budget is exceeded.

AGENTS.md reference: AGENTS.md:L15-L17

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of scope for this sync. ThreadManagementService.ts is byte-identical to upstream/main (git diff upstream/main HEAD -- apps/server/src/orchestration-v2/ThreadManagementService.ts is empty), and getThreadTranscript was added by upstream (pingdotgg#15210). The fork does not touch thread snapshots or transcript loading. Per the maintainer's instructions, problems already present on either parent are not fixed in the sync PR.

@Fryuni

Fryuni commented Oct 15, 2026

Copy link
Copy Markdown
Owner Author

@codex review

This is an upstream sync merge (parents: fork main d5ab41dbb, upstream main 339179f50). Please review only how upstream's changes integrate with the fork's own changes, which are recorded in docs/adr/ and visible with git diff upstream/main HEAD. Code that is byte-identical to upstream/main is upstream's implementation and out of scope here, like the two earlier findings in GitHubPullRequestApi.ts and ThreadManagementService.ts (both answered in their threads).

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: 13e4715c28

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@Fryuni
Fryuni merged commit 81c53a9 into main Oct 15, 2026
9 checks passed
@Fryuni
Fryuni deleted the fryuni/sync-upstream-main-6 branch October 15, 2026 10:23
Comment on lines +1289 to +1293
const { thread } = yield* projectionStore.getThreadRecords(input.threadId, []);
const providerTurn = yield* thread.worktreePath === null
? start(input)
: withWorkspaceLease(path.resolve(thread.worktreePath), start(input));
if (providerTurn !== undefined) yield* providerTurn;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚫️ [PROBLEM] Turn start on idle threads can now wait behind a whole storage-cleanup pass

⚫ [PROBLEM] Turn start now takes the workspace lease (line 1292). Storage cleanup holds that same lease for its entire per-worktree Effect.gen: see apps/server/src/storageCleanup.ts:677, (effect) => withWorkspaceLease(worktreePath, effect). That block includes a lot of slow work:

  • the git.fetchRemoteTrackingBranch network fetch (around storageCleanup.ts:529)
  • gitManager.branchPullRequest(..., { refresh: true }) (around :549)
  • the full recursive measureWorktree walk (:662)
  • two blockedSinceCheck passes

Cleanup only considers idle threads, and an idle thread is exactly where a user sends the next message. During a sweep, that message's turn start can block for several seconds or more, with no feedback in the UI. Rollback (CheckpointRollbackService.ts:382) waits on the same lease and gets the same delay. Before this PR, only terminal open contended for the lease.

Suggested fix: in storageCleanup.ts, take the lease only around the final critical section. That is the last blockedSinceCheck, the branch/HEAD/local-changes rechecks, git clean, and git worktree remove. Leave the fetch, the PR lookup, and the size walk outside the lease. The recheck already catches anything that started in the meantime, so the race stays closed, and turn start only waits for the short removal window.

Comment on lines +151 to +163
// A blocking delegate_task wait delivers the question itself.
if (
task.completionWake === "settled_only" &&
event.payload.responseCapability.type === "live" &&
parent.runs.some(
(run) =>
run.id === task.runId &&
(run.status === "preparing" || run.status === "starting" || run.status === "running"),
)
) {
return;
}
yield* wakeParent(task, request);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚫️ [PROBLEM] Skip check reads mutable completionWake, so the parent can be told about the same question twice

⚫ [PROBLEM] This guard decides whether the blocking delegate_task wait will deliver the question. It reads task.completionWake === "settled_only" from the projection at the moment the reactor runs (line 133). The problem is that the same runtime-request.updated event also wakes waitForTask in OrchestratorMcpService.ts (lines 1544/1560, hasPendingQuestion). After that wait returns, delegateTask immediately dispatches delegated_task.wake-policy with completionWake: "always" (OrchestratorMcpService.ts:2154-2165).

If that upgrade commits before this reactor reads the parent records, the check fails. wakeParent then queues a queue_after_active message about a question the parent already got in the tool result. Here is how that plays out: the parent passes the question to the user and ends its turn, and then the queued notification starts an extra parent turn about the same question. Whether this happens depends on timing. The reactor tests call handle directly, so they never exercise this ordering.

Suggested fix: base the skip on state that does not change when the wait ends. Some options:

  • Have the wait path record that it delivered this request id, for example in the wake-policy command or a separate event.
  • Have the wait path dispatch the same deterministic message:delegated-task-question:<key> command id, so the reactor's dispatch becomes an idempotent no-op.
  • Make the skip depend on whether the task was launched in wait mode and the launching parent run is still active, not on completionWake.

@fryuni-s-proval

Copy link
Copy Markdown

This is a big, carefully built change. The destructive paths (deleting a branch, removing a worktree) have more layers of guards than usual, and the tests cover the tricky orderings well. I'm raising two problems below, and both are about timing.

Overview

Summary
This PR covers several areas:

  • Source-branch deletion for merged/closed PRs. Adds the contract, the GitHub provider, the server service, and the web and mobile UI.
  • Settled-worktree retention rule. Storage cleanup now coordinates with turn start and rollback through the workspace lease.
  • Delegated-task question reactor. Wakes the parent agent when a child asks a question.
  • Subagent requests on ancestor threads. Pending subagent requests now show on ancestor threads and in notifications.
  • Smaller pieces: session-scoped approvals in Codex and an explicit Muse permission profile, clipboard capture in an isolated world for the preview browser, thread transcript import into the composer, paged Antigravity SQLite reads, a Windows PowerShell launch fix, and composer caret fixes.

The main risks are in how the new workspace lease and the question reactor interact with work that is already running.

Good points

  • 🟢 The GitHub branch delete (packages/source-control-github/src/server/GitHubPullRequestApi.ts) refuses open PRs, the base branch, the default branch, and a head that has moved. The final updateRefs call sends beforeOid, so a push that lands mid-request can't be deleted. A table-driven test covers each refusal.
  • 🟢 In apps/server/src/pullRequest/PullRequestService.ts, the permission check and the delete both run inside withVerifiedCredential. A test switches tokens mid-request and confirms the authorized account is the one that does the delete.
  • 🟢 In the preview browser, clipboard capture now lives in a CDP isolated world and only fires on trusted copy keys (apps/server/src/preview/ServerBrowser.ts). Page scripts can no longer push text to the viewer's clipboard.
  • 🟢 ProviderTurnStartService.start now returns the startRootRun effect, so the lease covers only startup and not the provider turn. Cleanup's recheck also compares settledAt, so a thread whose settle state changes while the worktree is measured won't lose its checkout (apps/server/src/storageCleanup.ts:620).

Main Issues

  • ⚫️ Turn start can wait on a full cleanup pass. apps/server/src/orchestration-v2/ProviderTurnStartService.ts:1292 now takes the workspace lease. Storage cleanup holds that same lease (apps/server/src/storageCleanup.ts:677) across a remote fetch, a refreshed PR lookup, and the recursive measureWorktree walk. A message sent to an idle thread during a sweep can therefore stall for a while.
  • ⚫️ The parent can be told about the same question twice. apps/server/src/orchestration-v2/DelegatedTaskQuestionReactor.ts:151 decides whether to skip by reading completionWake, which can change. The wait path can upgrade it to "always" (apps/server/src/mcp/OrchestratorMcpService.ts:2154) before the reactor reads it. When that happens, the parent gets a second, queued notification about a question the tool result already gave it.

Additional Notes

  • packages/contracts/src/pullRequest.ts line 422: capabilities.deleteBranch repeats what "delete-branch" in capabilities.actions already says. If a future host sets one but not the other, the action is silently hidden.
  • apps/web/src/components/settings/StorageSettings.tsx line 276: the enabled predicate is a copy of worktreeCleanupEnabled in apps/server/src/storageCleanup.ts around lines 74–79. Moving one shared helper into packages/shared/src/projectSettings.ts would keep the button and the server in agreement.
  • apps/web/src/components/ChatView.tsx line 7490: the child-input banner takes its label and target from childThreadInputs[0], so when a question and an approval are both pending it can say "Open question" while the sidebar says Approval. Sorting approvals first in childThreadInputsAtomFamily would make them match. Mobile's ThreadDetailScreen.tsx around line 528 has the same issue.
  • apps/web/src/components/Sidebar.logic.ts line 985: the new pendingSubagentRequest branches in resolveSidebarThreadStatus, resolveThreadListV2Status, and threadRaisedHandWhileSnoozed have no direct unit tests.
  • apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts line 1899: the JSDoc for sessionAllowance has drifted above endSessionApprovalsOnModeChange, so it no longer documents the function it describes.
  • apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts line 1329: 65 * 60 is hard-coded, as is the Claude equivalent. Neither is derived from MAX_WAIT_TIMEOUT_MS in OrchestratorMcpService.ts, so raising the server's wait cap would quietly cut long waits short again.
  • apps/web/src/components/ComposerPromptEditorTiptap.navigation.test.tsx line 13: the fixture includes a contributor's absolute local path (/Users/...). A short synthetic string with the same quote, bold, code, and link structure would work just as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants