main.rs declared nearly every module itself (mod ai; mod database; …), and lib.rs declared the same modules as pub mod. Rust treats those as two separate crates, so:
every build compiled the ~100k-line crate twice: once as the library (for the src/bin tools) and once as the server binary
cargo test ran most tests twice, as the 749 + 841 result blocks
watcher.rs, compiled as part of the binary, reached into the library's copy through image_api::
Change
The six modules only the binary had (backfill, handlers, hls_stats, knowledge, reels, watcher) move into lib.rs.
main.rs keeps only the startup wiring, using image_api::….
Three items the binary calls become pub: RealFileSystem::new and the two reel spawners.
Four dead_code allowances that existed only because each copy saw half the callers are removed. Clippy stays clean.
CLAUDE.md now says not to add mod declarations to main.rs.
Log targets are unchanged (image_api::watcher and so on), because the binary's crate name was already image_api.
Build times
Release builds of --bin image-api with nice -n 19 -j 3. Absolute numbers are inflated; compare relative changes.
before
after
warm rebuild, lto = "thin"
195s
156s (−20%)
warm rebuild, lto = "off"
126s
78s (−38%)
cold build, lto = "thin"
353s
299s
warm rebuild, all 14 bins (old deploy.sh)
459s
437s
With thin LTO the link step is now most of a rebuild. Turning LTO off would halve the deploy rebuild again, but at an unmeasured runtime cost; I left it as thin for now.
Testing
cargo test: 860 passed, each test now runs once.
cargo clippy --all-targets and cargo fmt --check are clean.
Smoke test: started the server built from this branch on port 8093 against a copy of the e2e state. The e2e date check passed (97/97), and the watcher and reel jobs started with no errors.
## Problem
`main.rs` declared nearly every module itself (`mod ai; mod database; …`), and `lib.rs` declared the same modules as `pub mod`. Rust treats those as two separate crates, so:
- every build compiled the ~100k-line crate twice: once as the library (for the `src/bin` tools) and once as the server binary
- `cargo test` ran most tests twice, as the 749 + 841 result blocks
- `watcher.rs`, compiled as part of the binary, reached into the library's copy through `image_api::`
## Change
- The six modules only the binary had (`backfill`, `handlers`, `hls_stats`, `knowledge`, `reels`, `watcher`) move into `lib.rs`.
- `main.rs` keeps only the startup wiring, using `image_api::…`.
- Three items the binary calls become `pub`: `RealFileSystem::new` and the two reel spawners.
- Four `dead_code` allowances that existed only because each copy saw half the callers are removed. Clippy stays clean.
- CLAUDE.md now says not to add `mod` declarations to `main.rs`.
Log targets are unchanged (`image_api::watcher` and so on), because the binary's crate name was already `image_api`.
## Build times
Release builds of `--bin image-api` with `nice -n 19 -j 3`. Absolute numbers are inflated; compare relative changes.
| | before | after |
|---|---|---|
| warm rebuild, `lto = "thin"` | 195s | **156s** (−20%) |
| warm rebuild, `lto = "off"` | 126s | **78s** (−38%) |
| cold build, `lto = "thin"` | 353s | 299s |
| warm rebuild, all 14 bins (old deploy.sh) | 459s | 437s |
With thin LTO the link step is now most of a rebuild. Turning LTO off would halve the deploy rebuild again, but at an unmeasured runtime cost; I left it as `thin` for now.
## Testing
- `cargo test`: **860 passed**, each test now runs once.
- `cargo clippy --all-targets` and `cargo fmt --check` are clean.
- Smoke test: started the server built from this branch on port 8093 against a copy of the e2e state. The e2e date check passed (97/97), and the watcher and reel jobs started with no errors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
main.rs re-declared nearly every module (`mod ai; mod database; …`)
that lib.rs also declared, so the ~100k-line crate compiled twice in
every build (lib for the src/bin tools, bin for the server) and the
test suite ran most tests twice. watcher.rs even reached into the lib
copy via `image_api::` from inside the bin copy.
The six bin-only modules (backfill, handlers, hls_stats, knowledge,
reels, watcher) move into lib.rs; main.rs keeps only startup wiring
over `use image_api::…`. A few items main calls become `pub`, and the
dead_code allowances that only existed because each copy saw half the
callers are gone. CLAUDE.md says not to reintroduce `mod` in main.rs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
main.rsdeclared nearly every module itself (mod ai; mod database; …), andlib.rsdeclared the same modules aspub mod. Rust treats those as two separate crates, so:src/bintools) and once as the server binarycargo testran most tests twice, as the 749 + 841 result blockswatcher.rs, compiled as part of the binary, reached into the library's copy throughimage_api::Change
backfill,handlers,hls_stats,knowledge,reels,watcher) move intolib.rs.main.rskeeps only the startup wiring, usingimage_api::….pub:RealFileSystem::newand the two reel spawners.dead_codeallowances that existed only because each copy saw half the callers are removed. Clippy stays clean.moddeclarations tomain.rs.Log targets are unchanged (
image_api::watcherand so on), because the binary's crate name was alreadyimage_api.Build times
Release builds of
--bin image-apiwithnice -n 19 -j 3. Absolute numbers are inflated; compare relative changes.lto = "thin"lto = "off"lto = "thin"With thin LTO the link step is now most of a rebuild. Turning LTO off would halve the deploy rebuild again, but at an unmeasured runtime cost; I left it as
thinfor now.Testing
cargo test: 860 passed, each test now runs once.cargo clippy --all-targetsandcargo fmt --checkare clean.🤖 Generated with Claude Code
2e207c5fa0to640cd3833a