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).
| 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. |
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 |
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. |
| 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). |
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.
| 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. |
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.
| 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. |
| 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. |
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. |
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.
| 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. |
| 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/.)
| 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/.)
| 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/.)
| 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.)
| 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. |
| 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. |
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 dispatchingtrading.mission.create. No trading command dispatch exists on the web today (apps/web/srchas the read path viauseTradingMissionForThreadbut zerotrading.mission.createwiring). - Trading timeline — render watch/run/inbox activity rows alongside chat messages, fed by the mission snapshot. The
TimelineEntrykind: "work"row insession-logic.tsis 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:44haspending = truehardcoded. - Mobile equivalents — React Native versions of the above in
apps/mobile/src/features/threads/; shared label/format helpers to move topackages/client-runtime.
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.
| 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. |
| 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. |
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.
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.
| 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. |
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.
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.
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.
| 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. |
| 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 |
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.
| 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. |
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@latest → npx ${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. |
| 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.css → apps/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. |
| 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. |
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.
| 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.
| 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. |
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.
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.
| 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.
| 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). |
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.
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.
| 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. |
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.
| 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. |