Sloth-ninja makes firm-managed workspaces say what they mean

Pilot feedback exposed a few small interface mismatches that could make a managed legal workspace feel less trustworthy than it is.

chat-uiworkflow

The sidebar now keeps its account area visible when space is tight, while matters and history share a scrollable area. Account controls also use the same collision-aware menu treatment already used elsewhere in the product.

  • Firm-managed AI choices now show the providing firm's name instead of a model selector members cannot change.
  • Firm names are read-only for members whose organisation manages the account, while independent and self-hosted users can still edit them.
  • The sidebar has been checked against crowded matter lists at both short and tall window sizes.
So what Firms standardising AI access should care because the interface now matches the controls already enforced behind it.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

8 commits from Sloth-ninja/JessicaOSS, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
bb479ec9 fix(sidebar): portal the account menu so it stops covering chat history sloth-ninja 2026-08-13 ↗ GitHub
commit body
The bottom profile block's dropdown was a hand-rolled `absolute
bottom-full z-50` box rendered in flow above its trigger, so it painted
over the last visible Assistant History rows (pilot feedback 13/08).

Swap it for the shared Radix wrapper already used one file away in
SidebarChatItem: portal-mounted, collision-aware, with native dismiss on
outside click and Escape. Positioned side="top" align="start"; the
existing glass styling is passed through to DropdownMenuContent, and both
sidebar states are preserved - expanded matches the trigger width (via
--radix-dropdown-menu-trigger-width, the house pattern from
account/models and TREditColumnMenu), collapsed stays w-56.

Net deletion: the isDropdownOpen state and the manual document
click-outside listener are gone; the trigger's open highlight now comes
from data-[state=open].

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ab9f7269 fix(chat): hide the model picker when the firm manages model preferences sloth-ninja 2026-08-13 ↗ GitHub
commit body
Firm members whose firm has memberModelPrefs OFF were still shown an
interactive model picker in both composers, even though the server
already clamps the chat model to the firm default. The control looked
live and did nothing (pilot feedback 13/08).

Both ChatInput and TRChatPanel now consult personalModelPrefsBlocked -
the same helper account/models/page.tsx uses - and render a quiet inline
"Provided by <firm>" label in place of the picker. Absence, not a
disabled-looking-but-clickable control, matching the established WS8
absence-not-disabled treatment.

The offeredProviders filtering is untouched for the policy-ON case.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
c183f0df fix(sidebar): stop the nav column painting over the profile block sloth-ninja 2026-08-13 ↗ GitHub
commit body
The account-menu swap only covered the popup case. A fresh owner
screenshot reproduces the overlap with no popup open: on a short viewport
the "Assistant History" header renders behind the bottom profile row.

Root cause is the flex chain, not the dropdown. The middle region is
flex-1 min-h-0, so it shrinks to nothing when the fixed nav sections
above it (this pilot user is a firm admin, so Firm *and* Firm admin are
both present) eat the height. Its children then keep their intrinsic
height - only the row list is overflow-y-auto, the Recent Matters block
and the History header are not - and with no clipping ancestor they paint
straight through onto the mt-auto profile block.

Wrap the nav sections and the middle region in one `flex-1 min-h-0
overflow-y-auto` column. The profile block is now a SIBLING of a scroll
container, so nothing above it can paint over it at any height - an
invariant of the structure rather than of the arithmetic. Add a min-h-56
floor on the middle region so History degrades to a shorter scrollable
list instead of a half-rendered header, and shrink-0 on the profile.

Verified by headless-Chrome renders of a raw-CSS harness translating this
class chain, before vs after, with the full firm-admin nav:
  - 820px viewport (the reproducing config): before overlaps, after clear
  - 700px viewport: before spills outside the card entirely, after clear
  - tall viewport: before/after pixel-identical, no scrollbar, no
    regression to the pinned Recent Matters + inner history scroll

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
a648cc3b fix(account): show firm members their firm name read-only sloth-ninja 2026-08-13 ↗ GitHub
commit body
The Organisation field edited user_profiles.organisation - a legacy
free-text column that predates firms and is shown nowhere else. A firm
member could type anything into it and nothing would change, while the
real firm name sat unused in the same payload as profile.firm.name
(pilot feedback 13/08).

Firm members now see profile.firm.name read-only with a quiet "Managed by
your firm." line, matching how this page already treats the Danger Zone
for firm members. Orgless self-hosters keep the editable field exactly as
before, so the legacy column stays reachable where it is still the only
source of an organisation name.

The seeding effect now skips the firm path, since only the orgless branch
has a field to populate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
e337f539 docs: BUILD_LOG entry for the 13/08 pilot-feedback UI fix wave sloth-ninja 2026-08-13 ↗ GitHub
Covers all three items, the harness-render evidence for the sidebar
layout fix, and the honest lint gate (count identical to main).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
87598c0f fix(sidebar): move the height floor onto the History section (review I1) sloth-ninja 2026-08-13 ↗ GitHub
commit body
Review caught that min-h-56 on the middle wrapper did not deliver what its
comment claimed. The floor is shared with the Recent Matters block, which
cannot shrink - with a full 5-matter list Recent Matters (~220px) eats the
entire 224px floor and the History section resolves to ZERO height: empty
list, header flush against the bottom. That is the exact configuration the
pilot firm will QA.

Drop the floor from the wrapper (it now sizes to content inside the
scrollable column) and put min-h-48 on the History section, where it
actually protects the list. The row container is itself a scroll
container, so its automatic minimum size is 0 and the section still
resolves to a bounded height.

Re-measured in a corrected harness - hard config this time: full 5-matter
Recent Matters, firm-admin nav, and the logo row OUTSIDE the scroll
column as in the real code (the first harness wrongly nested it):

  viewport   main            min-h-56 wrapper   min-h-48 History
  796px      history 0px,    history 0px        history 192px,
             escapes card    (no escape)        rows 174px
  676px      history 0px,    history 0px        history 192px,
             escapes card    (no escape)        rows 174px
  1006px     history 60px,   history 60px       history 192px,
             rows 42px       rows 42px          rows 174px

Matches the reviewer's independent measurement (192/168; the 6px delta is
header line-height modelling). Accepted trade-off, as flagged: at ~1030px
with 5 recent matters the outer column becomes scrollable where today it
is not - scroll is acceptable, an empty history list is not, and the fix
buys 174px of rows against main's 42px at that height.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
17444d9e fix(chat): truncate the firm label on the text, not the flex box (review M1) sloth-ninja 2026-08-13 ↗ GitHub
commit body
`truncate` sets overflow/text-overflow/white-space, but it was on the
flex container, where text-overflow has no line box to apply to - a long
firm name would hard-clip at max-w rather than ellipsing. Move it to an
inner span wrapping the text. The title attribute already carries the
full name and is unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fc4b4dcb docs: state the harness configuration and the floor move (review I2) sloth-ninja 2026-08-13 ↗ GitHub
commit body
The entry's 820px claim came from a harness that modelled the easy case -
empty Recent Matters, and the logo row nested inside the scroll column,
which the real code does not do. The conclusions held under a corrected
higher-fidelity harness, but the entry must say which configuration was
rendered rather than implying the hard one.

Records the round-1 vs round-2 harness configurations, the measurement
method (elementFromPoint sampling, since getBoundingClientRect ignores
clipping and false-positives on scrolled-out content), the I1 floor move
to the History section, and the accepted 1030px scroll trade-off.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-1017.md from inside the repo you want the changes in.

⬇ Download capture-thread-1017.md