feat(herdr): show the custom sidebar data in the phone layout - #29
Merged
Merged
Conversation
Herdr's single-column mobile layout ignores the custom sidebar rows. The herdr-spaces reporter now also writes a compact form of the same data into the fields that layout shows: agent state labels carry each home's counts and alert plus every agent's pull request line, a home agent's display agent carries its session topic, and the machine workspace's tab carries the machine's shares. Firstmate's own display agent, workspace labels and tab names are never written. The desktop sidebar is unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
"this shit is missing my custom herdr sidebar" (on the phone, over mosh)
"also i want the mobile ui navigation back, i can't see the chat at all"
"keep both"
"i want custom + the navigation"
"just make sure it keeps this look"
Context for reading those asks: Code-Factory renders a custom Herdr sidebar from
ansible/templates/herdr.toml.j2([ui.sidebar.spaces]and[ui.sidebar.agents]rows). Its tokens are fed bymaintenance/herdr-spaces.py(workspace tokens:$machine/$hostbox stats,$decisions,$crew,$queue,$res,$alert) and by the omp extensionconfig/herdr-sidebar.ts(pane tokens:$pr,$issue,$add,$del,$files, plus the terminal title). On a phone in portrait (about 50 columns, at or below Herdr's[ui] mobile_width_threshold, default 64), Herdr 0.9.3 switches to its single-column mobile layout. That layout has the navigation and full-width chat the user wants, but per Herdr's docs it "keeps its compact layout" and ignores the custom sidebar rows. Its entries show only fixed fields. Spaces:Local · <workspace label>, then a second line such asshell · tab 1. Agents:Local · <workspace label>, then<tab> · <state> · <display agent>, for example1 · working · omp. Raising the threshold brought the custom sidebar back but lost the mobile navigation and the chat, so the user wants both: the mobile layout, with the custom sidebar data visible inside it."This look" is the user's current desktop custom sidebar: the whole-machine box stats line first (CPU, RAM and disk); then each home as its own entry with its colored short name, its queue count (◷) and its per-home CPU, RAM and disk (⚙ ▤ ⛁) line; then the agents, grouped by home, each shown by its home's short name with its session/task title below. The desktop sidebar must stay exactly as it is.
What Changed
maintenance/herdr-spaces.pynow also writes the sidebar data into the fields Herdr's single-column mobile layout shows. That layout ignores the custom sidebar rows. Each agent pane gets its session topic as the display agent. Its state labels (idle,working,done,unknown;blockedkeeps Herdr's own word) carry the compact data, with glyphs unspaced and parts single-spaced. A home's own agent shows the home's counts, CPU/RAM/disk shares, a[WARN]watcherflag and the pull request line. Any other agent shows its pull request line. Both are written throughherdr pane report-metadata. The reporter also clears the labels when the data is empty.machineworkspace's first tab is pinned by tab id and renamed to the machine's CPU/RAM/disk shares, so the phone'smachineSpace line shows them. It is renamed at most every 30 seconds (TAB_TTL). It is renamed only while its label is still Herdr's own number or the reporter's last text, so an operator-chosen name is left alone. Desktop sidebar rows, tokens andherdr.toml.j2are not touched.docs/herdr.mdgains an "On a phone" section. It covers what each Space and Agent entry shows, the tab-rename rules, and the limits of the mobile layout. Theherdr-spaces.service.j2comment is updated to match.tests/test_herdr_sidebar.pyadds cases for the mobile reports (same data, settling, following a changed pane) and for the pinned, throttled machine tab. It also adds a parametrized shares test.Risk Assessment
Testing
The 74 targeted pytest cases passed, as unit-level evidence only. I drove the reporter live against isolated real Herdr servers. The 50-column mobile switch menu shows each home's
◷ ⚙ ▤ ⛁counts, pull request line and title in the extension's real token forms. The machine tab is pinned, throttled to 30 s and never overwrites an operator-named label. The agent-exit guard clears the reporter's metadata, while an unguarded control write survives. The reporter makes no writes when nothing changes, and the CPU label rises and falls with therestoken. The A/B comparison of the base and target reporters showed identical desktop sidebar columns apart from live host digits. The left-out issue is documented, and the border-label effect could not be observed in the fixture. All disposable servers and files were torn down and the worktree is clean.◷3 ⚙0% ▤0% ⛁0% ⎇1537 +12847 −3902 ✎214 · Plann…and◷1 ⚙0% ▤0% ⛁0% +84 −12 ✎3 · Fix ratings screen○ 1529) seeded on a home pane shows on the desktop agent row but is left out of the mobile entry, and docs/herdr.md lists that as a forced difference⎇ 1537 · ○ 1529 · +12847 · −3902 · ✎ 214) vs 15-mobile-machine-switch.png (no○); 14-per-home-cpu-change.txt last line; docs/herdr.md:193 `The issue (○) is left out…machineworkspace's pinned first tab, in both the Space entry and the tabs listshell · tab ⚙31% ▤28% ⛁71%and1 · ⚙31% ▤28% ⛁71%); 13-fresh-install-tab-and-idempotence.txt▤28% ⛁71%, then unchanged, then⚙13% ▤28% ⛁71%after 31 s. A fresh install shows a CPU-less machine tab for up to 30 s (informational).htop) is left alone after the throttle expires, and a second focused tab is never renamedhtopkept,w3:t2stays2w1:t1andw2:t1stay1pane report-metadatacall and no tab renamerestoken, and on the first run after the process exits it returns to ⚙0%…res ⚙ 12%↔label ⚙12%, thenres ⚙ 0%↔label ⚙0%on the first post-exit run and the two runs after itrelease-agent; controldisplay_agent="stale topic"survived. This run used a hand-seeded+84token, which does not affect the guard.whotoken) keeps the orchestrator's display agent, and its real-form pull request parts go to the state labels└ fix-token-raceunchanged; state labels⎇1540 +5 −1 ✎2herdr.toml.j2, base reporter cdd9549 then target 5fc8fb5,firstmatefocusedomp(decision C)herdr.toml.j2(show_agent_labels_on_pane_borders = true) at 120 columns, with panes whose agent was reported throughpane report-agent. Herdr dre…Evidence: Mobile captures as text (home and machine focus)
Evidence: A/B desktop sidebar: base reporter vs target reporter at 120 columns, with raw and digit-masked column diffs
Evidence: Fresh-install tab (CPU-less for up to 30 s) and six-run idempotence
Evidence: Per-home CPU rise and fall: `res` token vs phone label at each step, and the issue left out of the mobile label
Evidence: Machine-tab adversarial scenarios A-F
Evidence: Agent-exit guard with unguarded control
Evidence: Worker pane with real prParts tokens
Evidence: Topic follows a rename; 80-character cap; idempotent re-run
Evidence: Reporter with no herdr server: exit 0
Evidence: Targeted pytest run (unit evidence, not a live scenario)
Author's before/after captures
Captured from a throwaway Herdr 0.9.3 session (never the live session), through a real client attached in a 50-column and a 120-column terminal. "Before" ran the reporter from
main; "after" ran this branch's reporter. Fixture: workspacesmachine, a primary home (labelfirstmate) with its own agent plus a worker tab whose display agent the orchestrator set to└ fix-token-race, and a second-level home2ndmate-webapp-mate-s4, with the pane tokens the omp extension reports.Phone, 50 columns, switch menu: before
Phone, 50 columns, switch menu: after
Desktop, 120 columns, sidebar (first 46 columns)
Before and after differ only in the live CPU number on the machine line (
⌂ ⚙ 10%before,⌂ ⚙ 8%after, sampled seconds apart); every other line is identical. After:Also checked in the same session: a
machinetab renamed by hand (htop) was left alone by the next run, and once an agent is released from a pane its display agent and state labels no longer show.Compared with the desktop look: differences the mobile layout forces
machinespace entry.Local ·prefix (2ndmate-webapp-mate-s4, notwebapp), and no colors: these fields are plain text.⚙ ▤ ⛁shares share one line with its pull request line and topic; Herdr cuts the end with…, so the topic or worker name is often cut at 50 columns.working); the state dot still shows the state.shell · tab Nline: home tab names are matched by label elsewhere, so they are never renamed. The issue (○) is left out for width. Without amachineworkspace, the machine shares do not show on a phone.omp, and themachinetab shows the shares in the tab bar whilemachineis focused. The sidebar itself is unchanged.Lean review verdict (one round)
machine_tabcache". The reporter runs every second; without it the tab would be renamed every second. The review gate later tightened this to one pinned tab, a 30-second throttle, and never overwriting a label the reporter did not write.tight()into two named steps". The review itself marks it no line savings, flag only.Pipeline
Updates from git push no-mistakes
... (19 earlier update rounds omitted to keep the PR body within GitHub's 65536-char limit; full history is in the run log.)
Source evidence, Herdr v0.9.3 (the installed binary;
src/terminal/metadata.rsis identical to main):TerminalState::set_agent_metadatatakes theelsebranch when no clear flag is set.self.agent_metadata.insert(report.source, AgentMetadata{ display_agent: report.display_agent, state_labels: report.state_labels, .. }).code-factory:spacesrecord, so any field absent from the report is dropped.--clear-*branch is the only one that patches.--agentand--applies-to-sourceare unset here, so no other source supplies these fields on a home pane. The omp extensions never write them.Failing sequence for a home pane (one with a
whotoken), starting from the correct state{display_agent: "Topic A", state_labels: T1}:+84becomes+90), or the topic changes. These are routine.--state-label. The report replaces the record with{labels: T2}and the display agent is gone.display_agentis now None, so line 402 sends--display-agentalone. The record becomes{display_agent}and the labels are gone.The two fields are never both missing in the same tick, so it never converges. The phone's switch menu alternates between losing the counts and losing the topic. Herdr gets one subprocess and one metadata event per home pane per second. The tests miss it because the static stub neither models Herdr's replace semantics nor runs twice. The only home-pane case it covers (
w1:p2) has both fields stale, which sends them together.Fix at the single report site (lines 391-418): compute the desired display agent and labels together. If either differs, send both in the same call:
--display-agentwhen there is a title, and either the labels or--clear-state-labels. Sending both is safe.--clear-state-labelsputs Herdr in patch mode, so a display agent sent alongside it is kept.Sites that must follow the same rule:
report-metadatacall that must carry the full set.The workspace token reports (line 380-384) and the omp extension's token-only pane reports patch independently, so they are not affected. Add a regression test using a stateful stub that applies the replace-per-source semantic. Fixture: a
whopane with a matching display agent and stale labels. Runmain()repeatedly and assert the second run sends nothing.maintenance/herdr-spaces.py:397- The mobile layout does not carry all of the stated "look". The intent says each home should be its own entry with "its colored short name, its queue count (◷) and its per-home CPU, RAM and disk (⚙ ▤ ⛁) line". It also says agents should show "by its home's short name". The change deliberately drops these, and docs/herdr.md:174-190 admits it:resstays desktop-only).shell · tab 1line.whopane.machineworkspace exists.The author's reason is the 50-column width. Whether dropping per-home shares, short names and the home's Space-entry data is acceptable is a product decision. Adding them back, for example in a trimmed topic or another field, changes the design. The remedy needs authorization, not the defect.
maintenance/herdr-spaces.py:373- The reporter overwrites a user-visible tab name (herdr tab rename) every time the machine line changes. That rename policy needs a decision. The rename is real: Herdr's mobile Space line is<branch|shell> · tab {active tab label}(src/client/shell/mobile.rs,compact_tab_status). The side effects:tab rename, a persistent session change, fires about once a second. docs/herdr.md:191 says it renames "only when its text changes", which is true but understates this.active_tab_id. If an operator opens a second tab inmachineand focuses it, that tab's name is overwritten within a second. The first tab keeps its last shares text as a stale label. docs/herdr.md:181 says "the orchestrator never names that tab", but operators can.machineis focused (admitted at docs/herdr.md:191).Pinning one tab, restoring labels, dropping the rename, or throttling it are each product choices, so the remedy needs authorization.
maintenance/herdr-spaces.py:402- Setting the home pane's--display-agentto the session topic changes the desktop pane border, and docs/herdr.md says otherwise. The doc says none of these fields shows on the desktop except the renamed tab. That is accurate for the sidebar: config/default.yml uses onlystate_icon,$whoandterminal_title.It is not accurate for pane borders.
TerminalState::border_label(show_agent_labels)in Herdrsrc/terminal/state.rsfalls back toeffective_display_agent(). This repo setsshow_agent_labels_on_pane_borders = true(ansible/group_vars/all.yml:198, rendered at ansible/templates/herdr.toml.j2:21).Sequence: a home omp pane is in a split. Its border label was
ompand becomes the session topic, changing on every rename. The intent says the desktop "sidebar must stay exactly as it is". Borders are not the sidebar, but this is a desktop-visible change nobody has approved. Either accept it and document it, or avoid the display-agent write. That is a product decision about the desktop look.maintenance/herdr-spaces.py:417- The pane reports omit--agent, so the topic and counts this script writes stay on a pane after its agent exits. The script never cleans them up itself. Unlike the other findings, this is a source-proven defect with a small remedy.Sequence: a home omp pane (
whotoken set) gets--display-agent <topic>and state labels from this script. The user quits omp, or the extension clearswhoon session shutdown.pane.get("agent")is now falsy, so the loop hitscontinue(theif not pane.get("agent")check, ~line 392) and the pane is never visited again.Herdr keeps the record. In v0.9.3,
set_agent_metadatastoresagent_label = Nonefor a report without--agent.metadata_guards_match(src/terminal/metadata.rs) only hides metadata whoseagent_labelis set and no longer equalseffective_agent_label(). The exit handler (src/terminal/state.rs:573-583) only clears metadata whoseagent_labelequals the exited agent.metadata_report_blocked_by_process_exitlikewise only blocks--agent-tagged reports. So this source's record is never hidden or cleared.Result:
pane listkeeps returning the olddisplay_agentandstate_labels.border_label(state.rs, ~line 2409) falls back toeffective_display_agent()whileshow_agent_labels_on_pane_bordersis true (ansible/group_vars/all.yml:198). So a split shell pane shows the dead session's topic on its desktop border indefinitely.Same class, sibling sites, all using the same report call at line 417:
--display-agentwith no guard.--state-labelwith no guard.--clear-state-labelswith no guard.who(sotitlebecomes "") keeps its olddisplay_agent. Thetitle and ...test at ~line 409 skips it, and the replace-style report at line 412 only fires when the labels also differ.Fix at the shared boundary: add
--agent <pane["agent"]>to every report at line 417. I confirmed from Herdr's source that--agentonreport-metadatais only a guard.set_agent_metadatastores it,metadata_guards_matchhides the record when the pane's agent differs, and the process-exit handler clears it. It does not claim or relabel the pane.Idempotence is unaffected:
pane list'sagentiseffective_agent_label(), the same value the guard compares against.Update the stub arguments in
tests/test_herdr_sidebar.py(test_mobile_layout_carries_the_same_data,test_mobile_reports_settle_and_follow_a_changed_pane, and thew3:p4/w3:p8expectations).maintenance/herdr-spaces.py:402- The mobile layout does not carry all of "this look". The intent says each home is "its own entry with its colored short name, its queue count (◷) and its per-home CPU, RAM and disk (⚙ ▤ ⛁) line", and that agents show "by its home's short name". The change drops several of these, and docs/herdr.md ("What the mobile layout forces") admits it:restoken stays desktop-only.shell · tab 1line.whopane.machineworkspace exists.The author's reason is the 50-column width. I confirmed in Herdr's mobile.rs that the Agent line is
[tab] · state label · display agentand the Space line is Herdr-built, so some limits are real. Whether dropping per-home shares and the home Space-entry data is acceptable is a product decision. Adding them back (another field, or a trimmed topic) would change the design, so the remedy needs authorization, not the defect.maintenance/herdr-spaces.py:371- The reporter renames themachineworkspace's active tab, a persistent and user-visible tab name, whenever the shares text changes. The remedy is a rename policy, so it needs authorization.I checked Herdr's
handle_tab_rename(src/app/api/tabs.rs): each rename callsset_custom_name,schedule_session_save()and emits aTabRenamedevent. The text holds CPU%, RAM% and disk%, which change nearly every tick. So a session-save request and an event can fire about once a second, although docs/herdr.md says "only when its text changes".The rename targets
ws.get("active_tab_id"). Concrete sequence: an operator opens a second tab inmachine(for example htop) and focuses it. That tab's name is overwritten within a second. The first tab keeps its last shares text as a stale label, because the cache only remembers the last[tab, short]and nothing restores earlier names. This contradicts docs/herdr.md ("the orchestrator never names that tab"), since operators can name tabs there.The renamed tab is also desktop-visible beyond the tab bar the docs mention: the desktop navigator uses a custom tab label as the row name (aggregate_navigation.rs ~line 366).
Options to choose between: pin the rename to one tab, throttle it, restore labels, or drop it. Dropping it means the whole-machine line is absent on mobile, which the intent requires.
maintenance/herdr-spaces.py:410- Setting--display-agenton home panes changes the desktop pane border, and docs/herdr.md does not say so. The docs say none of these fields shows on the desktop except the renamed tab. That is accurate for the sidebar: config/default.yml is the only definition ofsidebar_agent_rowsin the repo, and its rows use onlystate_icon,$who,terminal_titleand the$pr/$add/$del/$filestokens. It uses noagentorstate_texttoken, so agent_sidebar.rs's reads ofdisplay_agentandstate_labelsnever reach the screen. aggregate_navigation.rs usesdisplay_agentonly as a fallback whenagentis unset and for search matching.It is not accurate for pane borders. Herdr's
TerminalState::border_label(show_agent_labels)(src/terminal/state.rs) falls back toeffective_display_agent()when no title or manual label is set. This repo rendersshow_agent_labels_on_pane_borders = true(ansible/group_vars/all.yml:198, templates/herdr.toml.j2:21).Sequence: a home omp pane sits in a split pane. Its border label was
ompand is now the session topic, which changes on every rename.The intent says the desktop "sidebar must stay exactly as it is". Borders are not the sidebar, but this desktop-visible change is unapproved and undocumented. Either accept it and document it, or avoid the display-agent write. That is a product decision about the desktop look. Mobile needs
display_agentto show the session title, because Herdr's mobile Agent line has no other field for it.🔧 Fix applied.
1 warning still open:
maintenance/herdr-spaces.py:417- The pane reports omit--agent, so the topic and counts this script writes stay on a pane after its agent exits. The script never cleans them up itself. Unlike the other findings, this is a source-proven defect with a small remedy.Sequence: a home omp pane (
whotoken set) gets--display-agent <topic>and state labels from this script. The user quits omp, or the extension clearswhoon session shutdown.pane.get("agent")is now falsy, so the loop hitscontinue(theif not pane.get("agent")check, ~line 392) and the pane is never visited again.Herdr keeps the record. In v0.9.3,
set_agent_metadatastoresagent_label = Nonefor a report without--agent.metadata_guards_match(src/terminal/metadata.rs) only hides metadata whoseagent_labelis set and no longer equalseffective_agent_label(). The exit handler (src/terminal/state.rs:573-583) only clears metadata whoseagent_labelequals the exited agent.metadata_report_blocked_by_process_exitlikewise only blocks--agent-tagged reports. So this source's record is never hidden or cleared.Result:
pane listkeeps returning the olddisplay_agentandstate_labels.border_label(state.rs, ~line 2409) falls back toeffective_display_agent()whileshow_agent_labels_on_pane_bordersis true (ansible/group_vars/all.yml:198). So a split shell pane shows the dead session's topic on its desktop border indefinitely.Same class, sibling sites, all using the same report call at line 417:
--display-agentwith no guard.--state-labelwith no guard.--clear-state-labelswith no guard.who(sotitlebecomes "") keeps its olddisplay_agent. Thetitle and ...test at ~line 409 skips it, and the replace-style report at line 412 only fires when the labels also differ.Fix at the shared boundary: add
--agent <pane["agent"]>to every report at line 417. I confirmed from Herdr's source that--agentonreport-metadatais only a guard.set_agent_metadatastores it,metadata_guards_matchhides the record when the pane's agent differs, and the process-exit handler clears it. It does not claim or relabel the pane.Idempotence is unaffected:
pane list'sagentiseffective_agent_label(), the same value the guard compares against.Update the stub arguments in
tests/test_herdr_sidebar.py(test_mobile_layout_carries_the_same_data,test_mobile_reports_settle_and_follow_a_changed_pane, and thew3:p4/w3:p8expectations).🔧 Fix applied.
2 issues (1 warning, 1 info) still open:
maintenance/herdr-spaces.py:417- The pane reports omit--agent, so the topic and counts this script writes stay on a pane after its agent exits. The script never cleans them up itself. Unlike the other findings, this is a source-proven defect with a small remedy.Sequence: a home omp pane (
whotoken set) gets--display-agent <topic>and state labels from this script. The user quits omp, or the extension clearswhoon session shutdown.pane.get("agent")is now falsy, so the loop hitscontinue(theif not pane.get("agent")check, ~line 392) and the pane is never visited again.Herdr keeps the record. In v0.9.3,
set_agent_metadatastoresagent_label = Nonefor a report without--agent.metadata_guards_match(src/terminal/metadata.rs) only hides metadata whoseagent_labelis set and no longer equalseffective_agent_label(). The exit handler (src/terminal/state.rs:573-583) only clears metadata whoseagent_labelequals the exited agent.metadata_report_blocked_by_process_exitlikewise only blocks--agent-tagged reports. So this source's record is never hidden or cleared.Result:
pane listkeeps returning the olddisplay_agentandstate_labels.border_label(state.rs, ~line 2409) falls back toeffective_display_agent()whileshow_agent_labels_on_pane_bordersis true (ansible/group_vars/all.yml:198). So a split shell pane shows the dead session's topic on its desktop border indefinitely.Same class, sibling sites, all using the same report call at line 417:
--display-agentwith no guard.--state-labelwith no guard.--clear-state-labelswith no guard.who(sotitlebecomes "") keeps its olddisplay_agent. Thetitle and ...test at ~line 409 skips it, and the replace-style report at line 412 only fires when the labels also differ.Fix at the shared boundary: add
--agent <pane["agent"]>to every report at line 417. I confirmed from Herdr's source that--agentonreport-metadatais only a guard.set_agent_metadatastores it,metadata_guards_matchhides the record when the pane's agent differs, and the process-exit handler clears it. It does not claim or relabel the pane.Idempotence is unaffected:
pane list'sagentiseffective_agent_label(), the same value the guard compares against.Update the stub arguments in
tests/test_herdr_sidebar.py(test_mobile_layout_carries_the_same_data,test_mobile_reports_settle_and_follow_a_changed_pane, and thew3:p4/w3:p8expectations).maintenance/herdr-spaces.py:385- Two changes are visible on the desktop outside the sidebar. The intent says the desktop sidebar must stay exactly as it is, and the sidebar itself is unchanged. The user can decide whether these two effects fit "keep this look".Sidebar unchanged (checked):
config/default.yml:27-65use onlystate_icon,$who,terminal_title,$pr,$issue,$add,$del,$files,$short,workspace,$decisions,$crew,$queue,$machine,$res,$hostand$alert.rows_by_agent,state_textand theagenttoken appear nowhere in the repo's Herdr config.state_textas the token that shows a reported state label.display_agentis the pane's displayed agent name.Desktop effects outside the sidebar, both disclosed in
docs/herdr.md:183and:185:herdr-spaces.py:384-389renames themachineworkspace's first tab to its CPU, RAM and disk shares. The new label shows in the desktop tab bar and navigator while that workspace is focused. It is needed because the mobile Space entry has no other field for the machine line.herdr-spaces.py:425sends the session topic as a home pane's display agent. The factory setsshow_agent_labels_on_pane_borders = true(ansible/group_vars/all.yml:198), so a home pane in a split shows the topic on its border instead ofomp.No action needed if these fit the intent. If they do not, the options are dropping the tab rename, or setting
factory_herdr_show_agent_labelsto false. The second option would also change the desktop border labels for every agent pane, so it is a user decision.This is separate from the advisory's scenario of a pane that loses
whowhile omp keeps running. I judged that scenario not worth a finding:config/herdr-sidebar.tsclearswhoonly insession_shutdown(lines 286-294).session_switchandsession_startre-report it.--agentguard added in round 5 drops the record when the agent exits. So any stale topic lasts only the short gap between the shutdown clear and Herdr dropping the agent.pane listmerges the orchestrator's worker display agents with ours. That is new durable state, so it would be the user's call.✅ **Test** - passed
✅ No issues found.
◷3 ⚙0% ▤0% ⛁0% ⎇1537 +12847 −3902 ✎214 · Plann…and◷1 ⚙0% ▤0% ⛁0% +84 −12 ✎3 · Fix ratings screen○ 1529) seeded on a home pane shows on the desktop agent row but is left out of the mobile entry, and docs/herdr.md lists that as a forced difference⎇ 1537 · ○ 1529 · +12847 · −3902 · ✎ 214) vs 15-mobile-machine-switch.png (no○); 14-per-home-cpu-change.txt last line; docs/herdr.md:193 `The issue (○) is left out…machineworkspace's pinned first tab, in both the Space entry and the tabs listshell · tab ⚙31% ▤28% ⛁71%and1 · ⚙31% ▤28% ⛁71%); 13-fresh-install-tab-and-idempotence.txt▤28% ⛁71%, then unchanged, then⚙13% ▤28% ⛁71%after 31 s. A fresh install shows a CPU-less machine tab for up to 30 s (informational).htop) is left alone after the throttle expires, and a second focused tab is never renamedhtopkept,w3:t2stays2w1:t1andw2:t1stay1pane report-metadatacall and no tab renamerestoken, and on the first run after the process exits it returns to ⚙0%…res ⚙ 12%↔label ⚙12%, thenres ⚙ 0%↔label ⚙0%on the first post-exit run and the two runs after itrelease-agent; controldisplay_agent="stale topic"survived. This run used a hand-seeded+84token, which does not affect the guard.whotoken) keeps the orchestrator's display agent, and its real-form pull request parts go to the state labels└ fix-token-raceunchanged; state labels⎇1540 +5 −1 ✎2herdr.toml.j2, base reporter cdd9549 then target 5fc8fb5,firstmatefocusedomp(decision C)herdr.toml.j2(show_agent_labels_on_pane_borders = true) at 120 columns, with panes whose agent was reported throughpane report-agent. Herdr dre…python3 -m pytest tests/test_herdr_sidebar.py -q -p no:cacheprovider(74 passed). Unit-level evidence only, not counted as a live scenario.Isolated realherdr server(own HOME, XDG_CONFIG_HOME, XDG_RUNTIME_DIR, XDG_CACHE_HOME).herdr workspace listshowed only the fixture's workspaces, and a /proc check found only the fixture's own pane process carryingHERDR_WORKSPACE_ID=w1. The unmodifiedmaintenance/herdr-spaces.pyran against it.Pane tokens seeded from the real exportedprPartsinconfig/herdr-sidebar.ts(run with bun, sent with the extension'sreport-metadataargument shape), including anissuetoken to check it is left out of the mobile lineHerdr TUI in 50x30 and 50x40 ptys (non-zero TIOCSWINSZ, drained master, patched pyte capture, PNG render): mobile main view andprefix+wswitch menu, with a home workspace focused and withmachinefocusedA/B desktop capture at 120x30 with the repo'sherdr.toml.j2rendered from the repo config (herdr config checkok): base-commit reporter first, then target reporter on the same server, with a split pane. Compared sidebar columns 0-45 raw and digit-masked, and columns 46+ separately.Fresh-install run: empty cache, machine tab reset to1. Run 1 named the tab without ⚙. Run 2 immediately after left it unchanged. Run 3 after 31 s added ⚙.Six back-to-back reporter runs with only fixture processes present: 0 pane writes and 0 tab renames eachRe-run of the CPU rise and fall on a fresh isolated server, printing therestoken next tostate_labels.workingat every step. Idle was ⚙0%, with a busy process taggedHERDR_WORKSPACE_ID=w1the label read ⚙12%, and the first run after the process exited gave ⚙0% again. The label matched the token at every step.Machine-tab adversarial cases: operator renames the pinned tab, opens and focuses a second tab, resets the label to a number, closes the pinned tab. Home workspaces' tabs stay1.Agent-exit guard:pane release-agentafter the reporter's--agent-tagged write, plus a control write without--agentWorker pane in a split (nowhotoken) with realprPartsoutput: the orchestrator's display agent kept, pull request parts written to state labelsSession topic follows a rename, is capped at 80 characters, and an unchanged title causes no rewriteReporter with no reachable herdr server: exit 0, no traceback✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.