Skip to content

Modular fork: move remaining fork code out of upstream files #24

Closed
5 of 5 issues completed
Closed

Description

@tannerpolley

Goal

Make the fork's customizations modular, so each daily upstream sync has as few conflicts as possible. Fork code lives in fork-owned files and connects to upstream files through small hook points. Upstream code changes only to fix a bug that blocks a fork feature.

The owner approved this as a follow-up to the upstream sync (#11) on 2026-10-12: "Yes, as a follow-up".

Already modular (2026-10-12)

  • Fork migrations have their own ledger (ForkMigrations.ts, table t3_fork_migrations).
  • Fork RPCs are a separate group (forkWsRpcs) served from ForkWsRpc.ts.
  • Issue recovery decisions live in IssueWorkRecovery.ts. Delegated request routing lives in DelegatedRequestRouting.ts, DelegatedRequestWake.ts and packages/shared/src/delegatedRequestVisibility.ts.

To do

  1. Inventory. List every place where fork code is still woven into upstream files: Orchestrator.ts, EventSink.ts, ProjectionStore.ts, ws.ts, ChatView.tsx, Sidebar*.tsx, the provider adapters, contracts, and so on. Record the file, the fork feature and the line count. Use git diff upstream/main...main limited to files upstream owns.
  2. Rank by how often each spot conflicted in the 2026-10-12 merge (132 files) and by size.
  3. Move the largest pieces behind hook points, one feature per change, each with its own review. No behavior changes.
  4. Check each step against the daily sync: conflicts should go down.

Mobile is out of scope.

Activity

  1. tannerpolley commented on Oct 13, 2026

    @tannerpolley
    OwnerAuthor

    Plan: maintain the fork as a patch stack (owner asked for a plan, 2026-10-13). For approval before any change.

    Today: main is upstream plus about 123 fork commits, synced by merging upstream into it. Fork changes are spread through history and through upstream's big files, so each sync re-fights the same conflicts. git rerere is now on, which helps with repeats.

    Target: the fork is upstream/main plus a short ordered list of feature commits, about 15–25, one per fork feature:

    • issue work and repository orchestration;
    • Issues page;
    • subagent question routing;
    • Don't ask mode;
    • model roles and usage ranking;
    • local servers;
    • sidebar background rows;
    • fork migrations ledger;
    • and the rest.

    Each daily sync rebases that list onto the new upstream instead of merging.

    Why it's cleaner:

    • A conflict names the one feature it touches.
    • When upstream ships something equivalent, that commit is dropped.
    • git range-diff old..new shows exactly how each feature changed between syncs, which suits review.

    Steps:

    1. Finish the modular pass in this issue first: fork code in fork-owned files with small hooks. Without that, every commit conflicts constantly.
    2. Build the stack. Starting from upstream/main, re-create each fork feature as one commit (squash its history), in dependency order (migrations/contracts → server → client → UI).
    3. Check the stack. The result must match current main exactly (empty git diff), and the targeted tests pass.
    4. Switch: main becomes the stack, force-pushed once with owner approval. Archive the old history as archive/main-merge-history-<date>.
    5. Daily sync becomes: fetch, git rebase upstream/main with rerere, fix any conflicting commit, range-diff review, then force-push main (owner-approved standing rule needed).

    Costs:

    • Rewritten history on every sync. Worktrees branched from old main must rebase. Each sync needs a force-push, which needs a standing approval from the owner.

    Decision points for the owner when step 1 is done:

    • approve steps 2–4;
    • standing approval for daily force-pushes of main.
  2. tannerpolley commented on Oct 13, 2026

    @tannerpolley
    OwnerAuthor

    Owner decision (2026-10-13): run the modular pass after the feature batches in #1's plan. New features are built modular from the start.

  3. tannerpolley commented on Oct 14, 2026

    @tannerpolley
    OwnerAuthor

    Inventory and plan (2026-10-14). Read-only research on main cc5a99dcd8 against upstream 570542662a, merge base a01c48f862.

    • 392 upstream-owned files differ: +37,778 / −5,761 lines. Tests and fixtures are 21,251 of those lines.
    • Replaying the last 3 real upstream syncs gave 8, 129 and 4 conflicting paths, 133 distinct paths in all.
    • ws.ts looks large, but ignoring whitespace it's +72/−19: the RPC split is already modular. contracts/rpc.ts is already modular too.

    Biggest woven spots (conflicts × size; estimated lines that would leave the upstream file):

    1. Orchestrator.ts (+1,948/−299): issue admission, repository lifecycle, app-owned questions, completion delivery, automatic switching. Move to IssueWorkCommands, RepositoryWorkCommands, AppOwnedUserInputCommands, ForkDelegatedCompletion and AutomaticProviderSwitchPolicy. Estimated 1,050–1,400 lines.
    2. ThreadRelationshipsControl.tsx: agent rows, history, columns. Move to useForkAgentRows and ForkAgentRows. 500–600.
    3. ProjectionStore.ts: issue projection, shell enrichment, feature queries. Move to IssueWorkProjection, ForkShellQueries and ForkProjectionQueries. 500–650.
    4. OrchestratorMcpService.ts: managed delegation, worktrees, task status, send policy. 330–430.
    5. Next, in order: Sidebar.tsx, ClaudeAdapterV2.ts, CodexAdapterV2.ts, contracts/orchestrationV2.ts, ClaudeSkills.ts, ChatMarkdown.tsx, contracts/settings.ts, ProviderSessionManager.ts, then EffectWorker.ts and PortScanner.ts.

    Test suites: fork tests sit inside upstream test files: thread launch about 4,900 lines, delegated completion about 1,200, Codex adapter about 1,100. They can move into fork-owned test files with no runtime risk.

    Batch plan, one feature per batch, each reviewed, no behavior changes:

    1. model roles and ranking
    2. managed issue admission
    3. repository ownership and handoff
    4. issue upkeep effects
    5. routed questions
    6. Don't ask mode
    7. provider switch
    8. background work
    9. provider parity
    10. sidebar sections
    11. sidebar columns
    12. plugin skills
    13. local servers
    14. inline shell runs
    15. Issues page
    16. math
    17. inline copy
    18. host media
    19. idle session release

    Keep inline as upstream-style fixes: default-ref fallback without origin/HEAD, native protocol corrections, clipboard and line-break fixes, worker-lane isolation.

    Not part of this plan: the patch-stack idea in the earlier comment. It rewrites history and needs separate approval.

  4. tannerpolley commented on Oct 14, 2026

    @tannerpolley
    OwnerAuthor

    Decision (2026-10-14, recommended option; the owner was away in Don't ask mode): start small and measure.

    1. Batch A: move the fork's test cases out of upstream-owned test files into fork-owned *.fork.test.ts files, with no product code changes. In progress on branch t3/24-fork-test-suites.
    2. Batch B: extract issue work from Orchestrator.ts.
    3. Then: compare the conflict count at the next daily upstream sync before doing more batches.
  5. tannerpolley commented on Oct 14, 2026

    @tannerpolley
    OwnerAuthor

    Batch A merged: fb7da58, 6 commits, tests only. Fork test cases moved out of six upstream-owned test files into *.fork.test.ts files, with shared fixtures in .testHarness.ts.

    File Fork diff vs upstream, before → after
    ThreadLaunchService.test.ts +5,080/−387 → +14/−465
    DelegatedCompletionDelivery.test.ts +1,252/−67 → +13/−339
    CodexAdapterV2.test.ts +1,177/−48 → +77/−751
    ClaudeAdapterV2.test.ts +854/−73 → +80/−488
    PortScanner.test.ts +458/−2 → +18/−19
    EffectWorker.test.ts +367/−34 → +61/−135

    Total: 9,799 → 2,460 changed lines, a 75% cut. The 668 tests are the same, with the same names, and all pass.

    Trade-off: shared fixtures had to leave the upstream files, because importing from a .test.ts file would re-register its tests. The remaining diff is mostly those deletions. If upstream edits a moved helper, the conflict now lands in the harness file.

    Measurement: a trial merge of today's upstream (614b432) gave the same result before and after: 18 conflicted paths and 33 conflict blocks. These upstream commits touched neither the moved tests nor the moved helpers. The real test is the next daily sync.

    Next: batch B, extracting issue work from Orchestrator.ts.

  6. 23 remaining items

  7. tannerpolley commented on Oct 29, 2026

    @tannerpolley
    OwnerAuthor

    Sync measurement (2026-10-29). main at ffa7e30 against nightly tag v0.1.5-nightly.20261029.3877 (6d450a4): 52 new upstream commits, giving 12 conflicted files and 15 <<<<<<< blocks. Measured with git merge-tree --write-tree --name-only --no-messages.

    Sync Upstream commits Conflicted files Blocks
    2026-10-27 132 33 68
    2026-10-28 159 80 209
    2026-10-29 (nightly tag) 52 12 15

    Conflicted files: apps/desktop/src/updates/DesktopUpdates.ts, apps/server/src/mcp/toolkits/project/tools.ts, apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts, apps/server/src/scheduledTasks/ScheduledTaskService.ts, apps/web/src/components/ChatMarkdown.tsx, apps/web/src/components/ChatView.tsx, apps/web/src/components/chat/MessagesTimeline.logic.ts, apps/web/src/components/chat/ThreadDetailsPanel.tsx, apps/web/src/components/settings/SettingsPanels.tsx, packages/contracts/src/settings.ts, packages/provider-core/src/server/managedProvider.ts and its test.

  8. tannerpolley commented on Oct 30, 2026

    @tannerpolley
    OwnerAuthor

    T3 Code closeout: done

    Issue: #24 Modular fork: move remaining fork code out of upstream files
    Thread: thread:delegated-task:command%3Amcp%3Aa45c4156-6756-45dc-bd27-1ea406cde16f%3Adelegate-task%3Aissue-24-orchestrate-20261029
    Model: gpt-6.1-sol
    Branch: issue-24-modular-fork-move-remaining-fork-code
    Completed: 2026-10-30T05:05:50.627Z

    Understood. I’ll continue local implementation and Checker review, with delivery held while authentication is unavailable. No pushes, PRs, main fast-forwards, or issue writes.

    After pass 2’s correction and review pass, I’ll check gh auth status once. If authentication is still invalid, I’ll report “ready to deliver” with the branch and head SHA. If valid, I’ll resume normal delivery.

    The formatting correction is still assigned to the same implementor and will resume this thread automatically. I’ll reference #256 for the existing unused-export hook failure; --no-verify is authorized when that is the only hook failure.

  9. tannerpolley commented on Oct 30, 2026

    @tannerpolley
    OwnerAuthor

    T3 Code closeout: waiting_on_sub_issues

    Issue: #24 Modular fork: move remaining fork code out of upstream files
    Thread: thread:delegated-task:command%3Amcp%3Aa45c4156-6756-45dc-bd27-1ea406cde16f%3Adelegate-task%3Aissue-24-orchestrate-20261029
    Model: gpt-6.1-sol
    Branch: issue-24-modular-fork-move-remaining-fork-code
    Completed: 2026-10-30T05:36:50.602Z

    Pass 2 now includes current origin/main and #260 at head 7d9c2365a0b19075d5279091742c0504117e3bab. Authentication is valid.

    The 68 launch/handoff tests, formatting, lint, generated GraphQL check, and affected typechecks pass. The remaining changed-file tests are running; the unused-export scan still reports the 74 findings tracked by #256.

    The Checker is reviewing the formatting and integration delta:

    t3-thread://v2/df61a5ad-76a1-4901-b919-31ae81c8e67d/thread:delegated-task:command%3Amcp%3Ad3506335-01b7-4a2c-9b60-c53578fcdb05%3Adelegate-task%3Aissue24-pass2-251-check-987ed4c0

    I’m waiting on those checks and review, which resume this thread automatically. The refreshed comparison against nightly v0.1.6-nightly.20261030.3904 is 17 files / 23 blocks before and after. Publication remains pending; passes 3–5 are unstarted.

  10. tannerpolley commented on Oct 30, 2026

    @tannerpolley
    OwnerAuthor

    Sync measurement (2026-10-30). main at b539f4b against nightly tag v0.1.6-nightly.20261030.3917 (97e35bcf23): 126 new upstream commits, giving 26 conflicted files and 37 <<<<<<< blocks. Measured with git merge-tree --write-tree --name-only --no-messages.

    Sync Upstream commits Conflicted files Blocks
    2026-10-27 132 33 68
    2026-10-28 159 80 209
    2026-10-29 (nightly tag) 52 12 15
    2026-10-30 (nightly tag) 126 26 37

    Conflicted files:

    • Server orchestration: Orchestrator.ts, ProjectionStore.ts, ProviderSessionManager.ts, ShellStream.ts, ThreadLaunchService.ts, ThreadManagementService.ts.
    • Other server files: RpcAuthorization.ts and its test, Sqlite.ts, ClaudeSkills.ts, ProviderRegistry.ts, agentContextBudget.json, serverRuntimeStartup.ts, serverSettings.ts, storageCleanup.ts, terminal/Manager.ts, GitVcsDriverCore.ts, ws.ts.
    • Web: MessagesTimeline.logic.test.ts, ThreadActivityBanners.tsx, ThreadLineageWorkflowRow.tsx, ThreadRelationshipsControl.tsx, threadActionMenu.logic.ts, useThreadActionMenu.ts.
    • Packages: clientRpcPermissions.ts, nodeSqliteClient.ts.

    Several conflicts are in files the fork changed in the last day: Sqlite.ts, nodeSqliteClient.ts and agentContextBudget.json (#240, #260), and storageCleanup.ts (#238). Modular pass 2, repository orchestration, is still in delivery.

  11. tannerpolley commented on Oct 31, 2026

    @tannerpolley
    OwnerAuthor

    Sync 2026-10-31 (#265, v0.1.7-nightly.20261031.3991, 401 upstream commits including the v0.1.6 release): 61 conflicted files, 99 conflict blocks against main da7da71. Up from 17/23 on 2026-10-30, mostly from the size of the upstream batch (side chats, project pinning, the model/effort picker, sidebar and right-panel changes).

  12. tannerpolley commented on Nov 1, 2026

    @tannerpolley
    OwnerAuthor

    Sync 2026-11-01 (v0.1.7-nightly.20261101.4035, 175 upstream commits): 22 conflicted files, 27 conflict blocks against main ee4c4c8. Down from 61/99 on 2026-10-31 (401 commits) and close to the 17/23 of 2026-10-30.

  13. tannerpolley commented on Nov 2, 2026

    @tannerpolley
    OwnerAuthor

    Sync 2026-11-02 (v0.1.7-nightly.20261102.4080, 176 upstream commits): 31 conflicted files, 54 conflict blocks against main 912112c. Up from 22/27 on 2026-11-01 (175 commits), below 61/99 on 2026-10-31. Largest: Orchestrator.ts, ThreadNotificationCoordinator.tsx and DesktopUpdates.ts with 5 blocks each, then GitVcsDriverCore.ts, ClaudeAdapterV2.ts and FoundationPersistence.test.ts with 3 each. Some of the Claude conflicts come from #276's cherry-picks of upstream pingdotgg#28410 and pingdotgg#29169, which this nightly also contains.

  14. tannerpolley commented on Nov 2, 2026

    @tannerpolley
    OwnerAuthor

    T3 Code closeout: done

    Issue: #24 Modular fork: move remaining fork code out of upstream files
    Thread: thread:delegated-task:command%3Amcp%3A1178ad5e-4ceb-4452-8960-16ff08db431e%3Adelegate-task%3Aissue-24-owner-20261102
    Model: claude-opus-5-5
    Branch: issue-24-modular-fork-move-remaining-fork-code
    Completed: 2026-11-02T19:11:10.692Z

    Both passes now have reviewed pull requests, open and mergeable. Neither pass reduces merge conflicts against today's nightly. Both move fork code out of upstream files. GitHub shows no CI results on either head.

    Pass 4 (#253, worktree placement and cleanup) Pass 5 (#254, the Issues pane)
    Pull request #283 #285
    Head 9ac293820fc5ddc4acca53d103a01b4556324f04 d4f26a54ef13005e320cda649574cc3d09cc4d57
    Base main at 912112ce1c main at 912112ce1c
    Conflicts before → after 31 files, 54 blocks, 1,298 → 1,290 lines 31 files, 54 blocks, 1,136 → 1,136 lines
    Fork code out of upstream files 63 lines in GitVcsDriverCore.ts; 28 in worktreesDirectory.ts; git.ts and its test now match upstream 498 lines, mostly from rpc.ts
    Checker (GPT-6.1 Sol, xhigh) Changes needed; all three findings fixed Approved, no findings

    Conflicts are measured against nightly v0.1.7-nightly.20261102.4080. Pass 4's line count includes the conflict-marker lines and pass 5's doesn't, so only the before/after within each pass compares.

    Pass 4:

    • Narrowed design: the 2026-10-30 commits had moved about 970 lines of upstream's own cleanup engine into a fork file. That broke the "upstream code stays in upstream files" rule and grew the conflict in that file from 240 to 883 lines. So I had the worker narrow it: storageCleanup.ts is untouched and only fork code moved.
    • Checker findings, all fixed:
      1. An upstream location check had moved into a fork file. It is back in GitVcsDriverCore.ts.
      2. The branch was behind main. It was rebased and force-pushed with a lease, which I authorized for that rebase only.
      3. The pull request description understated how much the moved code was restructured. It now says so.
    • Re-review: I checked the fixes myself rather than running a second Checker review.
    • vp run check:changed: not rerun after the fix round. Tests beside the changed files and the server and shared typechecks passed.

    Pass 5: on today's nightly the Issues pane touches only two conflicts, a one-line selector and one import, and no hook can remove either. The 117 blocks this feature was charged with came from earlier syncs.

    Checks: in both passes, tests beside the changed files and the affected typechecks passed. vp run check:changed failed only on known problems, so both commits use --no-verify:

    Left open on #24:

  15. tannerpolley commented on Nov 2, 2026

    @tannerpolley
    OwnerAuthor

    Closing: all five modular passes have landed (#250–#254, via #257, #261, #262, #283 and #285). On today's nightly, more moves no longer cut sync conflicts. What remains is fork code woven into upstream's own lists and state, where a hook would be as big as the code it moves. Each sync still posts its conflict numbers; a new issue can pick up any hotspot that recurs. The unused-export cleanup continues in #256.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementRequested improvement or new capability.

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions