# Decomposing core/src/pds.js **Status:** complete. Fourteen clusters moved and three helper modules extracted, 1,337 lines left in `pds.js` from 10,205. What stays in the class is the dispatch pipeline, authentication, and the commit and blob machinery. The static route table is empty; every route comes from a handler module. Read `CLAUDE.md` first for the conventions this follows. This file is the record: what moved, what each move needed, and the mistakes that cost time. A second phase followed. The feature routes that `handlers/account.js` held for git, drive, sites, spaces, OCI and npm moved into those packages, each mounted through the extension seam described in [architecture.md](architecture.md#extensions), along with the per-feature constructor options that wired them. The table below is the snapshot at the end of the first phase; `account.js` has since lost those routes and the adapters their feature construction. ## Where it stands | module | lines | statements | branches | functions | | --- | --- | --- | --- | --- | | `handlers/account.js` | 2,998 | 88.4 | 74.6 | 96.5 | | `handlers/oauth.js` | 1,682 | 83.7 | 73.8 | 100 | | `handlers/xrpc-server.js` | 1,036 | 98.0 | 94.3 | 95.0 | | `handlers/xrpc-repo.js` | 810 | 89.2 | 80.0 | 100 | | `handlers/xrpc-identity.js` | 679 | 95.3 | 82.9 | 100 | | `handlers/account-backup.js` | 535 | 97.5 | 90.3 | 100 | | `handlers/migration.js` | 356 | 96.6 | 83.9 | 84.6 | | `handlers/xrpc-sync.js` | 312 | 95.7 | 79.4 | 100 | | `handlers/server-meta.js` | 252 | 100 | 100 | 100 | | `handlers/xrpc-blob.js` | 189 | 100 | 100 | 100 | | `handlers/xrpc-firehose.js` | 155 | 100 | 86.1 | 100 | | `handlers/xrpc-preferences.js` | 81 | 100 | 100 | 100 | | `session.js` | 331 | 96.4 | 84.2 | 100 | | `proxy.js` | 282 | 98.8 | 96.9 | 100 | | `http.js` | 103 | 92.6 | 88.9 | 100 | | `passkey.js` | 85 | 100 | 80.0 | 100 | Repo-wide statements are 78.1%, from 59.87% at the start. The unit suite is 1,318 tests, up from 941. `proxy.js`, `session.js`, `http.js` and `passkey.js` are not under `handlers/` because they contribute no routes. Name a module for what it knows when that is true, and put it in `core/src`. ## What each cluster needs before it moves Two numbers decide the work, and they are not correlated. Coverage under the unit suite against coverage with a `PLATFORM=node` e2e run says where the untested code is. The count of instance members a cluster reaches says how much of a seam it has. `xrpc-blob` was 0% covered and reached six members. The account surface reaches forty-seven. Measure both before starting. The commands are in the commits; the shape is: ``` awk 'NR>=LO && NR