…2413)
Closes #2396
Executes **option 2** from the investigation on #2396: remove the dead
chunked file-transfer subsystem end-to-end. The path has **never fired
in production** — no server code has ever dispatched `file_transfer` /
`cancel_transfer` commands to the agent, and nothing has called `POST
/remote/transfers` since the web FileManager moved to the system-tools
path (9379f17, Feb 2026); even before that, the create route only
inserted DB rows. The live transfer mechanism (single-shot
`file_read`/`file_write` via `systemTools/fileBrowser.ts`, plus PR
#2404's client-side abort) is untouched.
## Removed
**API**
- `routes/remote/transfers.ts` (all `/remote/transfers*` routes) +
`transfers.test.ts`
- `routes/remote/internal.ts` (its only route was the agent-facing
transfer-progress PATCH) and both mounts in `routes/remote/index.ts`
- `workers/transferCleanup.ts` + its init/stop wiring in `index.ts`
- `services/fileStorage.ts` (chunk save/assemble/stream helpers — no
remaining consumers)
- `createTransferSchema` / `listTransfersSchema` in
`routes/remote/schemas.ts`
- `getTransferWithOrgCheck` + `MAX_ACTIVE_TRANSFERS_PER_*` in
`routes/remote/helpers.ts`; `hasSessionOrTransferOwnership` renamed to
`hasSessionOwnership` (session paths keep using it)
- openapi: `FileTransfer` component schema + `/remote/transfers*` paths
- `EVENT_TYPES.REMOTE_FILE_TRANSFERRED` (`remote.file.transferred` —
never emitted) and the transfer chunk-upload carve-out in
`middleware/bodyLimit.ts`
- Stale "use file transfer for larger files" copy in
`systemTools/schemas.ts`, `aiToolsFilesystem.ts`, and `bodyLimit.ts` —
that alternative no longer exists (and never worked)
**Agent**
- `agent/internal/filetransfer/` package (incl. its tests; PR #2391's
fix is deleted with it — expected)
- `handleFileTransfer` / `handleCancelTransfer` + registry entries in
`heartbeat/handlers_desktop.go`
- `CmdFileTransfer` / `CmdCancelTransfer` in `remote/tools/types.go`
- `fileTransferMgr` field, `ftConfig` plumbing, and failover
`SetServerURL` propagation in `heartbeat/heartbeat.go` (token init kept
for the helper manager, renamed `ftToken` → `secToken`)
**DB**
- Migration `2026-07-12-drop-file-transfers.sql`: idempotent `DROP TABLE
IF EXISTS file_transfers` + drops the two orphaned enum types. Per the
forensic-trail rule it logs `RAISE WARNING 'dropping file_transfers with
% rows'` before the drop. **The drop is destructive, but the data is
dead**: rows (if any) are inert metadata from the never-functional
feature — nothing could ever read or act on them.
- `fileTransfers` table +
`file_transfer_direction`/`file_transfer_status` enums removed from
`db/schema/remote.ts`
**Registration lists** (`file_transfers` removed from all three)
- `DEVICE_ID_JOIN_POLICY_TABLES` in `rls-coverage.integration.test.ts`
- device cascade-delete list in `routes/devices/core.ts` +
`INTENTIONALLY_NO_ORG_ID` in `moveOrg.coverage.test.ts`
- site-scope exempt lists in `site-scope-coverage.integration.test.ts`
**Config/docs**
- `TRANSFER_STORAGE_PATH` / `MAX_TRANSFER_SIZE_MB` /
`MAX_ACTIVE_TRANSFERS_PER_*` removed from `.env.example`,
`docker-compose.yml`, `deploy/docker-compose.prod.yml`, and the env docs
(droplets may keep a stray empty `data/transfers` dir; harmless)
- Docs: transfer API sections removed from `features/remote-access.mdx`,
`reference/api.mdx`, `agents/commands.mdx`, `features/webhooks.mdx`,
`docs/architecture.md`
- `docsIndex.json` regenerated via `scripts/build-docs-index.ts` — note
the checked-in index was stale, so the refresh also picks up docs pages
added since it was last built (generated file)
## Intentionally untouched
The `remote_session_type` enum value `'file_transfer'` and everything
typed on it (`remote_sessions`, `SessionHistory.tsx`,
`aiToolsRemote.ts`, `REMOTE_SESSION_TYPES`) — remote *sessions* typed
`file_transfer` are a separate, live concept, and PG enum values can't
be dropped safely anyway. `systemTools/fileBrowser.ts` and the
FileManager UI are also untouched.
## Verification
- Migration applied to a fresh scratch DB: table + enum types gone,
ledger row recorded, `db:check-drift` green (396 files match); the
forensic `WARNING: dropping file_transfers with 0 rows` fired
- RLS coverage contract test run against a real Postgres **with the
table actually dropped**: 53 passed
- Site-scope coverage contract: 7 passed; moveOrg coverage +
remote/sessions/bodyLimit/systemTools suites: green
- `cd agent && go test -race ./...` green; `GOOS=windows` and
`GOOS=linux` builds green
- `tsc --noEmit` clean for api, web, shared; `@breeze/shared` tests 1078
passed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Todd Hebebrand <todd@lanternops.io>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Summary
filetransfer.Manager.transfersadded an entry per transfer and never removed one — nodelete(call existed anywhere in the package. TheManageris owned by the process-lifetimeHeartbeatsingleton, so the map grew unbounded for the life of the agent (#2388).Fix
Simpler than the reaper proposed in the issue: nothing ever reads a transfer back after it reaches terminal state — the only map reader is
CancelTransfer, which needs the entry only while the transfer is in flight (the upload/download loops polltransfer.Statusthrough the shared pointer). SoHandleTransfernow defer-deletes its map entry on return, covering success, failure, and cancelled paths. A late cancel arriving after removal hits the existing not-found no-op branch inCancelTransfer(covered byTestCancelTransferNonexistentIsNoop). No timestamp field orseenCommands-style reaper needed.Also fixed a latent data race in the same file:
HandleTransfer/upload/downloadwrotetransfer.Status/transfer.Progress/transfer.Errorwithout holdingm.mu, whileCancelTransferand the in-flight cancellation checks used the mutex. Writes are now guarded, andreportProgresssnapshots the mutable fields underRLock.Tests
assertNoTransfershelper assertslen(m.transfers) == 0afterHandleTransferreturns in upload-success, download-success, upload-failure, download-failure, andTestConcurrentHandleTransfer.TestCancelTransferSetsStatus(mid-flight cancel semantics — entry exists while in flight) still passes unchanged.cd agent && go test -race ./internal/filetransfer/...— ok;gofmt -lclean.Closes #2388
🤖 Generated with Claude Code