Skip to content

feat(fork): catch up to upstream's V2 orchestrator (185 commits, 69 conflicts) #36

Description

@nohat

Problem

fork/prod last synced upstream at 54084ae1e6 (2026-10-01). Upstream has since landed 185 commits, including de34391427 "new orchestrator" (V2, 1907 files). A trial merge of upstream/main into fork/prod (scratch worktree, 2026-10-05, nothing landed) conflicts in 69 files, and many more fork files auto-merge but now sit on code that no longer exists. Upstream moves about 45 commits a day, so the cost of waiting rises daily. This is the first real sync under #6, and it cannot be automated.

What the trial merge found

  • Upstream deleted apps/server/src/orchestration/ and packages/contracts/src/orchestration.ts; V2 lives in orchestration-v2/ and orchestrationV2.ts. Git's rename detection dragged the fork's new drain/watchdog files into orchestration-v2/, where their imports point at deleted modules.
  • Wire protocol is now ORCHESTRATION_PROTOCOL_VERSION 2; /ws answers mismatches with HTTP 426. Server, web, desktop, and iPad must ship in lockstep.
  • V2 snapshots state.sqlite (about 1.08 GB live) into statev2.sqlite on first launch. The original stays for v1; later launches never refresh the copy.

Fork features: verdicts (read from the trial merge, not yet run)

Feature Verdict
Drain mode (c45ea87d87) Port. Choke point is orchestration-v2/ThreadMessageIntake.ts; running count from orchestration_v2_projection_runs; drain HTTP endpoints move out of deleted orchestration/http.ts; CLI into binCli.ts. The deploy depends on it.
Stall watchdog, stalledSince (911e4b6fe9, 442110291b) Port, lower priority. Upstream has no silent-provider watchdog. Only #28 consumes stalledSince.
Claude silent-CLI fix (#1) Mostly obsolete. ClaudeAdapterV2 reopens the query on model/policy change. One unbounded setPermissionMode remains.
OpenCode wave 0/1 + child-agent surface Obsolete. OpenCodeAdapterV2 has native child threads.
OpenCode scoped agents (f602765a91) Port (OpenCodeDriver.ts, v1 and v2 workspace paths).
#18 #19 #20 OpenCode lock/serve Not resolved upstream. Re-diagnose on V2 (OpenCodeAdapterV2.ts:959 still connects per session).
Provider-agnostic subagents (#21) Dispatch obsolete (delegate_task, t3_thread_launch). Pricing in capabilities output and the model-selection skill are still ours.
Papercuts Textual plus one port. Papercuts.ts reads projection_thread_sessions/_activities, which are frozen copies in statev2.sqlite and fail silently stale. Rewrite to V2 tables. Keep the papercutCreate scope entry.
Direct APNs (#15) Port. Not on fork/prod. Its migration id 055 collides with upstream's 055_OrchestrationV2; use a file store or separate ledger. Relay hook must be redone against V2 events.
Send-never-settles (#2) Port onto launchThread/message.dispatch (no expiry upstream).
Send-blocked reason Mechanical conflict.
Reconnect feedback (#7) Port: WorkspaceEnvironment became EnvironmentConnectionSummary in client-runtime.
Thread sync stall bound, reload thread Port/rewrite (V1 loader replaced; V2 sync is afterSequence). #3 may be mitigated by paged snapshots; needs a repro on V2.
Composer drafts (#8) Web clean, mobile mechanical.
Model picker, pricing Web clean; mobile port; pricing: mechanical (ModelListRow, providerIconUtils, ws.ts four small deltas).
iPad feed jump (#17) Upstream shipped its own keyboard-controller patch (pingdotgg#14808). Take upstream's whole, re-run the replay, re-add the fork's hunks only if the jump reproduces. The fork's guard test forbids what upstream's patch does, so it must change with the decision.
#23 PostHog default Unchanged upstream; still on by default.

Deploy and data effects (my live data)

  • The cutover creates statev2.sqlite beside state.sqlite; nothing is written back to the original. Rollback to a v1 release reopens state.sqlite and loses threads and messages created after cutover. Migrated history is messages only (no checkpoints, tool calls, approvals, plans).
  • fork-deploy-lib.ts countRunningSessions reads projection_thread_sessions in state.sqlite. After cutover that table is frozen, so the drain gate holds forever or reads zero. Fix before the first V2 deploy.
  • restartAndProbe allows 90 s; the 1.08 GB copy is untimed, so a false "unhealthy" rollback is possible.
  • fe417dff4c (t3 refuses to start when state names a live pid for the same base dir) must be checked against the swap ordering.
  • Fork migrations: none on fork/prod; papercuts are JSON files and carry over.

Plan

  1. Pre-flight (read-only, on a VACUUM INTO copy of live data): time the statev2 snapshot; record the result here.
  2. Make fork-deploy V2-aware: running count from statev2.sqlite when present (or from the drain-status endpoint), longer first-start probe, and a recorded rollback note that post-cutover data does not return to v1.
  3. Land the in-flight versioning work first (uncommitted in the primary checkout; a merge needs a clean tree, and it touches files upstream also changed).
  4. Merge in a scratch worktree off fork/prod, git-imerge style if it fights back, with rerere on. Take upstream for pnpm-lock.yaml and regenerate; keep fork deltas small per file.
  5. Port order: drain, papercut tables, send-never-settles and reconnect feedback, cache bound and resync, scoped agents, pricing/picker, watchdog last. Drop the obsolete rows. Each port keeps or rewrites its guard test.
  6. Gate: the patches.tsv guards and delta-check from feat(fork): upstream sync job, fork-delta check, and agent guards #6 are the acceptance test for this merge. Targeted typecheck/tests for touched packages only.
  7. Ship as fork 1.0.0: by the versioning bump rules, a data migration and wire break is a major. Server, web, desktop, and the iPad build go together. Then re-diagnose bug(mobile): iPad thread open hangs on 'Syncing messages...' until force-quit #3, fix(opencode): retry server startup on transient SQLite 'database is locked' #18-20 on V2.

Not in scope

Opening upstream PRs; resolving #14 (file chips) or the notification/discovery proposals, which now have a V2 baseline to re-map onto (environment-discovery.md D0 gets client-runtime/src/connection/routes.ts).

Related: #6, #5.

Activity

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

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions