Finding
devpod's on-disk layout is knowledge with no module. clients/devpod.rs is the seam for devpod-the-command; devpod-the-filesystem has none, so the path is rebuilt wherever it is needed.
rust/devlaunch-core/src/flows/lifecycle.rs:2861 already claims otherwise — the paths go through shared helpers "so devpod's on-disk layout is spelled out in one place and not three". It is spelled in four:
flows/lifecycle.rs:2779 — contexts/<ctx>/workspaces/<id>/workspace.json
flows/lifecycle.rs:2799 — .../workspace_result.json
flows/lifecycle.rs:2859 — read_dir(devpod_home.join("contexts"))
flows/provision/verdict_cache.rs:322 — contexts/.../workspaces/.../workspace_result.json
And four more times in tests, each reproducing the convention literally: flows/launch.rs:3153, flows/lifecycle.rs:3159, flows/lifecycle.rs:3253, flows/provision.rs:4767.
The missing module has already cost real surface. Because a devpod-home builder had nowhere to live, lifecycle's test module was promoted to pub(crate) mod tests so two other flows could import a fixture from it:
flows/provision/verdict_cache.rs:313 — use crate::flows::lifecycle::tests::devpod_home_with;
flows/provision.rs:4746 — same fixture
A test fixture is part of the crate's internal surface because a module is missing.
Shape
A DevpodHome adapter under clients/, taking the home path rather than resolving it — the binary already resolves lifecycle::devpod_home() and hands it down (dl/src/commands.rs:718, with the reasoning in the comment there), so the convention exists.
DevpodHome::at(path)
.workspace(id) -> the workspace record
.result(id) -> the create result
.contexts() -> the context walk
.repoint(id, source)
repoint_devpod_source (lifecycle.rs:2936) writes into devpod's own JSON, and its doc already argues why (devpod v0.26.1 has no subcommand that changes an existing workspace's source). That is an adapter's job; it is currently sited in flows/.
Two adapters make the seam real: the real home in production, a temp-dir one for tests — which is what devpod_home_with already is, minus a home to live in.
Proving it
The red is the duplication itself: after the move, grep -rn '"contexts"' rust/devlaunch-core/src should match one module. And pub(crate) mod tests in lifecycle.rs should go back to mod tests, with nothing outside importing from it.
Found by an architecture review; the full write-up is in the review report, not in the repo.
Finding
devpod's on-disk layout is knowledge with no module.
clients/devpod.rsis the seam for devpod-the-command; devpod-the-filesystem has none, so the path is rebuilt wherever it is needed.rust/devlaunch-core/src/flows/lifecycle.rs:2861already claims otherwise — the paths go through shared helpers "so devpod's on-disk layout is spelled out in one place and not three". It is spelled in four:flows/lifecycle.rs:2779—contexts/<ctx>/workspaces/<id>/workspace.jsonflows/lifecycle.rs:2799—.../workspace_result.jsonflows/lifecycle.rs:2859—read_dir(devpod_home.join("contexts"))flows/provision/verdict_cache.rs:322—contexts/.../workspaces/.../workspace_result.jsonAnd four more times in tests, each reproducing the convention literally:
flows/launch.rs:3153,flows/lifecycle.rs:3159,flows/lifecycle.rs:3253,flows/provision.rs:4767.The missing module has already cost real surface. Because a devpod-home builder had nowhere to live,
lifecycle's test module was promoted topub(crate) mod testsso two other flows could import a fixture from it:flows/provision/verdict_cache.rs:313—use crate::flows::lifecycle::tests::devpod_home_with;flows/provision.rs:4746— same fixtureA test fixture is part of the crate's internal surface because a module is missing.
Shape
A
DevpodHomeadapter underclients/, taking the home path rather than resolving it — the binary already resolveslifecycle::devpod_home()and hands it down (dl/src/commands.rs:718, with the reasoning in the comment there), so the convention exists.repoint_devpod_source(lifecycle.rs:2936) writes into devpod's own JSON, and its doc already argues why (devpod v0.26.1 has no subcommand that changes an existing workspace's source). That is an adapter's job; it is currently sited inflows/.Two adapters make the seam real: the real home in production, a temp-dir one for tests — which is what
devpod_home_withalready is, minus a home to live in.Proving it
The red is the duplication itself: after the move,
grep -rn '"contexts"' rust/devlaunch-core/srcshould match one module. Andpub(crate) mod testsinlifecycle.rsshould go back tomod tests, with nothing outside importing from it.Found by an architecture review; the full write-up is in the review report, not in the repo.