Spell the branch's slashes in the name a tab reads - #626
Conversation
`dl blooop/devlaunch@feature/auth` titled the terminal, the herdr tab and the container's prompt `devlaunch@feature-auth`. The flattening is the workspace *id*'s to do: an id is a devpod workspace name and a DNS label and can hold no slash. A tab is neither, and it was paying a cost that was never its own. What it cost was the one thing a tab is for: `feature/auth` and the different branch `feature-auth` are two workspaces with two ids, and both tabs said the same thing. `WorkspaceId::label` is the one derivation behind all three emitters, so the change is one place. `fit_ref` now takes the separator to write between the segments that survive its cut, and `parts_of` calls it twice -- once with `-` for the id, once with `/` for the label. Both separators are one character, so the budget, the middle segments dropped and the character the cut falls on are identical either way, which is what keeps a tab matchable by eye against a `dl --ls` row. The slash lands where the branch had one and nowhere else, because it comes from the segment split rather than from a pass over the finished id: a dash the slug made inside a segment stays a dash, so `dependabot/github_actions/x` labels as `dependabot/github-actions/x`. The golden id vectors are untouched and no workspace id, clone directory, hostname or devpod name moves. Claude-Session: https://claude.ai/code/session_015TVcYe8qh2n6Z5FxEyox4Z
`is_safe_name` constrains only the first character, so `feature/auth/` parses fine and reaches `label`. The comment claimed `validate_ref_name` refused it, and that claim was the only reason the case was missing from the assertion list. The label assertions pass on it unchanged -- the empty-segment filter was already doing the work the comment credited to the parse boundary. Claude-Session: https://claude.ai/code/session_015TVcYe8qh2n6Z5FxEyox4Z
The paragraph on where a slash lands published `dependabot/github_actions/codecov` labelling as `dependabot/github-actions/codecov`. With `devlaunch` -- the repo every other example in the same doc comment uses -- the ref has 32 characters of room and joins to 33, so `fit_ref` drops the middle segment and the real label is `devlaunch@dependabot/codecov`. The output named there needs a repo slug of eight characters or fewer, which the comment never said. The claim itself is true and stays: a dash `slug` made inside a segment stays a dash. Only the example moves, to the one the table in `a_label_is_the_id_with_the_suffix_off_and_its_separators_respelled` already pins, so the prose and its guard cannot drift apart. Claude-Session: https://claude.ai/code/session_015TVcYe8qh2n6Z5FxEyox4Z
The one place the change missed. `docs/workspaces.md`, `docs/workspace-tools.md` and the changelog all moved with the code; this line went on describing the tab as the id with "the dash before the branch spelled `@`", which is now half of what a label does. Nothing guards it -- `test_readme_cli_doc.py` reads the README for flags and the version, not for this prose -- so it drifted silently. Claude-Session: https://claude.ai/code/session_015TVcYe8qh2n6Z5FxEyox4Z
Reviewer's GuideWorkspace labels now preserve branch slashes using a parallel rendering derived from the same truncation and segment selection as the unchanged dashed workspace ID. Tests cover matching, truncation, slug-vs-separator behavior, shell safety, and all tab/title emission paths, while documentation and the changelog explain the distinction. Flow diagram for workspace ID and label renderingflowchart LR
Spec["owner/repo@ref"] --> Parts["parts_of"]
Parts --> FitId["fit_ref(..., ID_SEPARATOR)"]
Parts --> FitLabel["fit_ref(..., REF_SEPARATOR)"]
FitId --> ID["WorkspaceId::value\ndashes for separators"]
FitLabel --> Label["WorkspaceId::label\nslashes for ref separators"]
ID --> Addressed["devpod / hostname / dl --ls"]
Label --> Tabs["terminal title / herdr tab / PS1"]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="rust/devlaunch-core/src/domain/workspace_id.rs" line_range="533" />
<code_context>
struct Parts {
repo: String,
git_ref: String,
+ git_ref_read: String,
suffix: String,
}
</code_context>
<issue_to_address>
**nitpick:** The documentation immediately above `Parts` says that any of the three pieces can be empty, but `Parts` now carries four pieces after adding `git_ref_read`. That leaves the struct contract inaccurate and obscures that the readable ref copy has the same empty-state behavior as the id copy.
**Suggested fix:** Update the comment to describe the four fields, or explicitly distinguish the three id components from the additional readable-ref component.
```suggestion
/// Any of the three id components can be the empty string, which [`join`] drops rather than
```
</issue_to_address>| @@ -496,9 +532,17 @@ fn join_parts(parts: &Parts) -> String { | |||
| /// | |||
| /// Any of the three can be the empty string, which [`join`] drops rather than | |||
There was a problem hiding this comment.
nitpick: The documentation immediately above Parts says that any of the three pieces can be empty, but Parts now carries four pieces after adding git_ref_read. That leaves the struct contract inaccurate and obscures that the readable ref copy has the same empty-state behavior as the id copy.
Suggested fix: Update the comment to describe the four fields, or explicitly distinguish the three id components from the additional readable-ref component.
| /// Any of the three can be the empty string, which [`join`] drops rather than | |
| /// Any of the three id components can be the empty string, which [`join`] drops rather than |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
dl blooop/devlaunch@feature/authtitled the terminal, the herdr tab and thecontainer's prompt
devlaunch@feature-auth. The flattening is the workspaceid's to do, because an id is a devpod workspace name and a DNS label and can
hold no slash. A tab is neither, and it was paying a cost that was never its
own. What it cost was the one thing a tab is for:
feature/authand thedifferent branch
feature-authare two workspaces with two ids, and both tabssaid the same thing.
WorkspaceId::labelis the one derivation behind all four emitters (the OSC 2title,
herdr tab rename, the containerPS1line, and the tab namedlwritesbefore a launch resolves), so the change is one place.
fit_refnow takes theseparator to write between the segments that survive its cut, and
parts_ofcalls it twice: once with
-for the id, once with/for the label. Bothseparators are one character, so the budget, the middle segments dropped and the
character the cut falls on are identical either way, which is what keeps a tab
matchable by eye against a
dl --lsrow.The slash lands where the branch had one and nowhere else, because it comes from
the segment split rather than a pass over the finished id: a dash the slug made
inside a segment stays a dash, so
dependabot/github_actions/xlabels asdependabot/github-actions/x. The golden id vectors are untouched, and noworkspace id, clone directory, hostname or devpod name moves.
Reviewed in fresh context on three axes before the push. Defects and Types found
no correctness defect (the two-spellings invariant was brute-forced over ~1.6M
ref and budget combinations); the three commits after the first are what the
review found: a test comment that credited
validate_ref_namewith a guard itdoes not have, a
label()docstring example whose output that repo cannotproduce, and a README sentence the change had falsified.
🤖 Generated with Claude Code
Summary by Sourcery
Preserve branch separators in workspace labels so tabs and prompts distinguish branches without changing workspace IDs.
New Features:
Bug Fixes:
feature/authandfeature-auththat previously rendered identically.Enhancements:
Documentation:
Tests: