Repository navigation
Widen the workspace-id budget to 47, one inside devpod's fatal 48 - #283
Conversation
Reviewer's GuideIncrease workspace-id maximum length from 38 to 47 characters (one below devpod’s hard 48-char limit), adjust truncation behavior and tests to keep more of long repo/ref segments while preserving uniqueness and hostname constraints, and document the new behavior in changelog and README. File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Self-reviewRead the diff back against the four things this change can get wrong. The cap itself is the only behavioural line. Suffixes must not move, and none did. Every changed golden value keeps its One test stopped testing what it says, and one nearly did. The invariant tests are all cap-relative, deliberately. Every length Nothing else in the tree encodes the old number. Decision recordedThe clone-directory leaf changes for long names, so an affected workspace gets a 🤖 Generated with Claude Code |
38 was never a limit anything enforced. Two limits are real underneath it: devpod rejects a 49-character `--id` outright (`workspace name cannot be longer than 48 characters`, verified against the pinned v0.26.1), and the container hostname is capped at 64 bytes, which devlaunch shares with downstream tooling that stacks its own prefixes onto the name (kinisi-robotics/kinisi_ros#9766 already sat at 62/64). 38 was devlaunch holding ten characters back for the second one. This spends nine of them on legibility and keeps one against devpod's wall. `kinisi_ros@ags-devcontainer-tooling-support` now reads `kinisi-ros-ags-devcontainer-tooling-su-lenevere` instead of losing the branch's tail, a dependabot ref keeps its whole action name, and ~17 characters are still there for whatever bolts itself onto the container name -- a caller that wants more is now the one that has to shorten. Nothing about uniqueness moves with this: the eight-character suffix is hashed over the full (owner, repo, ref) triple before any truncation, so the readable part is a legibility choice with no effect on the collision rate. That is why the golden tables' suffixes are untouched here while their values are not. The golden tables in both Rust modules are regenerated by `rust/golden_vectors.py` rather than hand-edited, which is the discipline that file exists for. `only_as_many_middle_segments_drop_as_needed` needed a bigger fixture in both languages: its 8-character segments now fit whole under the wider budget, so the test it was became "nothing drops", pinning nothing. It is now sized to the budget -- over by less than one segment, so exactly one middle has to go -- and the old fixture is kept as its opposite, `a_ref_that_fits_whole_keeps_every_segment`. Co-Authored-By: Claude <noreply@anthropic.com>
`the_first_and_last_segments_survive_heavy_truncation` claims the ends of a path-shaped ref survive however many middles have to go. With 30-character middles it was making that claim with a single character to spare under the wider budget: `aa-<30 n>-zz` is 36 against a 35-character ref budget, so one more character of cap would have quietly turned it into a test of dropping *one* middle, still green and no longer testing what it says. 40 each puts it far past the budget rather than just over it, in both languages, and the golden corpus moves with it because `rust/golden_vectors.py` is where the Rust table's inputs live. Co-Authored-By: Claude <noreply@anthropic.com>
e5167cb to
c8a0482
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #283 +/- ##
=======================================
Coverage 93.26% 93.26%
=======================================
Files 25 25
Lines 3774 3774
=======================================
Hits 3520 3520
Misses 254 254
🚀 New features to boost your workflow:
|
Main moved 43 commits and four releases (0.2.0 through 0.3.0) while this branch was being written, and two of those commits touch the same ground. Reconciled rather than re-applied, since main thought about one of them more carefully than this branch had. **The Rust toolchain in the pixi environment (#284) was already done, better.** This branch had added `rust` as a plain dependency; main added it as a *feature* carried only by `default`, so the py31x solves and their CI caches do not each drag in a 1.5GB toolchain, with the 521MB→2044MB disk trade written down. Main's design is kept and the plain dependency dropped; the collapse to one environment in this branch then removes the reason the feature had to be scoped at all, and its comment says so. One correction on top of it: the pin was `rust = "1.97.*"`, while AGENTS.md told a reader the environment is "pinned to the 1.97.1 that rust-toolchain.toml names". Those disagree the day 1.97.2 is published — silently, and only inside the container, which is the worst place for a toolchain difference to surface. Tightened to `1.97.1.*`, which is what the lockfile already held, so it costs no re-solve and makes main's own sentence true. `test_agents_doc.py` now reads the feature and holds the two to each other exactly. **Nothing was lost to the deletion.** The two Python modules main edited in that window were checked against their Rust counterparts before being removed: `workspace_id.py`'s `TARGET_LENGTH = 47` (#283) is `TARGET_LENGTH: usize = 47` in `domain/workspace_id.rs`, and `tools.py`'s `PIXI_HOME_TARGET = "$HOME/.devlaunch/pixi"` (#277) is `PIXI_HOME_EXPORT`/`PIXI_BIN_LINE`/`CLAUDE_SHIM_BIN_LINE` in `flows/provision.rs`, with byte-goldens pinning the rendered scripts. Both sides moved together, which is what the parity discipline was for. The rest was mechanical: main's `pixi.lock` is lock-file version 7, which needed a newer pixi than the container had, and the manifest's dependency changes here required a fresh solve (932 lines shorter, four environments gone). README keeps main's new paragraph about cargo needing no toolchain of your own — that one is about the crates, not about the Python build this branch ends. `test/unit/test_devcontainer_manifest.py` gained 333 lines on main and imported `tomli`, which this branch removes; it reads `tomllib` now, like its two siblings. Also, while re-reading the goldens that survive: the `PYTHON_*` constants in `flows/provision.rs` are named for where they were transcribed from, and that module is now gone. Kept under their names — what they pin did not change when their author left, and the name is the one thing still recording that nobody read them off the implementation they judge — with a note saying exactly that, and saying that there is nothing left to re-derive them from.
`the_repo_slug_floor_still_leaves_the_ref_room` asserted `room == 8`, which was 38 - 20 - 8 - 2 when it was written. #283 widened TARGET_LENGTH to 47 (one inside devpod's fatal 48), so the room the repo-slug floor leaves is 17, and the test failed on rebase asserting 8. The literal stays a literal. Deriving it from the same constants the line above already uses would assert nothing at all, and the failure is the ratchet working: a budget change should have to be acknowledged here rather than absorbed silently. The comment now says so, and records what the number was. Nothing else in the test needed touching -- the layout assertions below are written in terms of `room`, so they followed it. 65 tests in the module pass; clippy and fmt are clean.
#283 widened TARGET_LENGTH to 47, so the room fit_ref gets is 17, not the 8 it was at 38. The assertion moved with it; this sentence did not.
What
TARGET_LENGTHgoes from 38 to 47 — one character inside devpod's own ceiling of48 — in both
devlaunch/workspace_id.pyandrust/devlaunch-core/src/domain/workspace_id.rs.38 was devlaunch's own budget, not a limit anything enforced. Two limits under it
are real:
devpod up --id <49 chars>is rejected outright —fatal prepare workspace client: workspace name cannot be longer than 48 characters, verified against the pinned v0.26.1. Not a truncation: a launchthat does not happen.
workspace id, and downstream tooling stacks its own prefixes and suffixes onto
that (kinisi-robotics/kinisi_ros#9766 already sat at 62/64 with a 38-char id).
38 was ten characters held back for the second. This spends nine of them on
legibility and keeps one against devpod's wall, leaving ~17 for whatever bolts
itself on — so a caller that wants more is now the one that has to shorten.
Uniqueness does not move with this. The eight-character syllable suffix is hashed
over the full
(owner, repo, ref)triple before any truncation, so the readablepart is a legibility choice with no effect on the collision rate — which is why
every golden suffix here is untouched while the values are not.
What existing users see
dladdresses a workspace by the devpod idrecorded in
metadata.json(Build: persist the devpod workspace id instead of re-deriving it, and reconcile the orphans #88), and the recorded id wins over thederivation, so a workspace created under the old budget keeps opening the same
container.
dl <ws> rmand--ls --jsonlikewise resolve a record's clonethrough its recorded
local_path(The unsaved-work guard and the delete can name different directories #174).next launch (the launch path derives the leaf; the one-shot schema-2
migration has already run on these caches, so it does not re-run). The old
directory stays where it is and becomes one no record claims, which is what
dl --prunereports and offers to remove.That second point is the one thing worth a decision beyond this PR. See the
comment below.
Tests
Regenerated rather than hand-edited:
rust/golden_vectors.pyemits both goldentables (
workspace_id.rs,spec.rs), which is what that script exists for.only_as_many_middle_segments_drop_as_neededneeded a bigger fixture in bothlanguages: its 8-character segments now fit whole, so the test became "nothing
drops" and pinned nothing. It is now sized to the budget — over by less than one
segment, so exactly one middle has to go — and the old fixture is kept as its
opposite,
a_ref_that_fits_whole_keeps_every_segment.Run locally (rust via
pixi exec -s rust, which is not in the project env):cargo test -p devlaunch-core: 1138 passed, 3 failed — all threereal_git_*_lfs, ongit-lfs: not foundin this container, not this change.cargo test -p dl --lib --bins --test grammar --test launch --test migration --test lifecycle --test read_side: green (73 / 5 / 42 / 37 / 1).cargo clippy --all-targets -- -D warnings,cargo fmt --check: clean.pytest test: 1887 passed, 2 failed — bothtest_devcontainer_manifest.pyasserting
pixi task listoutput, pre-existing in this container and unrelated.🤖 Generated with Claude Code
Summary by Sourcery
Widen workspace ID generation to 47 characters so longer repository and branch names remain readable without exceeding devpod’s limit.
New Features:
Enhancements:
Documentation:
Tests: