Skip to content

Latest commit

 

History

History
569 lines (450 loc) · 138 KB

File metadata and controls

569 lines (450 loc) · 138 KB

Patch Ledger

Tracks every place T3 Trade has diverged from the pinned upstream baseline (docs/upstream/BASELINE.md), so future syncs know which upstream changes are expected to conflict and why. Each entry should stay small enough to resolve independently during a sync.

Statuses: applied (change is in main), deferred (identified, not yet applied — listed so a later phase doesn't have to rediscover it).

PROMPT-00 · Fork and integration baseline

Applied

Seam File(s) Change
Desktop app identity scripts/build-desktop-artifact.ts, apps/desktop/scripts/electron-launcher.mjs, apps/desktop/src/app/DesktopEnvironment.ts DESKTOP_APP_ID / bundle & AppUserModelIDs: com.t3tools.t3code(.dev)com.t3trades.app(.dev)
Desktop product name apps/desktop/package.json, scripts/build-desktop-artifact.ts, apps/desktop/scripts/electron-launcher.mjs, and all runtime strings under apps/desktop/src/** Display name "T3 Code" (and its (Alpha)/(Dev)/(Nightly) variants) → "T3 Trade"
Desktop artifact naming scripts/build-desktop-artifact.ts artifactName pattern T3-Code-${version}-${arch}.${ext}T3-Trades-${version}-${arch}.${ext}
Release/CLI copy scripts/resolve-nightly-release.ts, scripts/notify-discord-release.ts, scripts/build-desktop-artifact.ts (CLI description) User-facing release name/announcement copy rebranded to T3 Trade
Doc/help copy packages/shared/src/devHome.ts, packages/shared/src/relayClient.ts, scripts/dev-runner.ts Comments/CLI help text referencing the installed app rebranded
Update/release endpoint independence scripts/build-desktop-artifact.ts (resolveGitHubPublishConfig) Already parametrized via T3CODE_DESKTOP_UPDATE_REPOSITORY / CI GITHUB_REPOSITORY with no hardcoded upstream owner — verified, no upstream-owned release/update endpoint is reachable from a fork build. No code change required; confirmed by grep (see Tests in PROMPT-00).
Build/version metadata packages/shared/src/buildMetadata.ts (new), scripts/build-metadata.ts, packages/contracts/src/environment.ts (ExecutionEnvironmentDescriptor.fork/t3UpstreamCommit), apps/server/src/environment/ServerEnvironment.ts, apps/web/src/branding.ts Server's ExecutionEnvironmentDescriptor and the web client's branding.ts both now emit fork: "T3 Trade" and the pinned t3UpstreamCommit SHA. scripts/build-metadata.ts is registered as npm run build:metadata and its own baseline-parsing regex (which never actually matched BASELINE.md's padded table columns) is fixed; buildMetadata.test.ts cross-checks the constant against BASELINE.md on every run.
Web/mobile/server user-visible copy apps/web/src/branding.ts, apps/web/src/versionSkew.ts, apps/web/src/connection/platform.ts, apps/web/src/components/desktopUpdate.logic.ts, apps/web/src/components/settings/providerStatus.ts, apps/web/src/cloud/linkEnvironment.ts, apps/mobile/app.config.ts (appName, permission strings), apps/server/src/vcs/GitVcsDriver.ts (git author/committer name), apps/server/src/cloud/bootService.ts (systemd unit), apps/server/src/cloud/cliAuthHtml.ts (OAuth page titles), apps/server/src/cli/*.ts, apps/server/src/bin.ts, apps/server/src/serverRuntimeStartup.ts, apps/server/src/startupAccess.ts, apps/server/src/cloud/selfUpdate.ts Remaining "T3 Code" display copy in surfaces PROMPT-00 hadn't touched (web fallback branding, version-skew/update copy, mobile app name and OS permission strings, git commits made on the user's behalf, systemd unit description, CLI/OAuth copy) rebranded to "T3 Trade". Identifiers (below) were left alone.

Deferred (identified, not yet applied)

Internal, non-user-facing identifiers

These still read t3code. Renaming them touches OS-level registration (protocol handlers, window manager class), on-disk state locations, and lint tooling wiring — all higher blast-radius than PROMPT-00's "additive branding" scope, and are left for a dedicated branding phase once trading code exists and can exercise them under test:

Seam File(s) Note
Custom URL protocol scheme apps/desktop/src/electron/ElectronProtocol.ts (DESKTOP_PRODUCTION_SCHEME/DESKTOP_DEVELOPMENT_SCHEME = t3code/t3code-dev), scripts/build-desktop-artifact.ts (mac protocols), apps/desktop/scripts/electron-launcher.mjs OS-registered protocol handler; renaming requires a migration path for existing installs
Linux executable name / WM class scripts/build-desktop-artifact.ts (executableName, StartupWMClass), apps/desktop/src/app/DesktopEnvironment.ts (linuxDesktopEntryName, linuxWmClass) Coupled to the protocol scheme change above
User data directory names apps/desktop/src/app/DesktopEnvironment.ts (userDataDirName, legacyUserDataDirName) Changing breaks continuity with any existing on-disk state; needs an explicit migration, not a rename
Git worktree branch prefix packages/shared/src/git.ts (WORKTREE_BRANCH_PREFIX = "t3code") Referenced by dev tooling across the monorepo; rename requires an audit of all call sites
oxlint plugin namespace oxlint-plugin-t3code/*, rule references like t3code/no-global-process-runtime Renaming the package/namespace is a lint-config-wide change, independent of product branding
WSL prebuild marker filename apps/desktop/src/wsl/DesktopWslEnvironment.ts (t3code-wsl-node-pty.json) Internal build artifact marker, not user-visible
Mobile showcase demo data scripts/mobile-showcase.ts, scripts/mobile-showcase-environment.ts Seeds a simulated "T3 Code" project as example content for App Store screenshot generation; not this fork's own identity

User-visible, but deliberately not yet applied

Unlike the identifiers above, these ARE user-visible. They're deferred because renaming them means touching infra identity (bundle IDs, deep-link schemes, push payloads, auth domains) rather than swapping a display string, and that has to be a deliberate migration, not a drive-by rename:

Seam File(s) Note
Mobile bundle IDs / scheme / auth domain apps/mobile/app.config.ts (iosBundleIdentifier/androidPackage = com.t3tools.t3code*, scheme = t3code*, relyingParty = clerk.t3.codes) Referenced by ~15 files across infra/relay, packages/client-runtime, and test fixtures (APNs device registration, passkey relying party); a rename needs its own audit, like the desktop protocol scheme above
Relay / push-notification copy infra/relay/src/agentActivity/AgentActivityPublisher.ts, infra/relay/src/observability.ts, infra/relay/scripts/deploy.ts, packages/ssh/src/auth.ts, doc comments in packages/contracts/src/{relay,t3ProjectFile,settings}.ts Push-notification alert titles and relay-side identifiers reading T3 Code; not yet audited for downstream effects on device-registered payload shape
Agent-facing provider identity apps/server/src/provider/Layers/*Provider.ts, apps/server/src/provider/CodexDeveloperInstructions.ts, apps/server/src/textGeneration/OpenCodeTextGeneration.ts, apps/server/src/mcp/McpHttpServer.ts Strings that identify the tool to the coding agent itself (Claude/Codex/Cursor/Grok/OpenCode), not end-user UI copy — renaming risks changing agent behavior and needs its own review
Marketing site apps/marketing/src/** (index, download, legal/privacy/terms pages, testimonials) Includes legal-document copy; a rebrand pass there needs legal sign-off, not just a find-and-replace
Desktop updater release-notes link apps/web/src/components/desktopUpdate.logic.ts (DESKTOP_RELEASE_TAG_URL) Reintroduced by the v0.0.33 sync and allow-listed in check-fork-independence.ts on 2026-08-13. Points at upstream's release tags; the fork publishes no releases of its own (nightly releases disabled), so repointing it links to nothing. Resolve with the rebrand pass, or when the fork starts releasing.
t3 triage destination apps/server/src/cli/triagePrompt.ts (TRIAGE_PLAYBOOK), .github/triage/PLAYBOOK.md Arrived with the v0.0.34 sync and allow-listed in check-fork-independence.ts on 2026-08-20. The playbook sends a fork user's agent to pingdotgg/t3code for the newer playbook, the source clone, prior issues, and the issue it files, so fork bug reports land on upstream's tracker. Repointing it is a product decision (fork tracker, or drop the command), and the two files must move together — triagePrompt.test.ts asserts they are byte-identical.

PROMPT-01 · Trading domain and workspace

Applied

Date Seam File(s) Change
2026-07-30 Static migration registry apps/server/src/persistence/Migrations.ts Added the Migration0035 static import and the [35, "TradingDomain", Migration0035] entry to migrationEntries. Trading tables start at 035; highest upstream migration at the baseline is 034.
2026-07-30 Server package dependencies apps/server/package.json Added "@t3tools/trading-contracts": "workspace:*" so apps/server/src/trading/** can import the domain contracts. Moved to devDependencies the same day: the desktop staging prod-installs the server's runtime dependencies, where a workspace:* spec cannot resolve — bundled workspace packages live in devDependencies like @t3tools/contracts (surfaced by the first pnpm dist:desktop:dmg after Phase 1).

PROMPT-01B · Trading MCP toolkit, orchestration, and workspace shell

Every row below is an upstream-owned file. Fork-owned additions (apps/server/src/trading/**, apps/server/src/mcp/toolkits/trading/**, apps/server/src/orchestration/decider.trading.test.ts, apps/server/src/persistence/Migrations/036_TradingProjection.ts, apps/web/src/components/trading/**, apps/web/src/lib/tradingMissionsState.ts, packages/contracts/src/trading.ts, packages/trading-contracts/**) are new files and cannot conflict on sync, so they are not listed.

Applied

Date Seam File(s) Change
2026-07-30 MCP capability set apps/server/src/mcp/McpInvocationContext.ts, apps/server/src/mcp/McpInvocationContext.test.ts McpCapability widened from "preview" to "preview" | "trading". requireMcpCapability's hard-coded PreviewAutomationUnavailableError generalized into requireCapability(capability, onDenied); requireMcpCapability is now a thin preview-only wrapper with an unchanged failure type.
2026-07-30 MCP credential scope apps/server/src/mcp/McpSessionRegistry.ts, apps/server/src/mcp/McpSessionRegistry.test.ts issue grants {"preview", "trading"} uniformly. Authorization for a trading call is resolved per call from the thread's mission binding, not per session.
2026-07-30 MCP toolkit registration apps/server/src/mcp/McpHttpServer.ts TradingToolkitRegistrationLive merged alongside the preview registration; layer now merges both before the HTTP transport.
2026-07-30 RPC method authorization apps/server/src/auth/RpcAuthorization.ts Added orchestration.getTradingMissionSnapshot at the existing orchestration read scope. The map is exhaustive over ORCHESTRATION_WS_METHODS, so a new method must be added here.
2026-07-30 Orchestration commands and events packages/contracts/src/orchestration.ts Trading members added to DispatchableClientOrchestrationCommand, ClientOrchestrationCommand, InternalOrchestrationCommand, OrchestrationEventType, and OrchestrationEvent. OrchestrationAggregateKind gained "mission"; aggregateId widened with TradingMissionId.
2026-07-30 Contracts module surface packages/contracts/src/index.ts, packages/contracts/package.json export * from "./trading.ts" added the way resourceTelemetry.ts was; @t3tools/trading-contracts added as a dependency so the read model can carry the published domain contracts verbatim.
2026-07-30 RPC surface packages/contracts/src/rpc.ts, packages/contracts/src/ipc.ts WsOrchestrationGetTradingMissionSnapshotRpc added and registered in the WS group; the IPC bridge mirrors getTradingMissionSnapshot. environmentHttp.ts is untouched — it does not mirror orchestration snapshot reads.
2026-07-30 Decider apps/server/src/orchestration/decider.ts, apps/server/src/orchestration/commandInvariants.ts One case per trading command. TRADING_CONTROL_TARGET_STATUS maps each §14.7 control to its §11.1 destination; from-side legality stays in TradingMissionService.transition, which is the only writer of mission status.
2026-07-30 Projectors apps/server/src/orchestration/projector.ts, apps/server/src/orchestration/Layers/ProjectionPipeline.ts Trading events explicitly pass through the in-memory read-model projector unchanged. A tradingMissions projector was added last in ORCHESTRATION_PROJECTOR_NAMES and is deliberately absent from REQUIRED_SNAPSHOT_PROJECTORS, so the orchestration snapshot does not wait on it.
2026-07-30 Reactor registry apps/server/src/orchestration/Layers/OrchestrationReactor.ts, apps/server/src/orchestration/Layers/OrchestrationReactor.test.ts TradingMissionReactor started alongside the existing reactors; the test's expected start order gained trading-mission-reactor.
2026-07-30 Event/receipt stream ids apps/server/src/persistence/Layers/OrchestrationEventStore.ts, apps/server/src/persistence/Services/OrchestrationCommandReceipts.ts streamId / aggregateId unions widened with TradingMissionId to match the widened OrchestrationEvent.
2026-07-30 Migration registry apps/server/src/persistence/Migrations.ts Added the Migration0036 import and the [36, "TradingProjection", Migration0036] entry.
2026-07-30 WS route apps/server/src/ws.ts getTradingMissionSnapshot handler reading TradingMissionProjection.list().
2026-07-30 Server layer graph apps/server/src/server.ts TradingLayerLive provided to the MCP layer; TradingMissionReactorLive added to ReactorLayerLive with its own TradingLayerLive.
2026-07-30 Server route tests apps/server/src/server.test.ts appLayer now provides SqlitePersistenceMemory and TradingMissionProjectionLive: the routes layer genuinely needs a database now that /mcp and the snapshot RPC read mission state.
2026-07-30 Orchestration integration harness apps/server/integration/OrchestrationEngineHarness.integration.ts TradingMissionReactor stubbed (the harness exercises the engine, not trading) and TradingLayerLive provided.
2026-07-30 Client RPC atoms packages/client-runtime/src/state/orchestration.ts tradingMissionSnapshot query atom family added beside archivedShellSnapshot.
2026-07-30 Web routing and nav apps/web/src/routes/settings.trading.tsx (new), apps/web/src/routeTree.gen.ts, apps/web/src/components/settings/SettingsSidebarNav.tsx, apps/web/package.json New /settings/trading route following the settings.*.tsx convention, its generated route-tree entries, a Trading nav item, and the @t3tools/trading-contracts dependency.
2026-07-30 Trading boundary test scope apps/server/src/trading/ProviderBoundary.test.ts The §6.3 static scan now also walks apps/server/src/mcp/toolkits/trading, so the new toolkit is covered by the same no-provider-process rule.
2026-07-30 Upstream web test deflake apps/web/src/lib/stashImageCompression.test.ts The give-up-path test stubbed 8MB per encode; 15 encode passes through jsdom's per-character btoa exceeded the 15s timeout under full-suite load. Stub sizes reduced to 1.4MB encodes / 2MB file — still over the 1.3M-char budget, identical semantics, ~6× less base64 work.

PROMPT-02 · Trading market-data read path

Fork-owned additions (packages/hyperliquid/**, apps/server/src/mcp/toolkits/trading/** new tool definitions, apps/web/src/components/trading/** thread-surface additions) are new files and cannot conflict on sync, so they are not listed. Only upstream-owned edits appear below.

Applied

Date Seam File(s) Change
2026-07-31 trading-contracts subpath exports packages/trading-contracts/package.json ./market and ./account-snapshot subpaths added to the source-first exports map, serving the new §10.6 read contracts.
2026-07-31 trading-contracts subpath parity packages/trading-contracts/src/contracts.test.ts The expected-subpaths array gained ./market and ./account-snapshot; the source-first regex widened from [a-zA-Z]+ to [a-zA-Z-]+ to permit the hyphenated account-snapshot module name the spec §10.6 requires.
2026-07-31 Trading mission service apps/server/src/trading/TradingMissionService.ts getMasterWalletAddress(tradingAccountId) added to the service shape + impl; reads trading_accounts.master_wallet_json and decodes via Schema.fromJsonString(TradingMasterWallet).
2026-07-31 Trading runtime layer apps/server/src/trading/runtimeLayer.ts HyperliquidReadLayerLive merged into TradingLayerLive (bottom-up: FetchHttp → InfoClient → Resolver → Gateway).
2026-07-31 MCP toolkit handler layer apps/server/src/mcp/toolkits/trading/handlers.test.ts FetchHttpClient import removed; the read layer is now self-contained via runtimeLayer.ts.
2026-07-31 Server dependency apps/server/package.json @t3tools/hyperliquid added as a workspace dependency.
2026-07-31 WS snapshot sequence apps/server/src/ws.ts getTradingMissionSnapshot now derives snapshotSequence from orchestrationEngine.latestSequence instead of the hardcoded 0, so the client can order catch-up.
2026-07-31 Chat thread surface apps/web/src/components/ChatView.tsx useTradingMissionForThread hook + <MissionThreadPanel> inserted above the timeline for mission-bound threads.

Corrections to the Phase 2 plan

Date Item Finding
2026-07-31 "missing desktop IPC handler" The plan's Step 8 claims getTradingMissionSnapshot has "no handler in apps/desktop". This is a non-defect: the handler IS implemented server-side at apps/server/src/ws.ts:1233 (auth wired at apps/server/src/auth/RpcAuthorization.ts:29), and the desktop app proxies orchestration RPCs to the server over WebSocket — exactly like getTurnDiff. No desktop-local handler exists for any orchestration method by design. This sub-task was skipped rather than fabricated.

PROMPT-02 review corrections (2026-07-31)

The as-committed wire layer had never been run against the real exchange; live verification against api.hyperliquid-testnet.xyz falsified most of it. All fixes are fork-owned (packages/hyperliquid/**); recorded live fixtures now sit under packages/hyperliquid/fixtures/ and are replayed by wire.test.ts.

Item Finding and fix
Wire schemas Candles are {t,T,s,i,o,c,h,l,v,n} objects (was tuples); candleSnapshot requires startTime; l2Book levels are {px,sz,n} objects (was tuples); HTTP allMids is a flat record (was {mids}); withdrawable is top-level (was inside marginSummary); open orders are flat rows (there is no orderState); midPx is null on dead markets (54/210 on testnet), which failed the whole metaAndAssetCtxs decode and with it every read.
WebSocket client Inbound frames were "parsed" with Schema.Unknown (an identity decode), so the envelope decode failed on the raw string and every frame was silently dropped — the client could never deliver a message. Also fixed: per-subscription routing (channel type alone cross-delivered coins/intervals), reconnect backoff now resets per outage, duplicate connect loops guarded, unsubscribed entries removed from the resubscribe set.
Candle clamp / finalisation The 500-bar clamp kept the OLDEST bars (slice(0, cap)); now keeps the most recent. finalisedClose reported the in-progress bar's close; now the last bar whose close time has passed.
Fixture recorder Logged counts but never wrote a fixture; now records raw responses (market fixtures need no credentials) and decode-checks them at record time.
Test-runner rule The trading test files used Effect.runPromise, which t3code(no-manual-effect-runtime-in-tests) rejects — lint was failing at the Phase 2 HEAD. Converted to @effect/vitest it.effect/it.live.

PROMPT-03 · Watches and harness wake-up

Phase 3 — the central architecture proof. The T3 server stays active after a harness turn ends, evaluates persisted watches, and resumes the same provider session with a fresh mission snapshot when a typed event fires.

Step 0 — Shared contracts (2026-07-31)

Date Seam File(s) Change
2026-07-31 trading-contracts subpath exports packages/trading-contracts/package.json, src/index.ts, src/contracts.test.ts ./wakeup subpath added (§12.2 TradingHarnessWakeup, TradingDomainEventSummary; §12.3 HarnessRunRequest, HarnessRunOutcome); barrel re-export added; expected-subpaths snapshot updated.
2026-07-31 Watch tool contracts packages/trading-contracts/src/tools.ts Four §14.4 watch-tool schemas + name constants: trading_register_watch, trading_schedule_reassessment, trading_list_watches, trading_cancel_watch (inputs/results reusing MarketWatch/PersistedWatch).
2026-07-31 Orchestration trading commands/events packages/contracts/src/trading.ts, packages/contracts/src/orchestration.ts Four internal commands + four payloads + four event literals: trading.mission.{watch-registered,watch-cancelled,watch-fired,run-started}. Literals appended to OrchestrationEventType; event structs added to the OrchestrationEvent union; imports updated.
2026-07-31 Decider cases apps/server/src/orchestration/decider.ts Four new cases mirroring the existing trading command→event pattern (exhaustiveness satisfies never forced them).
2026-07-31 Pure projector fall-through apps/server/src/orchestration/projector.ts Four new trading event types added to the no-op fall-through list (the mission read model is maintained by ProjectionPipeline, not here).
2026-07-31 SQL projection refresh apps/server/src/orchestration/Layers/ProjectionPipeline.ts applyTradingMissionsProjection switch now refreshes on the four new event types (re-reads the authoritative row from migration-035 tables, as the existing trading events do).
2026-07-31 Server contract re-exports apps/server/src/trading/Schemas.ts Re-exports the wakeup contracts and the four watch-tool schemas so server modules import them from one place.

Step 1 — Watch registry (2026-07-31)

Date Seam File(s) Change
2026-07-31 Trading runtime layer apps/server/src/trading/runtimeLayer.ts TradingWatchServiceLive merged into TradingLayerLive.

(Fork-owned: TradingWatchService.ts + test are new files under apps/server/src/trading/.)

Step 2+3 — Watch evaluator and event inbox (2026-07-31)

Date Seam File(s) Change
2026-07-31 Trading runtime layer apps/server/src/trading/runtimeLayer.ts TradingEventInboxLive and HyperliquidWsLayerLive merged into TradingLayerLive.
2026-07-31 Orchestration reactor apps/server/src/orchestration/Layers/OrchestrationReactor.ts WatchEvaluator yielded and start() called (subscribes to the WS candle stream, announces trading.mission.watch-fired).
2026-07-31 Server reactor wiring apps/server/src/server.ts WatchEvaluatorLive.pipe(Layer.provide(TradingLayerLive)) added to ReactorLayerLive (mirrors TradingMissionReactorLive).
2026-07-31 Reactor test stubs apps/server/src/orchestration/Layers/OrchestrationReactor.test.ts, integration/OrchestrationEngineHarness.integration.ts Stub WatchEvaluator provided in both test layers (engine harness does not exercise trading).
2026-07-31 Hyperliquid dev subpath export packages/hyperliquid/package.json ./InfoClientTest subpath added so the evaluator test can import fakeWebSocketClientLayer (dev-only fake; live WS client unaffected).

(Fork-owned: TradingEventInbox.ts, WatchEvaluator.ts, and tests are new files under apps/server/src/trading/.)

Step 4+5 — Turn coordinator and wake path (2026-07-31)

Date Seam File(s) Change
2026-07-31 Trading runtime layer apps/server/src/trading/runtimeLayer.ts TradingWakeupComposerLive wired with gateway + mission/watch/inbox deps; coordinatorWithDeps provides it. TradingLayerLive composition updated.
2026-07-31 Mission service address type apps/server/src/trading/TradingMissionService.ts getMasterWalletAddress return type changed from string to EvmAddress so callers (composer, handlers) pass it to the gateway without a cast.
2026-07-31 Watch service read apps/server/src/trading/TradingWatchService.ts getWatch(watchId) added so the wake path can resolve the triggering watch for the wakeup snapshot.
2026-07-31 Integration harness layer apps/server/integration/OrchestrationEngineHarness.integration.ts TradingLayerLive now provided with orchestrationLayer + projectionSnapshotQueryLayer so the coordinator's OrchestrationEngineService requirement is met type-safely.

(Fork-owned: TradingTurnCoordinator.ts (wake dispatch + lease-release watcher), TradingWakeupComposer.ts, TradingWakePath.integration.test.ts — new files under apps/server/.)

Step 6 — Watch MCP tools (2026-07-31)

Date Seam File(s) Change
2026-07-31 Toolkit dependencies apps/server/src/mcp/toolkits/trading/tools.ts TradingWatchService added to the shared dependencies array so watch handlers can resolve it.
2026-07-31 Toolkit handler casts apps/server/src/mcp/toolkits/trading/handlers.ts Three address as \0x${string}`casts removed (now thatgetMasterWalletAddressreturnsEvmAddress` natively).

(Fork-owned: the four tool definitions and four handlers are additions to existing files; no new files.)

Step 7 — Thread-derived binding and first run (2026-07-31)

Date Seam File(s) Change
2026-07-31 Mission reactor provider read apps/server/src/trading/TradingMissionReactor.ts ProjectionSnapshotQuery dependency added; resolveHarnessBinding derives provider/instance from the thread's session (replacing the hardcoded provider: "claude"). First run (cause: mission_created) dispatched after create.
2026-07-31 Coordinator fork apps/server/src/trading/TradingTurnCoordinator.ts Wake fork switched from forkScoped to forkDetach; requestRun no longer requires Scope.Scope.

Review pass — wake-loop closure and inbox lifecycle (2026-07-31)

Date Seam File(s) Change
2026-07-31 Mission reactor wake loop apps/server/src/trading/TradingMissionReactor.ts trading.mission-watch-fired now handled: the reactor derives the run cause from the fired watch's type and calls TradingTurnCoordinator.requestRun (forked retry while queued behind an active run). This closes the watch→resume loop, which previously ended at the projection.
2026-07-31 Coordinator release watcher apps/server/src/trading/TradingTurnCoordinator.ts Turn-end watcher takes exactly one matching event (was a process-lifetime stream consumer per run), is forked before the dispatch, and markIncludedConsumed is keyed by mission id (was mistakenly the thread id). Inbox claim is one atomic UPDATE … RETURNING.
2026-07-31 Inbox schema apps/server/src/persistence/Migrations.ts, Migrations/037_TradingInboxSummary.ts Migration 037 adds trading_event_inbox.summary so the human summary persisted with an event survives to the wakeup (it was previously discarded). Dedupe keys are now scoped per watch id.
2026-07-31 Watch evaluator coverage apps/server/src/trading/WatchEvaluator.ts Candle subscriptions widened to all five §13 direct intervals; a 2s sweep evaluates price_cross (fresh gateway snapshot) and fires due scheduled_reassessment watches. Redundant in-memory seen-close set removed (markTriggered + inbox dedupe are the durable guards).
2026-07-31 Test stubs apps/server/src/orchestration/Layers/OrchestrationReactor.test.ts, integration/OrchestrationEngineHarness.integration.ts WatchEvaluator stubs gained the new sweep member.

PROMPT-03 · Follow-ups (tracked)

The following were scoped out of this phase and are tracked for a future pass:

  • Web mission composer — a composer surface in the bound thread for authoring {instruction, allocatedCapitalUsd} and dispatching trading.mission.create. No trading command dispatch exists on the web today (apps/web/src has the read path via useTradingMissionForThread but zero trading.mission.create wiring).
  • Trading timeline — render watch/run/inbox activity rows alongside chat messages, fed by the mission snapshot. The TimelineEntry kind: "work" row in session-logic.ts is the plug-in point.
  • Lifecycle rail, versioned plan card, armed card (web) — Step 8 surfaces. The plan's Research/Plan/Armed/Entered/Managing/Closed vocabulary does not exist in TradingMissionStatus (10 statuses today); either a UI-side mapping or a contract change is needed. MissionThreadPanel.tsx:44 has pending = true hardcoded.
  • Mobile equivalents — React Native versions of the above in apps/mobile/src/features/threads/; shared label/format helpers to move to packages/client-runtime.

PROMPT-04 · Trading execution and reconciliation

Fork-owned additions (packages/trading-contracts/src/execution.ts, packages/hyperliquid/src/{Cloid,NonceCoordinator,Signing,OrderMapper}.ts, apps/server/src/trading/InterimSignerConfig.ts, docs/architecture/trading-execution.md) are new files and cannot conflict on sync, so they are not listed. Only upstream-owned edits appear below.

Applied

Date Seam File(s) Change
2026-07-31 Build-time env .env.example Added the optional T3_TRADES_INTERIM_SIGNER_KEY / T3_TRADES_INTERIM_SIGNER_ADDRESS knobs for the interim testnet signer (PROMPT-04). Fail-closed when unset; Privy replaces this in PROMPT-06.
2026-07-31 hyperliquid deps packages/hyperliquid/package.json Added @noble/curves and @noble/hashes (both already in the workspace catalog, consumed elsewhere for DPoP) as dependencies and the ./Cloid, ./NonceCoordinator, ./Signing, ./OrderMapper subpath exports.
2026-07-31 trading-contracts packages/trading-contracts/package.json, src/index.ts, src/contracts.test.ts Added the ./execution subpath and its export/tests for the deferred execution-domain contracts (§14.4–§14.7, §15, §16.2, §18).
2026-08-01 Server dependency apps/server/package.json @t3tools/hyperliquid moved from devDependencies to dependencies (Signing/ExchangeClient/Reconciler are now runtime imports, not test-only).
2026-08-01 Migration registry apps/server/src/persistence/Migrations.ts Added the Migration0038/Migration0039/Migration0040 imports and the [38, "TradingExecution", …], [39, "TradingExecutionColumns", …], [40, "TradingExecutionStopAndMark", …] entries for the six §18 execution tables, the additive execution columns, and the stop/mark columns.
2026-08-01 Orchestration contracts packages/contracts/src/trading.ts OrchestrationTradingMission gained three optional execution views (inFlightExecution, recentFills, position) for the Step 10 thread cards.
2026-08-01 Decider case apps/server/src/orchestration/decider.ts Added the trading.execution.requested case (~:1339) emitting trading.execution-requested. A named INTEGRATION_MAP high-conflict seam.
2026-08-01 Orchestration events packages/contracts/src/orchestration.ts Added the trading.execution-requested event literal + union member + TradingExecutionRequestedPayload.
2026-08-01 MCP trading tools apps/server/src/mcp/toolkits/trading/{tools,handlers}.ts Added the trading_request_entry tool definition and handler that dispatches the execution command.
2026-08-01 Integration harness apps/server/integration/OrchestrationEngineHarness.integration.ts Uses TradingCoreLayerLive (reactor-only) instead of the full TradingLayerLive; the harness exercises the engine, not trading execution.
2026-08-01 CLI test scope apps/server/src/bin.test.ts Stubs TradingMissionReactor so the project-CLI test doesn't pull in the full execution layer.

PROMPT-04 remediation · close the gaps left by the Phase-4 merge

Applied

Date Seam File(s) Change
2026-08-02 Order wire field name packages/hyperliquid/src/OrderMapper.ts buildOrderAction order leg now uses key c for the client order id, not cloid (canonical Hyperliquid wire form, verified byte-for-byte against hyperliquid-python-sdk). The cancel-by-cloid action's top-level leg still uses cloid. The wrong key changed the action hash and produced self-consistent-but-canonical-rejected signatures; this was the root cause of the live Gate E failure and the original "sell-action signature recovers to a wrong address" symptom.
2026-08-02 Cloid wire format packages/hyperliquid/src/Cloid.ts deriveCloid now returns a 0x-prefixed 34-char hex string (was bare 32-char). Reading the live Gate E entry back showed the exchange stored "cloid": null for the bare form; the 0x prefix makes the exchange register the cloid so retry-dedup is enforced server-side.
2026-08-02 Cancel-by-cloid action shape packages/hyperliquid/src/OrderMapper.ts buildCancelByCloidAction(assetIndex, cloid) now emits { type: "cancelByCloid", cancels: [{ asset, cloid }] } (was { cancels: [{ coin, cloid }] } with no type). Same class of defect as the order-path type:"order" fix; verified against the exchange-endpoint docs.

Future entries

Add a new ## PROMPT-NN · <phase name> section per phase that touches upstream-owned files, so SYNC_RUNBOOK.md batches can be checked against this ledger for expected conflicts.

PROMPT-05 · Protection, deterministic controls, position management

Fork-owned additions (packages/trading-contracts/src/protection.ts, packages/hyperliquid/src/ExchangeResponse.ts, apps/server/src/trading/{TradingProtectionService,TradingEmergencyCloseService,TradingControlService}.ts, apps/web/src/components/trading/*, apps/server/src/trading/TradingAccountBootstrap.ts) are new files and conflict with nothing. The upstream seams below are the ones a sync has to reconcile.

Date Area Files Change
2026-08-02 Orchestration commands and events packages/contracts/src/orchestration.ts Added the trading.mission-risk-control-requested event literal, its union member, and the TradingMissionRiskControlRequestedPayload import. Same shape as the PROMPT-03/04 additions.
2026-08-02 Decider case apps/server/src/orchestration/decider.ts Added the trading.mission.risk-control case emitting trading.mission-risk-control-requested. Unlike the pause/resume/revoke case it resolves no target status — what the mission becomes depends on the exchange, so the reactor decides after the fact. A named INTEGRATION_MAP high-conflict seam.
2026-08-02 Pure projector fall-through apps/server/src/orchestration/projector.ts trading.mission-risk-control-requested added to the no-op fall-through list beside trading.mission-control-requested.
2026-08-02 Client command operations packages/client-runtime/src/operations/commands.ts Added tradingMissionControl and tradingRiskControl dispatchers at the end of the file, following the existing dispatch(...) pattern.
2026-08-02 Client orchestration atoms packages/client-runtime/src/state/orchestration.ts Added missionControl and riskControl environment commands beside the existing query families; the factory's runtime parameter gained Crypto.Crypto, which the command path needs for command ids.
2026-08-02 Client command operations packages/client-runtime/src/operations/commands.ts Added the tradingMissionCreate dispatcher, which mints the mission id through Crypto rather than taking one from the caller. Same seam as the row above.
2026-08-02 Client orchestration atoms packages/client-runtime/src/state/orchestration.ts Added the missionCreate environment command beside missionControl/riskControl. Same seam as the row above.
2026-08-02 Interim signer secret reader apps/server/src/trading/InterimSignerConfig.ts readFileText moved from Effect.promise to Effect.tryPromise. A rejection from promise is a DEFECT, so an absent key file walked past the orElseSucceed that turns "no file" into "unarmed" and killed the caller instead. Fork-owned file, listed because it is the gate that guards testnet capital.
2026-08-02 Reachability integration test apps/server/integration/TradingExecutionReachability.integration.test.ts Fake exchange response moved to the exchange's real response.data.statuses shape, and getOpenOrders now surfaces accepted reduce-only triggers so the protection path can confirm them. Fork-owned test, listed because a sync that changes the fakes will touch it.
2026-08-03 Reactor event subscription apps/server/src/trading/TradingMissionReactor.ts The reactor handles upstream thread lifecycle events (today thread.settled and thread.deleted, which end a thread's mission; the original thread.created auto-mission shortcut was deleted in final-form Phase 9). Fork-owned file, listed because it is the first place trading code consumes a non-trading.* event: a sync that changes those payloads reaches it.
2026-08-03 Reactor event subscription apps/server/src/trading/TradingMissionReactor.ts The reactor now also handles the upstream thread.settled event: settling a mission-bound thread revokes the mission, closing an open position first. Fork-owned file, listed because a sync that changes ThreadSettledPayload or the settle decider's preconditions reaches it.

PLANS 21–25 · Execution UI, harness primitives, lifecycle/live panel, tool optimization, stand-down (backfill 2026-08-13)

Backfilled before the v0.0.33 sync (plan 26, runbook step 4): plans 21–25 landed 2026-08-05 → 2026-08-10 without ledger rows. Fork-owned additions (apps/web/src/components/trading/**, apps/server/src/trading/**, packages/trading-contracts/src/**, migrations 041–053 files) conflict with nothing and are not listed. Upstream-owned seams below.

Applied

Date range Seam File(s) Change
2026-08-05 → 08-10 Migration registry apps/server/src/persistence/Migrations.ts Registry rows 41–53 added (inbox-summary repair, authority valid-until, watch provenance, account observations, peak-pnl, excursion, closed trades, fill lifecycle, watch observability, stop adjustments, run decisions, entry quotes, execution sequences). Renumber policy: every incoming upstream migration takes the fork's next free id (054+).
2026-08-05 → 08-10 Decider trading cases apps/server/src/orchestration/decider.ts Additional trading command cases appended (stop-adjustment envelope, settle/boot/turn-dispatch fixes, entry-quote/exit receipts). Append-append seam; fork cases stay after upstream's.
2026-08-06 Projector fall-through apps/server/src/orchestration/projector.ts New trading events added to the no-op fall-through list (stop-adjustment).
2026-08-05 → 08-10 Orchestration contracts packages/contracts/src/orchestration.ts New trading event literals/union members and payloads (market-chart RPC, review-chart window, mission-on-first-message, stop adjustment, entry quotes/exits). Append-append seam.
2026-08-05 → 08-10 WS routes + history join apps/server/src/ws.ts getTradingMarketChart RPC; mission history joined server-side into the snapshot (one join for all clients); wake-path failure hardening; mission-on-first-message and settle-deletes-mission wiring; live-mark quoting. Semantic overlap with upstream ca72e381c (bounded catch-up replay / no full-DB snapshot hydration) — hand-review on sync.
2026-08-05 → 08-10 Provider adapters + profile apps/server/src/provider/Layers/{Claude,Codex,Cursor,Grok,OpenCode}Adapter.ts, apps/server/src/provider/SessionProfile.ts, apps/server/src/provider/CodexDeveloperInstructions.ts MCP server key renamed to t3-trade in every adapter's server registration; mission-locked provider/session profile (session lock, wakeup shrink); OpenCode stop kept clean on echoed session.error. Semantic overlap with upstream e60821f0e model-menu refactor — hand-review on sync.
2026-08-06 → 08-10 Server layer graph apps/server/src/server.ts Turn-dispatch reliability wiring for live missions (reactor/layer adjustments).
2026-08-05 → 08-10 Client runtime atoms/commands packages/client-runtime/src/state/orchestration.ts, packages/client-runtime/src/operations/commands.ts tradingMarketChart query atom; entry-quote/exit command dispatchers. Append-append seam.
2026-08-05 → 08-10 Web chat surface apps/web/src/components/ChatView.tsx, apps/web/src/components/chat/{ChatHeader,ChatComposer,MessagesTimeline}.tsx Mission live panel above composer, centered mission pill, sticky/windowed charts, timeline trading cards, turns rug, mission composer controls, wakeup-provider composer wiring. Take upstream's structure on sync, re-inject these trading mounts.
2026-08-05 → 08-07 Web sidebar + css + hooks apps/web/src/components/{Sidebar,SidebarV2}.tsx, apps/web/src/index.css, apps/web/src/hooks/{useHandleNewThread,useThreadActions}.ts, apps/web/src/session-logic.test.ts Mission rows in sidebar and draft hero; mission schedule styles; archived-thread resurrection stop; settle action wiring; session-logic test expectations for the t3-trade MCP key.

| 2026-08-13 | CI test scoping | .github/workflows/ci.yml, package.json, apps/server/package.json, apps/web/package.json | Fork-scoped CI tests: a PR whose changes are confined to fork-owned paths runs test:fork and skips Rust/Electron setup + resource-monitor tests. Scope decided by the fork-new scripts/test-scope.ts from gh pr diff; pushes to main and upstream-touching PRs still run the full suite. Fork-owned = trading-contracts, hyperliquid, apps/server/src/trading, apps/server/src/mcp/toolkits/trading/, apps/server/src/provider/TradingSessionProfile.ts, web trading dirs, docs. The last two sit in upstream directories and are only safe because the server's test:fork runs src/mcp and src/provider whole — widening the path list without widening that glob breaks main. docs/upstream/BASELINE.md is explicitly excluded (asserted by packages/shared/src/buildMetadata.test.ts, which test:fork does not run). On sync, re-add the test:fork script lines and the scope steps in the Test job. |

Settle-path semantic seam (hand-review on sync)

Upstream 491219bf1 (threads with open PRs no longer auto-settle) and 5c9358aca (title regeneration) touch the settle path. The fork revokes missions on thread.settled (TradingMissionReactor, threadSettled.ts, decider.settled.test.ts) and deletes the mission on settle (09b673f92). A sync must re-run decider.settled/snoozed/trading tests and TradingWakePath.integration.test.ts after resolving.

PLAN 26 · v0.0.33 sync (a8e05cbb..3b72d17cb, 2026-08-13)

236 upstream commits accepted in two merges on sync/upstream-2026-08-04-cec1bb9de: batch A to cec1bb9de (79 commits, pre-Effect-beta.103), batch B to v0.0.33 (157 commits, carrying the Effect bump). Seams resolved below; every one is a place a future sync will land again.

Migration renumber policy (now exercised)

Upstream migrations collide with the fork's 035–053 trading range, so every incoming upstream migration takes the fork's next free id, keeping ids stable in databases that already recorded them. Applied this sync:

Upstream id / name Fork id
035_ProjectionThreadTitleRegeneration 054
036_ProjectionThreadsPinned 055
037_ProjectionTurnsKeysetIndex 056
038_ProjectionThreadsPinOrderKey 057
039_ProjectionProjectsDefaultThreadEnvMode 058
040_ProjectionProjectFaviconPath 059

Renumbering means renaming the file, its registry row, and the runMigrations({ toMigrationInclusive: N }) bounds inside its own test — those bounds are ids, not offsets, and a stale one silently tests the fork's migration instead of upstream's.

Applied

Seam File(s) Change
Sidebar v2 became default apps/web/src/components/Sidebar.tsx (upstream deleted SidebarV2.tsx in #5672) Upstream promoted SidebarV2 to Sidebar.tsx and demoted the old one to LegacySidebar.tsx. The fork's mission rows lived in both files. Resolution: take upstream's Sidebar.tsx wholesale, re-inject the mission join (tradingMissionSnapshot poll + missionByThreadKey), the row's mission prop, and a mission branch in topStatus that outranks Working/Woke/Done but yields to approval/input/failed. MISSION_STATUS_DOT became MISSION_STATUS_CLASS because upstream's row colours the label, not a dot.
Chat header mission pill apps/web/src/components/chat/ChatHeader.tsx Upstream rewrote the header (thread-action menu, breadcrumb, project scripts). The fork's three-column grid is gone; missionSlot is now rendered between the breadcrumb and the actions. ChatHeader.test.ts, which the fork had deleted, is restored from upstream.
Settle path apps/server/src/orchestration/decider.ts Upstream now emits thread.unpinned when settling a pinned thread. Composed with the fork's session-stop: settle emits stop (if running) → settled → unpin (if pinned), in that order.
Settle gating apps/web/src/hooks/useThreadActions.ts Upstream added a canSettle guard that blocks settling a running/approval/input thread. Deliberately not taken — a live mission is always in one of those states, and settle is the control that stops it. Upstream's threadWokeAt visit-marking is kept.
Settings nav apps/web/src/components/settings/{SettingsSidebarNav.tsx,settingsSearch.ts} Upstream derives the nav from SETTINGS_SECTION_LABELS, so /settings/trading is now registered in settingsSearch.ts (SettingsPath + labels) and gets its icon in SETTINGS_SECTION_ICONS. The fork's local SettingsSectionPath union is gone. Upstream also dropped /settings/beta.
Claude adapter grants apps/server/src/provider/Layers/ClaudeAdapter.ts Upstream grants the attachments dir via additionalDirectories. A trading thread still grants nothing (no cwd, no attachments), so the array is empty and the key is omitted.
Draft thread reuse apps/web/src/hooks/useHandleNewThread.ts Upstream rewrote empty-draft reuse (async default env mode, staleness bail-out, emptyStoredDraftThread). The fork's fresh newThreadId() mint is re-injected — reusing a stored draft's id resurrects an archived mission thread and the orchestration invariant refuses it.
Startup phases apps/server/src/serverRuntimeStartup.ts Upstream moved the heartbeat/headless/browser-open block into an earlier forkParked; the fork's duplicate block is dropped and the "T3 Trade" pairing copy reapplied at the new site.
Test layer stacks apps/server/integration/{OrchestrationEngineHarness,TradingExecutionReachability}.*, src/trading/TradingMissionReactor.test.ts, src/orchestration/Layers/StaleSessionReconciler.test.ts Upstream's projection pipeline now needs ThreadBackgroundLivenessService and ThreadPlanProgressService; every fork-owned layer stack that builds the pipeline must provide both, including the inner orchestrationLayer the trading harness instantiates separately.
MCP protocol version apps/server/src/mcp/{McpHttpServer.ts,toolkits/trading/handlers.test.ts} McpServer.layerHttp now declares protocols: [McpProtocol.v2025_06_18]. Post-initialize requests must carry an mcp-protocol-version header or the transport answers with an empty body before reaching a handler — the fork's toolkit test now sends it.
Environment descriptor apps/server/src/cli/pair.test.ts Upstream's new t3 pair test fixture omits the fork-required fork / t3UpstreamCommit descriptor fields, so discovery reported "no running server" rather than a decode error. Fixture now carries both from @t3tools/shared/buildMetadata.
Docs tree README.md, docs/README.md Upstream moved docs/architecture/**docs/internals/** and added docs/user/**; fork doc indexes repointed. Upstream's desktop-install/registry sections stay out — this fork publishes no releases.

Effect 4.0.0-beta.103 API breaks (fork-owned code)

API Change Fork sites
SchemaIssue.InvalidValue Dropped the leading actual argument; now takes annotations only packages/trading-contracts/src/strategy.ts
Schema.UnknownFromJsonString Removed; use Schema.fromJsonString(Schema.Unknown) (both directions behave the same) packages/hyperliquid/src/WebSocketClient.ts, apps/server/src/trading/TradingEventInbox.ts, trading handlers test

PLANS 27–39 · seams on the v0.0.34 conflict surface (backfill 2026-08-20)

Backfilled before the 3b72d17cb..beab6886f sync. Scope is deliberately narrow: the 28 files git merge-tree main upstream/main forecast as conflicts. Fork-only files (the whole apps/web/src/components/trading/** tree, apps/server/src/trading/**, packages/trading-contracts/**, packages/hyperliquid/**) are not seams — upstream does not have them and they cannot conflict.

Resolution policy, one bucket per group. A = keep ours. B = take upstream, re-apply the fork delta. C = take upstream's rewrite, re-inject the seam. D = regenerate.

A · Fork identity — keep ours

Seam File(s) Change
Fork README README.md The fork's own product README (T3 Trade, trading architecture, spec links). Upstream keeps editing its own; ours wins whole.
Install docs docs/user/install.md Desktop downloads point at TaraxioT/t3trade releases; the winget/brew/AUR block is relabelled as upstream T3 Code, not this fork.
Marketing site apps/marketing/src/pages/index.astro Fully fork-authored landing page (3010+/910-). Take ours whole.
Marketing download apps/marketing/src/pages/download.astro Deleted in the fork. Upstream keeps editing it — keep the deletion (git rm) on every sync.
Release workflow .github/workflows/release.yml Fork release conventions: t3trade-v* tags, unsigned arm64 artifacts, prerelease flag, a preflight job gating relay stages on has_relay_config, and 2vcpu runners in place of upstream's larger Blacksmith boxes.
Showcase workflow .github/workflows/mobile-showcase-screenshots.yml Runner downgrade only (blacksmith-2vcpu-ubuntu-2404) — the fork has no macOS/16vcpu runner budget.
Desktop icons apps/desktop/resources/icon.ico, icon.png (and icon.icns) Fork-branded binaries. Upstream ad117235b deleted the committed icons and replaced them with an optional path probe (DesktopAssets.ts returns Option-typed iconPaths from resolveResourcePathCandidates). Resolution: keep the fork's binaries and take upstream's probe code — the probe finds them. electron-launcher.mjs also copies icon.icns into Resources.

B · Rebrand and version plumbing — take upstream, re-apply the fork delta

Every row below is the same one-word seam: user-visible "T3 Code" → "T3 Trade", plus CLI_PACKAGE_NAME in place of the hard-coded t3 binary name. Upstream rewrites the surrounding text often; the delta is mechanical.

Seam File(s) Change
CLI root command apps/server/src/bin.ts Root command name and description come from CLI_PACKAGE_NAME / "T3 Trade"; the fork also registers sessionReportCommand.
Connect onboarding copy apps/server/src/cli/connect.ts "T3 Trade will stay reachable after you log out."
Service CLI copy apps/server/src/cli/service.ts Every T3 Code service string → T3 Trade service; npx t3@latestnpx ${CLI_PACKAGE_NAME}@latest.
Version-skew hints apps/web/src/versionSkew.ts + .test.ts Mismatch hint and desktop-managed guidance say "T3 Trade". The test fixture also carries the fork-only fork / t3UpstreamCommit descriptor fields.
Desktop update copy apps/web/src/components/desktopUpdate.logic.ts Rosetta / Windows-install warnings say "T3 Trade".
Desktop test fixtures apps/desktop/src/app/DesktopAppIdentity.test.ts, DesktopLifecycle.test.ts, src/telemetry/DesktopTelemetryPublisher.test.ts, src/window/DesktopApplicationMenu.test.ts ElectronApp.name fixtures, app paths, and the (Alpha) userData path all read "T3 Trade".
Shared package exports packages/shared/package.json Fork-added ./buildMetadata export. Additive — re-add it after taking upstream's export map.

C · Behavioural seams — take upstream's rewrite, re-inject the seam

Seam File(s) Change
Settle stops first apps/server/src/orchestration/decider.ts The fork removed all three settle refusals (live session, open approval, queued turn) — a running mission is always in those states, so the one control meant to stop a mission was the one control that could not. Settle now emits thread.session-stop-requested before the settled event when a session is starting/running, then upstream's companion events. Upstream 07e668dc4 added an unsnoozed companion event in the same block: keep both, ordered stop → settle → unpin/unsnooze.
Trading command block apps/server/src/orchestration/decider.ts ~240 fork-only lines appended after the last upstream case (trading.mission.*, guarded by requireTradingControlTarget). Pure addition at the end of the switch — it survives any upstream rewrite above it.
Settle tests apps/server/src/orchestration/decider.settled.test.ts, packages/client-runtime/src/state/threadSettled.test.ts The fork deleted canSettle from threadSettled.ts and its whole describe("canSettle") block, and rewrote the decider's settle tests to assert the stop-first event order. Upstream keeps adding tests that import canSettle (f21b47e52). On every sync: take upstream's new cases, then re-delete the canSettle import and its describe blocks, or typecheck fails on a function the fork no longer exports.
Session profiles apps/server/src/provider/Layers/ProviderService.ts Two fork lines: import SessionProfile and call SessionProfile.clearAllSessionProfiles() in the same teardown that clears MCP provider sessions.
Composer mission footer apps/web/src/components/chat/ChatComposer.tsx Two optional props — missionControls and assetPicker (ReactNode) — declared on ChatComposerProps, destructured, and rendered at the end of the footer's left-hand control row. Undefined on every non-mission thread, so upstream's footer is unchanged for them. Also a title on the disabled no-provider button.
Timeline wakeup rows apps/web/src/components/chat/MessagesTimeline.tsx A footer prop (execution cards pinned after the last message, inside the scroll), plus TradingWakeupTimelineRow — the runtime injects wake snapshots as user messages (§12.4), and without this the thread is a stack of JSON blobs. Event wakes get the amber accent, clock wakes stay neutral; NEW_WAKEUP_WINDOW_MILLIS = 10_000.
Sidebar mission rows apps/web/src/components/Sidebar.tsx SidebarThreadRow takes a mission prop; MISSION_STATUS_CLASS colours the status label; a mission-bound row shows MISSION_STATUS_LABELS[status] · ±$x (unrealised while exposed, realised once flat with fills) and outranks the session-derived status, but never outranks approval/input/failed. The list joins missions by threadId off the primary environment on the mission surfaces' poll cadence.
Mission CSS apps/web/src/index.cssapps/web/src/trading.css 486 fork-added lines: mission-panel-glass, mission-chip*, mission-order-*, mission-log-*, watch-tick-in/watch-dot-pulse, their @keyframes and prefers-reduced-motion / prefers-reduced-transparency fallbacks, and the deliberately unlayered rules (inside @layer components they lose to upstream's utilities). Upstream rewrote 1600 lines of index.css in 9885a845c, so as of this sync the block moves wholesale into fork-owned apps/web/src/trading.css, imported by one line from index.css. This is meant to be the last index.css conflict — new mission CSS goes in trading.css.

D · Regenerated, never hand-merged

Seam File(s) Change
Lockfile pnpm-lock.yaml Take either side during the merge, then run pnpm install once every package.json conflict is settled, and commit the regenerated file.

SYNC · v0.0.35 (beab6886f..f925d6394, 2026-08-28)

133 upstream commits in one merge on sync/v0.0.35. The previous baseline was a v0.0.34 nightly, so this batch carried stable v0.0.34 as well as v0.0.35 — see BASELINE.md. Twelve files conflicted, exactly the set merge-tree forecast.

Migration renumber policy (exercised again)

Upstream id / name Fork id
041_AuthSessionClientConnection 080
042_ProjectionThreadLinkedPullRequest 081
043_ProjectionThreadsUnsettledAt 082

The fork owns 035–079, so upstream's 041–043 could not keep their own ids. Each move renames the file, its registry row, its layer(...) name and the runMigrations({ toMigrationInclusive: N }) bounds inside its own test — the bounds are ids, not offsets. Verified by running the whole chain against a VACUUM INTO snapshot of the real ~/.t3trade/dev database: 82 rows, no gaps, no duplicates, and the 27 existing trading missions survived the boot.

Applied

Seam File(s) Change
Client-attributed dispatch apps/server/src/ws.ts Upstream 11f051373 routes every client command through dispatchFromClient so threads and turns record which client started them. The fork's dispatchTradingAwareTurnStart and its bootstrap already-exists guard both called orchestrationEngine.dispatch directly; both now call dispatchFromClient. Any future fork dispatch site must do the same or it silently drops client attribution.
Editor-discovery rename apps/server/src/ws.ts Upstream renamed EDITOR_DISCOVERY_TIMEOUT to CONFIG_DISCOVERY_TIMEOUT and wrapped it in resolveDiscoveryForConfig. The fork's trading wire helpers (toWireThreadMarketFocus, toWireAccountWatch, toWireWatchlist*) sit immediately above and conflict with every edit to that block.
Composer send notice apps/web/src/components/ChatView.tsx The fork's startResult.value.notice handling and upstream's releaseAttachmentUploads are independent statements in the same success branch — take both.
Labelled settle buttons apps/web/src/components/Sidebar.tsx The fork gives the Settle / Un-settle row buttons visible text labels. Upstream 9b5d41687 instead wrapped the icon-only Un-settle button in a Tooltip. Keep the fork's labels; a tooltip on a labelled button is redundant. Upstream will keep editing that button — re-take ours.
Version-skew hint constant apps/web/src/versionSkew.test.ts Upstream hoisted the mismatch hint into a local MISMATCH_HINT const that reads "T3 Code". The fork's versionSkew.ts says "T3 Trade", so the constant is a new instance of the bucket-B rebrand seam and has to be re-pointed on every sync.
macOS signing hook scripts/build-desktop-artifact.ts Upstream 63eb0429f added a batched sign hook (scripts/sign-macos.ts) on the signed path. The fork does not sign; its afterPack ad-hoc hook and identity: null stay, and upstream's sign is kept on the signed branch so the seam stays a one-line ternary.
Model manifest URL apps/server/src/provider/ModelManifest.ts Upstream badae6a5c fetches legacy-model classification from raw.githubusercontent.com/pingdotgg/t3code, with a bundled copy as fallback. Added to ALLOWED_FILES in scripts/check-fork-independence.ts. Deferred: repointing needs the fork to host a manifest of its own.
.plans/ now gitignored .gitignore Upstream 9167622a4 moved its implementation plans out of the repo and added .plans/ to .gitignore. The fork's already-tracked plans (21–26) stay tracked, but a new plan file will not be picked up by git add without -f. Decide deliberately rather than by accident.
CI and Macroscope, again .github/workflows/**, .macroscope/** The modify/delete conflicts were resolved by keeping the deletions, and upstream's two newly added files (.github/workflows/desktop-macos-preview.yml, .macroscope/approvability.md) were deleted too. The fork has zero workflow files, so the CI perf commits (a3a8cbd60, 25dcee00a) had nothing to be ported into.
Lockfile pnpm-lock.yaml No package.json conflicted; the lock was regenerated with vp i.

Stale doc note

SYNC_RUNBOOK.md still points at .github/workflows/upstream-drift.yml as a weekly job. That workflow was deleted with the rest of .github/workflows/**; only scripts/upstream-drift.sh remains, and it has to be run by hand.

SYNC · v0.0.40 (f925d6394..09e8de9c6, 2026-09-09)

879 upstream commits in two --no-ff merges on sync/upstream-2026-09-07-09e8de9c6: batch A to v0.0.38 (152 commits, 34 conflicts), batch B to v0.0.40 (727 commits, 78 conflicts). Landed by local merge + direct push to main at the user's explicit instruction — recorded in BASELINE.md.

Migration renumber policy (exercised again)

Upstream id / name Fork id
044_ClearAutomaticProjectModelDefaults 095
045_ProjectionProjectsAutoPull 096
046_RepairAutomaticSettlementTimestamps 097
047_ProjectionProjectIcon 098
048_ProjectionThreadBranchPullRequest 099
049_ProjectionThreadsActiveOrderKey 100

The fork owns 035–094; the fork's migration ids now run 1–100. Pins rewritten: the three renamed tests' toMigrationInclusive bounds (45/46→96/97, 46/47→97/98, 48/49→99/100), their it.layer name strings, and the 016_CanonicalizeModelSelections.test.ts seed bound (43/44→94/95 — that test seeds through the full fork chain to reach upstream's 044, now 095). One renamed test also imports its migration file by path — rename that import or the suite fails with module-not-found.

Applied (the seams a future sync lands on again)

Seam File(s) Change
Server-side settlement apps/server/src/orchestration/{decider,ThreadSettlementPolicy,ThreadSettlementReactor}.ts Upstream moved settle eligibility server-side (thread.auto-settle, ThreadSettlementReactor sweep, resolveAutoSettlementAt returning the settledAt). Composed: upstream guards apply to thread.auto-settle ONLY; manual thread.settle keeps the fork's never-refuse + stop-first doctrine and now ALSO dismisses message-mode async questions (upstream's companion events) while still settling through approvals/native callbacks (the dismissal loop filters to responseMode: "message"). Mission exemption: resolveAutoSettlementAt takes missionActive; the reactor builds a thread-id set from TradingMissionProjection.list() per sweep — a thread bound to a non-terminal mission is never server-settled. Direct tests in all three files' suites.
NodeSqliteClient moved to shared apps/server/src/persistence/NodeSqliteClient.ts (deleted), 69 fork importers Rewrote every ../NodeSqliteClient.ts import to @t3tools/shared/nodeSqliteClient (API-identical, verified by export diff). No shim kept.
WSL runtime cache apps/desktop/src/wsl/DesktopWslEnvironment.ts Upstream's new runtime cache hardcodes $HOME/.t3/wsl-runtime inside the distro; fork-named to .t3trade/wsl-runtime with .t3trade-wsl-runtime-ready/selected markers (new code, no migration needed; prevents the two apps' cleanup from pruning each other's runtimes). The pre-existing t3code-wsl-node-pty.json prebuild marker stays upstream-named (deferred identifier).
Desktop schemes are fork-named apps/desktop/src/electron/ElectronProtocol.ts Corrected stale ledger row: the fork renamed URL schemes to t3trade/t3trade-dev on 2026-08-21 (8c821d2b0). Preserved through this sync; an upstream sync restoring t3code schemes is a regression.
New rebrand surface apps/web/src/connection/clientMetadata.ts (+test) Upstream's new clientPresentationMetadata labels ("T3 Code Desktop/Web") rebranded; platform.ts took upstream's structure wholesale.
Composer footer became teleport apps/web/src/components/chat/ChatComposer.tsx Upstream's footer is now an internal DOM node (data-chat-composer-footer-controls) with a resting-strip portal; missionControls/assetPicker re-mounted at the end of the footer controls div (footer-only visibility — they hide with the footer in resting state). Currently no caller passes them (dormant seam).
Sidebar rows re-architected apps/web/src/components/Sidebar.tsx Upstream routes every section through one renderThreadRowInner/SortableThreadRowBag; the mission join (missionByThreadKey) injects mission={...} there, now covering settled-tail rows too. Visible Settle/Un-settle labels kept (re-take ours on every sync). Upstream deleted the change-request row feature tree-wide — the fork's props went with it.
Timeline projection pipeline apps/web/src/components/chat/MessagesTimeline.tsx Wake rows' early-return moved BELOW upstream's new hooks in UserTimelineRow (conditional-hook rule); fork footerContent folded into timelineListFooter; fork's formatMcpToolCallDetail kept over upstream's JSON dump; WorkEntryCopyButton replaces MessageCopyButton in expanded bodies (base-ui Tooltip crashes react-test-renderer's node env).
MCP label prefix packages/client-runtime/src/work-log/presentation.ts The t3-code prefix regex now also strips t3-trade/t3_trade/t3trade — without it every fork MCP tool lost its friendly label (and one session-logic test).
Engine mock shape fork engine-mock tests OrchestrationEngineShape gained readThreadEvents, getThreadReplayStats (returns {eventCount, payloadBytes, hasCreateEvent}), subscribeDomainEvents (an Effect returning a Stream). Every fork test mock must carry them (handlers, TradingTurnCoordinator ×2, TradingWatchCoverageFloor, OrchestrationReactor lease test).
Effect suggestions gate repo-wide The patched tsgo exits 1 on ANY diagnostic. ~30 accumulated suggestions (fork drift + upstream's own new files) fixed in a dedicated post-merge commit; new code must keep the count at zero. docs/upstream/ stale wording updated: fork migrations now end at 100, next free id 101.
Marketing apps/marketing/** Fork pages kept whole (bucket A); upstream's 95.astro joke page + RetroBox/RetroIcon/retro.css/public/95 deleted (orphaned on the fork site, upstream-branded). site.ts keeps fork repo URLs plus upstream's MARKETING_STATS (now unreferenced — prune on the next pass if still unused).
Relay doc hostname docs/operations/connect-setup.md Upstream moved the OAuth callback doc here; fork hostname app.athelstan.xyz reapplied (app.t3.codes must never win where the fork replaced it).

Standing seam policy (2026-08-20)

apps/web/src/trading.css is fork-owned and upstream has no file by that name, so it can never conflict. Every new trading rule goes there; index.css is upstream's. The same rule holds for apps/web/src/components/trading/**, apps/server/src/trading/** and packages/trading-contracts/** — see "Where the fork's own code lives" in SYNC_RUNBOOK.md.

Drift is measured, not remembered: scripts/upstream-drift.sh reports the commit count and the merge-tree conflict forecast, and .github/workflows/upstream-drift.yml runs it weekly and opens one upstream-sync issue when either threshold is crossed.

INFRA REMOVAL · CI and Macroscope (2026-08-21)

The fork runs no GitHub Actions. Upstream ships 14 workflow definitions that run on Blacksmith runners, plus .macroscope/ check-run agent configs read by the macroscopeapp installation; both org apps are being removed.

Applied

Seam File(s) Change
Workflow definitions .github/workflows/** All 14 upstream workflows deleted (bdf852fa2) — every one ran on blacksmith-* runners. A sync restores them; delete again, or port selectively via the free-tier CI plan (PR #4).
Macroscope agents .macroscope/** Deleted. Inert once macroscopeapp is uninstalled; it exists only to instruct that app. A sync restores the directory — delete it again.

Z1 · Fork relay and hosted-app defaults (2026-08-29)

Upstream's relay rejected this fork's environments with not_authorized because nothing in code pointed a fresh build at the fork's own relay: the relay URL was pure configuration that failed closed when unset, the hosted app default still named upstream's deployment, and the channel router's host was a literal. The fork self-hosts its relay and web app, so the defaults are now the fork's own.

Applied

Date Seam File(s) Change
2026-08-29 Hosted app default packages/shared/src/connectAuth.ts DEFAULT_HOSTED_APP_URL repointed from https://app.t3.codes to https://app.athelstan.xyz. Sync patch: keep.
2026-08-29 Relay URL default packages/shared/src/connectAuth.ts, apps/server/src/cloud/publicConfig.ts, apps/web/src/cloud/publicConfig.ts New DEFAULT_RELAY_URL = "https://relay.athelstan.xyz", used as the final fallback in makeRelayUrlConfig (server) and resolveCloudPublicConfig (web). Precedence stays env var, then build-time value, then default; only the previously fail-closed case changes. Sync patch: keep.
2026-08-29 Channel router host apps/web/vercel.ts ROUTER_HOST and the latest/nightly channel origins now derive from VITE_HOSTED_APP_URL (visible to the config file at deploy time) with the fork's literal as fallback, replacing the three app.t3.codes literals.
2026-08-29 Example and doc hosts .env.example, docs/internals/t3-connect.md, docs/user/remote-access.md Hostnames repointed to the fork's relay and hosted app, so a fresh clone links against the fork rather than upstream.