# M2b task 08: `loopd serve` **Branch:** `m2b` (run `git switch m2b`; `git status --short` must be empty, otherwise stop) **Commit subject:** `Add the loopd serve command` ## Goal The command that runs the harness: self-test, then the channel server. It refuses to start if the self-test fails. ## Files - Copy: `crates/loopd/tests/serve.rs` - Modify: `crates/loopd/src/main.rs`, `docs/implementer-log.md` ## What `loopd serve --config ` does, in order 1. Load the config; on failure print `loopd: ` and exit 1. 2. Work out the socket path with `cfg.channel_socket()`. If a socket file is already there, remove it **now**, before the self-test, so that a client sees "not running" rather than "connection refused" while the self-test runs. 3. Run the self-test exactly as `loopd selftest` does, printing the same lines. On failure exit 1 without binding anything. 4. Create the socket's parent directory, bind, set the socket file's mode to 0600, print `loopd: serving on `, and call `channel::serve` with a `Context` made of the config, the client, `Box::new(FakeTools::new())` and `Registry::m2b()`. `loopd selftest --config ` keeps working as before. Anything else prints the usage for both commands and exits 2. ## Steps - [ ] **1. Copy.** `git switch m2b`, then `cp docs/plans/M2b/files/crates/loopd/tests/serve.rs crates/loopd/tests/` - [ ] **2. See the test fail.** `cargo test -p loopd --test serve`. Expected: all 3 fail, because `serve` is not a command yet. - [ ] **3. Rewrite `main.rs`.** Keep the `selftest` command. Run `cargo fmt --all`. - [ ] **4. See the tests pass.** `cargo test -p loopd --test serve`. Expected: `3 passed`. - [ ] **5. Run the gate.** `make gate`. Expected last line: `gate: ok`. - [ ] **6. Log and commit.** `git add crates/loopd docs/implementer-log.md && git commit` ## Done when - `cargo test -p loopd --test serve` reports 3 passed; `make gate` prints `gate: ok`. ## Stop and report if - The socket cannot be given mode 0600 with `std::fs::set_permissions`.