Skip to content

fix(sessions): tighten session-list spacing, 2px colour bar, left folder unread dot - #3903

Merged
michellemxm merged 1 commit into
mainfrom
feat/session-list-polish
Aug 16, 2026
Merged

fix(sessions): tighten session-list spacing, 2px colour bar, left folder unread dot#3903
michellemxm merged 1 commit into
mainfrom
feat/session-list-polish

Conversation

@michellemxm

@michellemxm michellemxm commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Problem / Motivation

Follow-up polish to the session-list rows that landed in #3766 (merged). Iterating against a live preview surfaced several spacing/visual details that were slightly off once the redesign was in real use:

  • Session rows carried more horizontal padding than needed (px-3), pushing content in.
  • The colored session indicator bar (3px) read a touch heavy.
  • The collapsed-folder unread dot sat on the right (next to the count), inconsistent with the session rows, whose unread marker is in the left gutter.
  • Level-one and level-two folder counts did not line up on the right edge — nested folders were pushed in a few px per level.
  • Folder-row and nested-connector indentation needed retuning.

Why it matters

These are the rows a user scans dozens of times a session. Inconsistent left/right alignment (unread dot on opposite sides, folder counts not lining up by depth) reads as visual noise and undercuts the redesign's intent. Small, but directly in the primary navigation surface.

What changed (motivation → approach → change)

Visual tuning of ChatSidebar.tsx + index.css. The only non-visual touch is a tightened render guard (item 4) so the folder unread dot does not overlap the rename input; no signal is lost:

  • Session row: gap-1.5 px-3gap-1 pl-1 pr-2 — tighter, asymmetric padding.
  • Colored indicator bar: 3px2px (both the solid .session-colored::before and the gradient-mode solid stops), for a finer line.
  • Folder row: px-2.5pl-[18px] pr-3 (arbitrary-value left pad because this Tailwind config has no 4.5 step). The extra left pad opens a gutter for the folder unread dot.
  • Folder unread dot: moved from an inline flex child (right, before the count) to an absolutely-positioned <span> in the left gutter, matching the session rows' left marker. Render guard tightened to also suppress it while the folder is being renamed; kept aria-hidden.
  • Nested connector: ml-2 pl-1ml-4 (sessions sit flush against the connector line).
  • Folder-count right-alignment across depths: FolderBody's inner wrapper had symmetric 2px padding, so each nesting level pushed content in 2px on the right and counts drifted left per level. Changed to 2px 0 2px 2px (top/right/bottom/left) — right padding removed — so counts share the same right edge at every depth.

Tests

Updated ChatSidebar.folderAlignment.test.tsx token-exact assertions to the new values (folder-row pl-[18px]/pr-3 + gap-2, nested body ml-4 with no pl-1, session row pl-1/pr-2/gap-1) and refreshed its doc header + the stale in-source measurement comment. All 337 sidebar/color-bar tests pass; tsc -b clean; eslint 0 errors; brand + i18n gates clean (no string/locale changes).

Manual verification

Captured against the isolated preview harness (built dist served on loopback with stubbed API — no gateway), folder-tree view showing nested folders, right-aligned counts, 2px color bars, and the tightened spacing. See below.

Screenshots / video

session list — folder tree, aligned counts, 2px color bars, tightened spacing

Related Issues

no linked issue: visual follow-up polish to the merged #3766 redesign, no tracked issue.

Checklist

  • Single commit with a Conventional Commits title
  • Existing tests pass and new tests added for new functionality
  • Self-review completed; code follows project style guidelines
  • Documentation updated (if applicable) — N/A (no docs affected; in-source comment refreshed)
  • No secrets, credentials, or internal references in the diff

@michellemxm
michellemxm requested a review from a team August 16, 2026 05:18
@michellemxm
michellemxm requested a review from a team as a code owner August 16, 2026 05:18
@github-actions github-actions Bot added the readiness: checking Automated validation is still running label Aug 16, 2026
@github-actions

github-actions Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

GPT 5.6 Review — ✅ no blocking findings

GPT 5.6 completed its review of 96e676634d35df76e7b85158cf55d8d65b8cccba and found no blocking issues.

This comment is updated in place on each push.

Review details

No findings.
[GPT-REVIEWED] 96e6766

False positive or not applicable? A repository writer can comment:
/ai-review override gpt 96e676634d35df76e7b85158cf55d8d65b8cccba: <one-sentence reason>

@github-actions

github-actions Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Design Review (Fable 5) — ✅ PASS

Advisory design-level review of 96e676634d35df76e7b85158cf55d8d65b8cccba — updated in place on each push; does not block merge.

Design-Verdict: PASS

Proportionate visual polish with the geometry decisions, their rationale, and the guard tests all updated coherently in one commit.

[DESIGN-REVIEWED] 96e6766

@github-actions

github-actions Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Opus 4.8 Review — ✅ no blocking findings

Reviewed 96e676634d35df76e7b85158cf55d8d65b8cccba — this comment is updated in place on each push.

Review details

No findings.

[OPUS-REVIEWED] 96e6766

Verdict parsed from the review's SHA-scoped output markers for commit 96e676634d35df76e7b85158cf55d8d65b8cccba.

False positive or not applicable? A repository writer can comment:
/ai-review override fable 96e676634d35df76e7b85158cf55d8d65b8cccba: <one-sentence reason>

@github-actions

github-actions Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

UX Review (Fable 5) — ✅ PASS

Advisory UX-level review of 96e676634d35df76e7b85158cf55d8d65b8cccba — updated in place on each push; does not block merge.

UX-Verdict: PASS

Consistency polish that pays off: unread markers now share one left-gutter convention, counts align by depth, and the screenshot confirms the spacing claims.

Suggestions

  • The relocated folder unread dot (ChatSidebar.tsx:3107) is aria-hidden with no text fallback, while the session-row marker it "matches" carries the agent_finished_your_turn label — fold unread state into the toggle button's aria-label (e.g. "Expand folder {name}, has unread") so non-sighted users get the same cue.
  • 01-folder-tree.png shows no collapsed folder with unread, so the PR's headline change ships visually unverified — capture one unread collapsed folder to confirm the gutter dot clears the glyph and connector at nested depths.

[UX-REVIEWED] 96e6766

@michellemxm
michellemxm enabled auto-merge (squash) August 16, 2026 05:24
@github-actions

github-actions Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

First Principles Review (Fable 5) — 🟡 CONCERNS

Advisory premise-level review of 96e676634d35df76e7b85158cf55d8d65b8cccba — why this exists and whether the shipped surface is the smallest honest version. Updated in place on each push; does not block merge.

Evidence gathered: I read the contract, the intent file, the patch, and verified against the repo — the FolderBody component has 2 consumers (list view ChatSidebar.tsx:3295 and board view ChatSidebar.tsx:2372), the old ml-2 pl-1 connector spelling survives once in board view (ChatSidebar.tsx:2373), the old right-side dot was already hidden during rename (it lived inside the non-editing branch), and temp-screenshots/ commits are the repo's sanctioned PR-evidence mechanism per its README.

First-Principles-Verdict: CONCERNS

The unread-dot move is backed only by "consistent with session rows" — no one named as misreading it — and the connector retune skips its board-view twin.

What this change ships

Intent: polish the just-merged (#3766) session-list rows' spacing and alignment — a FIX (visual-defect follow-up).

  1. Session rows sit tighter (smaller side padding and gap) — justified
  2. Colored session bar thins 3px → 2px, both color modes — justified
  3. Folder rows get 18px left / 12px right padding, opening a dot gutter — justified
  4. Collapsed-folder unread dot moves from right of count to left gutter — unjustified move
  5. Folder glyph→name gap widens 5px → 8px — undeclared (surfaces only in the Tests paragraph)
  6. Nested sessions sit flush against the connector line — justified; 1 unfixed sibling
  7. Folder counts right-align at every depth (per-level right pad removed) — justified, cause-level
  8. Row divider inset shrinks 30px → 20px — rides along (derived from item 1)
  9. Board view's nested content also loses 2px right pad via shared FolderBody — undeclared
  10. One screenshot under temp-screenshots/ — justified (repo convention)

Watch

  • Item 4 is a MOVE, and its only support is "inconsistent with the session rows" — exactly the consistency-as-analogy the bar for moves discounts; nobody is named as failing to spot unread state on the right. Mitigating: feat(sessions): redesign the session list rows #3766 merged days ago, so habituation cost is near zero. A human should confirm the trade knowingly.
  • Item 6's stated harm ("sessions sit flush against the connector") still exists in board view: grep ml-2 pl-1 counts 1 unfixed sibling at website/src/pages/ChatSidebar.tsx:2373. Either scope the claim to list view or fix both.
  • FolderBody has 2 consumers (list :3295, board :2372); the right-pad removal (item 7) silently changes board-view geometry the description never mentions — likely benign, but undeclared scope.

[FIRST-PRINCIPLES-REVIEWED] 96e6766

@michellemxm
michellemxm force-pushed the feat/session-list-polish branch from 3bb17ac to 96e6766 Compare August 16, 2026 05:35
@michellemxm

Copy link
Copy Markdown
Contributor Author

Dispositions for the First Principles advisory (verified against 96e676634d35df76e7b85158cf55d8d65b8cccba). Thanks — the divider catch was real.

Fixed

  • Session-row divider still computed from the old 30px offset (ChatSidebar.tsx:3050): correct — my diff moved the row's content offset from px-3(12)+gutter(12)+gap-1.5(6)=30 to pl-1(4)+gutter(12)+gap-1(4)=20, but the ml-[30px] divider inset shipped untouched and sat 10px right of the new content edge. Fixed to ml-[20px] and rewrote its derivation comment to the current tokens. This is squarely in scope (it's the session-list row divider, and my change caused the drift).

Accepted / deferred (out of scope for this list-view tuning)

  • Board-view folder body keeps ml-2 pl-1 (ChatSidebar.tsx:2373) while list view moved to ml-4: correct observation. This PR's iteration was scoped to the sidebar list view (tuned live against a preview); the board/kanban column layout is a separate surface this diff never touched, and its indentation is intentionally not retuned here. The connector-flush claim in the description is about the list view; I'll tighten that wording. Filing a follow-up so the board view can be brought to parity as its own change: it's a one-line pl-1 removal but belongs with a board-view visual pass, not smuggled into a list-view PR.
  • History ("Older Sessions") row paddingLeft: '10px' (ChatSidebar.tsx:4311): flagged as Watch, not a Subtraction. It hardcodes a left column to sit under the session rows' gutter; my change moved that gutter left by 8px, so it's now slightly off. The correct offset for that row is a small design decision (it has no status gutter of its own), and the row is a distinct section the user did not scope into this pass — deferring rather than guessing a new hardcode that could introduce a fresh misalignment.

Noted (honesty nit)

  • "No behaviour change" vs. the tightened render guard (unread dot suppressed during folder rename): the description already declares the guard change explicitly in the "What changed" list; I've softened the "pure visual tuning" headline so it no longer reads as off-by-one. The guard only prevents the absolute dot from overlapping the rename input — no signal is lost.

None of these block; the rollup is green and mergeable.

@michellemxm

Copy link
Copy Markdown
Contributor Author

Addendum for the refreshed First Principles verdict on 96e676634:

  • FolderBody right-pad removal also changes board-view geometry — undeclared (item 9): correct — FolderBody has two consumers (list :3295, board :2372), so dropping its inner right padding pulls nested content's right edge out by 2px in both views, not just the list. In the list view that is the point (it's what aligns folder counts across depth). In the board view it is benign: kanban columns are fixed-width and have no across-depth count-alignment to correct, so the only effect is nested content reaching 2px further right — consistent, not a regression. Accepting as an intended side effect of a shared-component change; noted here so the scope is declared rather than silent.
  • Board-view flush-connector still unfixed (ml-2 pl-1 at :2373): unchanged from my prior disposition — deferred to follow-up Bring board-view folder body indentation to parity with the list view #3909, and the description's flush-connector claim is scoped to the list view.

Both advisory; rollup remains green and mergeable.

@github-actions github-actions Bot added readiness: passed Eligible automated validation passed for the current revision and removed readiness: checking Automated validation is still running labels Aug 16, 2026

@bolichen97 bolichen97 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tier 1 auto-approve: cosmetic-UI (4 files). Criteria: no conflict, no requested changes, security path denylist clean, SAST annotations clean, security checklist all-NO, AI reviewers green. Category: tightens session-list spacing, adds 2px colour bar, positions folder unread dot — pure CSS/layout polish.

@michellemxm
michellemxm merged commit 5193be3 into main Aug 16, 2026
65 of 67 checks passed
@michellemxm
michellemxm deleted the feat/session-list-polish branch August 16, 2026 06:02
@github-actions github-actions Bot removed the readiness: passed Eligible automated validation passed for the current revision label Aug 16, 2026

@iamwhatever iamwhatever left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tier 1 auto-approve: cosmetic-UI (4 files). Criteria: no conflict, no requested changes, no security surface, AI reviewers green. Category: session-list spacing polish — 2px colour bar, left folder unread dot, tighter vertical spacing.

@bolichen97 bolichen97 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tier 1 auto-approve: cosmetic-UI (4 files). Criteria: no conflict, no requested changes, security path denylist clean, SAST annotations clean, security checklist all-NO, AI reviewers green. Category: CSS spacing polish — session-list 2px colour bar and folder unread dot.

CrysisDeu added a commit that referenced this pull request Aug 16, 2026
A folder in the session list and the sessions filed under it did not share a
left edge. #3766 added the row's status gutter as an in-flow flex child, so
its 12px width plus a gap landed on the content column: the agent label,
title and tool-call subtitle of every session inside a folder sat well right
of that folder's own name. #3903 then tightened the same rows and got
closer, but measured on a real render it still left the folder name 1px past
its sessions' text and a nested folder's glyph 2px short of their column.

Three guides now hold, in the root lane and at every nesting depth:

  1. a folder glyph sits on its own border-l connector line
  2. a folder name shares one edge with the agent label / title /
     tool-call subtitle of every session inside it
  3. a NESTED folder's glyph sits on the content column of the sessions
     filed beside it, so a subfolder reads as their peer

Solving all three simultaneously forces header pad == session row pad. With
D = 2, a MEASURED container differential (the header's box starts 2px left
of the nested body's box, and no class in the component expresses it):

  guide 1  P = D + M                       14 = 2 + 12
  guide 2  P + G + g = D + M + B + p + R   33 = 33
  guide 3  P = R                           14 = 14

The status gutter moves out of the content flow (absolutely positioned
inside that pad) and is centred on the row rather than deriving the
headline's y; in flow it is what broke guide 2, and no class-level assertion
could see it. Because the algebra has no per-depth term it is scale-free:
depth 3 nests as depth 2 does, and root-lane sessions land on the root
folder's glyph, which restores the original pre-#1211 guide.

Measured on the built SPA: depth 1 glyph/connector 259, name and all three
text lines 278; depth 2 glyph/connector 278 (== depth 1's content column),
name/content 297; root lane content 259.

This reverts #3903's row and folder geometry, agreed with its author. Its
collapsed-folder unread dot goes back inline on the right of the name rather
than into an absolute left gutter: that gutter is what forced the header pad
to 18px, and the pad is not free — it has to equal the session row's. The
2px colour bar from #3903 is kept, being orthogonal to the guides.

Also drop the title's mt-0.5 (row height 49.6 -> 43.6px idle, 68.1 -> 62.1
running), use lucide Loader for the running spinner (at 12px the
LoaderCircle arc reads as a broken ring where the spokes read as motion),
and pull the divider inset and the empty-folder "New chat in X" affordance
onto the same column as the sessions.

The alignment invariant test has been rewritten by each of the last two PRs
to accept the then-current misalignment. It now pins all three guides, adds
guide 3 at depth 2 with a nested fixture, and the gutter test pins the
gutter as out-of-flow and row-centred. Every number in the test header is a
measurement with its frame named: two paper estimates during this fix were
2px and 3px out.
CrysisDeu added a commit that referenced this pull request Aug 16, 2026
A folder in the session list and the sessions filed under it did not share a
left edge. #3766 added the row's status gutter as an in-flow flex child, so
its 12px width plus a gap landed on the content column: the agent label,
title and tool-call subtitle of every session inside a folder sat well right
of that folder's own name. #3903 then tightened the same rows and got
closer, but measured on a real render it still left the folder name 1px past
its sessions' text and a nested folder's glyph 2px short of their column.

Three guides now hold, in the root lane and at every nesting depth:

  1. a folder glyph sits on its own border-l connector line
  2. a folder name shares one edge with the agent label / title /
     tool-call subtitle of every session inside it
  3. a NESTED folder's glyph sits on the content column of the sessions
     filed beside it, so a subfolder reads as their peer

Solving all three simultaneously forces header pad == session row pad. With
D = 2, a MEASURED container differential (the header's box starts 2px left
of the nested body's box, and no class in the component expresses it):

  guide 1  P = D + M                       14 = 2 + 12
  guide 2  P + G + g = D + M + B + p + R   33 = 33
  guide 3  P = R                           14 = 14

The status gutter moves out of the content flow (absolutely positioned
inside that pad) and is centred on the row rather than deriving the
headline's y; in flow it is what broke guide 2, and no class-level assertion
could see it. Because the algebra has no per-depth term it is scale-free:
depth 3 nests as depth 2 does, and root-lane sessions land on the root
folder's glyph, which restores the original pre-#1211 guide.

Measured on the built SPA: depth 1 glyph/connector 259, name and all three
text lines 278; depth 2 glyph/connector 278 (== depth 1's content column),
name/content 297; root lane content 259.

This reverts #3903's row and folder geometry, agreed with its author. Its
collapsed-folder unread dot goes back inline on the right of the name rather
than into an absolute left gutter: that gutter is what forced the header pad
to 18px, and the pad is not free — it has to equal the session row's. The
2px colour bar from #3903 is kept, being orthogonal to the guides.

Also drop the title's mt-0.5 (row height 49.6 -> 43.6px idle, 68.1 -> 62.1
running), use lucide Loader for the running spinner (at 12px the
LoaderCircle arc reads as a broken ring where the spokes read as motion),
and pull the divider inset and the empty-folder "New chat in X" affordance
onto the same column as the sessions.

The alignment invariant test has been rewritten by each of the last two PRs
to accept the then-current misalignment. It now pins all three guides, adds
guide 3 at depth 2 with a nested fixture, and the gutter test pins the
gutter as out-of-flow and row-centred. Every number in the test header is a
measurement with its frame named: two paper estimates during this fix were
2px and 3px out.
CrysisDeu added a commit that referenced this pull request Aug 16, 2026
A folder in the session list and the sessions filed under it did not share a
left edge. #3766 added the row's status gutter as an in-flow flex child, so
its 12px width plus a gap landed on the content column: the agent label,
title and tool-call subtitle of every session inside a folder sat well right
of that folder's own name. #3903 then tightened the same rows and got
closer, but measured on a real render it still left the folder name 1px past
its sessions' text and a nested folder's glyph 2px short of their column.

Three guides now hold, in the root lane and at every nesting depth:

  1. a folder glyph sits on its own border-l connector line
  2. a folder name shares one edge with the agent label / title /
     tool-call subtitle of every session inside it
  3. a NESTED folder's glyph sits on the content column of the sessions
     filed beside it, so a subfolder reads as their peer

Solving all three simultaneously forces header pad == session row pad. With
D = 2, a MEASURED container differential (the header's box starts 2px left
of the nested body's box, and no class in the component expresses it):

  guide 1  P = D + M                       14 = 2 + 12
  guide 2  P + G + g = D + M + B + p + R   33 = 33
  guide 3  P = R                           14 = 14

The status gutter moves out of the content flow (absolutely positioned
inside that pad) and is centred on the row rather than deriving the
headline's y; in flow it is what broke guide 2, and no class-level assertion
could see it. Because the algebra has no per-depth term it is scale-free:
depth 3 nests as depth 2 does, and root-lane sessions land on the root
folder's glyph, which restores the original pre-#1211 guide.

Measured on the built SPA: depth 1 glyph/connector 259, name and all three
text lines 278; depth 2 glyph/connector 278 (== depth 1's content column),
name/content 297; root lane content 259.

This reverts #3903's row and folder geometry, agreed with its author. Its
collapsed-folder unread dot goes back inline on the right of the name rather
than into an absolute left gutter: that gutter is what forced the header pad
to 18px, and the pad is not free — it has to equal the session row's. The
2px colour bar from #3903 is kept, being orthogonal to the guides.

Also drop the title's mt-0.5 (row height 49.6 -> 43.6px idle, 68.1 -> 62.1
running), use lucide Loader for the running spinner (at 12px the
LoaderCircle arc reads as a broken ring where the spokes read as motion),
and pull the divider inset and the empty-folder "New chat in X" affordance
onto the same column as the sessions.

The alignment invariant test has been rewritten by each of the last two PRs
to accept the then-current misalignment. It now pins all three guides, adds
guide 3 at depth 2 with a nested fixture, and the gutter test pins the
gutter as out-of-flow and row-centred. Every number in the test header is a
measurement with its frame named: two paper estimates during this fix were
2px and 3px out.
bolichen97 pushed a commit that referenced this pull request Aug 16, 2026
A folder in the session list and the sessions filed under it did not share a
left edge. #3766 added the row's status gutter as an in-flow flex child, so
its 12px width plus a gap landed on the content column: the agent label,
title and tool-call subtitle of every session inside a folder sat well right
of that folder's own name. #3903 then tightened the same rows and got
closer, but measured on a real render it still left the folder name 1px past
its sessions' text and a nested folder's glyph 2px short of their column.

Three guides now hold, in the root lane and at every nesting depth:

  1. a folder glyph sits on its own border-l connector line
  2. a folder name shares one edge with the agent label / title /
     tool-call subtitle of every session inside it
  3. a NESTED folder's glyph sits on the content column of the sessions
     filed beside it, so a subfolder reads as their peer

Solving all three simultaneously forces header pad == session row pad. With
D = 2, a MEASURED container differential (the header's box starts 2px left
of the nested body's box, and no class in the component expresses it):

  guide 1  P = D + M                       14 = 2 + 12
  guide 2  P + G + g = D + M + B + p + R   33 = 33
  guide 3  P = R                           14 = 14

The status gutter moves out of the content flow (absolutely positioned
inside that pad) and is centred on the row rather than deriving the
headline's y; in flow it is what broke guide 2, and no class-level assertion
could see it. Because the algebra has no per-depth term it is scale-free:
depth 3 nests as depth 2 does, and root-lane sessions land on the root
folder's glyph, which restores the original pre-#1211 guide.

Measured on the built SPA: depth 1 glyph/connector 259, name and all three
text lines 278; depth 2 glyph/connector 278 (== depth 1's content column),
name/content 297; root lane content 259.

This reverts #3903's row and folder geometry, agreed with its author. Its
collapsed-folder unread dot goes back inline on the right of the name rather
than into an absolute left gutter: that gutter is what forced the header pad
to 18px, and the pad is not free — it has to equal the session row's. The
2px colour bar from #3903 is kept, being orthogonal to the guides.

Also drop the title's mt-0.5 (row height 49.6 -> 43.6px idle, 68.1 -> 62.1
running), use lucide Loader for the running spinner (at 12px the
LoaderCircle arc reads as a broken ring where the spokes read as motion),
and pull the divider inset and the empty-folder "New chat in X" affordance
onto the same column as the sessions.

The alignment invariant test has been rewritten by each of the last two PRs
to accept the then-current misalignment. It now pins all three guides, adds
guide 3 at depth 2 with a nested fixture, and the gutter test pins the
gutter as out-of-flow and row-centred. Every number in the test header is a
measurement with its frame named: two paper estimates during this fix were
2px and 3px out.
iamwhatever pushed a commit that referenced this pull request Aug 16, 2026
The sidebar's three folder alignment guides have regressed four times
(#1211, #3766, #3903, and twice on paper inside #3905), every time via a
Tailwind-class derivation that omitted the 2px FOLDER_BODY_INSET_PX
container differential between the folder header's box and the nested
body's box. The jsdom test (ChatSidebar.folderAlignment.test.tsx) cannot
catch that class of break: jsdom has no layout engine, so it asserts
class tokens and an arithmetic identity between constants, never the
rendered geometry.

Add a Playwright spec to the `E2E (stub ACP backend, offline)` gate that
seeds one folder, one subfolder, and sessions in both plus one ungrouped
session via the harness gateway API, then asserts the guides on
getBoundingClientRect().left of the real rendered elements:

- guide 1: folder glyph on its border-l connector line (depth 1 and 2)
- guide 2: folder name on the agent label / title of its sessions
  (depth 1 and 2)
- guide 3: nested folder glyph on its sibling sessions' content column,
  and the root-lane identity (ungrouped content on the root glyph)
- depth invariance: the depth-2 connector on depth 1's content column

Falsified against the historical regression class: rebuilding with
FOLDER_BODY_INSET_PX bumped 2 -> 4 fails the spec with
"fGlyph=259 vs fConnector=261" while the jsdom test stays green. The
missing-selector diagnostics were falsified the same way (a broken
selector fails with "missing: [aAgent, ...]", not a bare timeout).

Pre-push review (GPT + Opus model-pinned): no blocking. Fixed advisory
findings: absolute sanity anchors so difference-only assertions cannot
hold vacuously at left=0; seeding requests assert response.ok() so a
4xx fails as a seeding fault, not an alignment fault; the settle poll
subsumes the render wait (budget fits the 30s test timeout) and names
missing selectors; the serial-run dependency on the wipe discipline in
session-tags-folders.spec.ts is documented in the header.

The tool-call subtitle is not asserted: it needs a live agent turn to
render, is a sibling of the title inside the same block container (equal
left by construction), and its class parity is pinned by the jsdom test.

MIN_EXECUTED_SPECS raised 219 -> 220 for the added spec.

Closes #3914
iamwhatever pushed a commit that referenced this pull request Aug 16, 2026
The sidebar's three folder alignment guides have regressed four times
(#1211, #3766, #3903, and twice on paper inside #3905), every time via a
Tailwind-class derivation that omitted the 2px FOLDER_BODY_INSET_PX
container differential between the folder header's box and the nested
body's box. The jsdom test (ChatSidebar.folderAlignment.test.tsx) cannot
catch that class of break: jsdom has no layout engine, so it asserts
class tokens and an arithmetic identity between constants, never the
rendered geometry.

Add a Playwright spec to the `E2E (stub ACP backend, offline)` gate that
seeds one folder, one subfolder, and sessions in both plus one ungrouped
session via the harness gateway API, then asserts the guides on
getBoundingClientRect().left of the real rendered elements:

- guide 1: folder glyph on its border-l connector line (depth 1 and 2)
- guide 2: folder name on the agent label / title of its sessions
  (depth 1 and 2)
- guide 3: nested folder glyph on its sibling sessions' content column,
  and the root-lane identity (ungrouped content on the root glyph)
- depth invariance: the depth-2 connector on depth 1's content column

Falsified against the historical regression class: rebuilding with
FOLDER_BODY_INSET_PX bumped 2 -> 4 fails the spec with
"fGlyph=259 vs fConnector=261" while the jsdom test stays green. The
missing-selector diagnostics were falsified the same way (a broken
selector fails with "missing: [aAgent, ...]", not a bare timeout).

Pre-push review (GPT + Opus model-pinned): no blocking. Fixed advisory
findings: absolute coherence anchors so difference-only assertions cannot
hold vacuously at left=0; seeding requests assert response.ok() so a
4xx fails as a seeding fault, not an alignment fault; the settle poll
subsumes the render wait (budget fits the 30s test timeout) and names
missing selectors; the serial-run dependency on the wipe discipline in
session-tags-folders.spec.ts is documented in the header.

The tool-call subtitle is not asserted: it needs a live agent turn to
render, is a sibling of the title inside the same block container (equal
left by construction), and its class parity is pinned by the jsdom test.

MIN_EXECUTED_SPECS raised 219 -> 220 for the added spec.

Closes #3914
bolichen97 pushed a commit that referenced this pull request Aug 16, 2026
… (#3942)

The sidebar's three folder alignment guides have regressed four times
(#1211, #3766, #3903, and twice on paper inside #3905), every time via a
Tailwind-class derivation that omitted the 2px FOLDER_BODY_INSET_PX
container differential between the folder header's box and the nested
body's box. The jsdom test (ChatSidebar.folderAlignment.test.tsx) cannot
catch that class of break: jsdom has no layout engine, so it asserts
class tokens and an arithmetic identity between constants, never the
rendered geometry.

Add a Playwright spec to the `E2E (stub ACP backend, offline)` gate that
seeds one folder, one subfolder, and sessions in both plus one ungrouped
session via the harness gateway API, then asserts the guides on
getBoundingClientRect().left of the real rendered elements:

- guide 1: folder glyph on its border-l connector line (depth 1 and 2)
- guide 2: folder name on the agent label / title of its sessions
  (depth 1 and 2)
- guide 3: nested folder glyph on its sibling sessions' content column,
  and the root-lane identity (ungrouped content on the root glyph)
- depth invariance: the depth-2 connector on depth 1's content column

Falsified against the historical regression class: rebuilding with
FOLDER_BODY_INSET_PX bumped 2 -> 4 fails the spec with
"fGlyph=259 vs fConnector=261" while the jsdom test stays green. The
missing-selector diagnostics were falsified the same way (a broken
selector fails with "missing: [aAgent, ...]", not a bare timeout).

Pre-push review (GPT + Opus model-pinned): no blocking. Fixed advisory
findings: absolute coherence anchors so difference-only assertions cannot
hold vacuously at left=0; seeding requests assert response.ok() so a
4xx fails as a seeding fault, not an alignment fault; the settle poll
subsumes the render wait (budget fits the 30s test timeout) and names
missing selectors; the serial-run dependency on the wipe discipline in
session-tags-folders.spec.ts is documented in the header.

The tool-call subtitle is not asserted: it needs a live agent turn to
render, is a sibling of the title inside the same block container (equal
left by construction), and its class parity is pinned by the jsdom test.

MIN_EXECUTED_SPECS raised 219 -> 220 for the added spec.

Closes #3914

Co-authored-by: Joe Guo <zejiangg@amazon.com>
encomjp pushed a commit to encomjp/kirocrew-customapi that referenced this pull request Aug 22, 2026
encomjp pushed a commit to encomjp/kirocrew-customapi that referenced this pull request Aug 22, 2026
…dotdev#3905)

A folder in the session list and the sessions filed under it did not share a
left edge. kirodotdev#3766 added the row's status gutter as an in-flow flex child, so
its 12px width plus a gap landed on the content column: the agent label,
title and tool-call subtitle of every session inside a folder sat well right
of that folder's own name. kirodotdev#3903 then tightened the same rows and got
closer, but measured on a real render it still left the folder name 1px past
its sessions' text and a nested folder's glyph 2px short of their column.

Three guides now hold, in the root lane and at every nesting depth:

  1. a folder glyph sits on its own border-l connector line
  2. a folder name shares one edge with the agent label / title /
     tool-call subtitle of every session inside it
  3. a NESTED folder's glyph sits on the content column of the sessions
     filed beside it, so a subfolder reads as their peer

Solving all three simultaneously forces header pad == session row pad. With
D = 2, a MEASURED container differential (the header's box starts 2px left
of the nested body's box, and no class in the component expresses it):

  guide 1  P = D + M                       14 = 2 + 12
  guide 2  P + G + g = D + M + B + p + R   33 = 33
  guide 3  P = R                           14 = 14

The status gutter moves out of the content flow (absolutely positioned
inside that pad) and is centred on the row rather than deriving the
headline's y; in flow it is what broke guide 2, and no class-level assertion
could see it. Because the algebra has no per-depth term it is scale-free:
depth 3 nests as depth 2 does, and root-lane sessions land on the root
folder's glyph, which restores the original pre-kirodotdev#1211 guide.

Measured on the built SPA: depth 1 glyph/connector 259, name and all three
text lines 278; depth 2 glyph/connector 278 (== depth 1's content column),
name/content 297; root lane content 259.

This reverts kirodotdev#3903's row and folder geometry, agreed with its author. Its
collapsed-folder unread dot goes back inline on the right of the name rather
than into an absolute left gutter: that gutter is what forced the header pad
to 18px, and the pad is not free — it has to equal the session row's. The
2px colour bar from kirodotdev#3903 is kept, being orthogonal to the guides.

Also drop the title's mt-0.5 (row height 49.6 -> 43.6px idle, 68.1 -> 62.1
running), use lucide Loader for the running spinner (at 12px the
LoaderCircle arc reads as a broken ring where the spokes read as motion),
and pull the divider inset and the empty-folder "New chat in X" affordance
onto the same column as the sessions.

The alignment invariant test has been rewritten by each of the last two PRs
to accept the then-current misalignment. It now pins all three guides, adds
guide 3 at depth 2 with a nested fixture, and the gutter test pins the
gutter as out-of-flow and row-centred. Every number in the test header is a
measurement with its frame named: two paper estimates during this fix were
2px and 3px out.
encomjp pushed a commit to encomjp/kirocrew-customapi that referenced this pull request Aug 22, 2026
…dotdev#3914) (kirodotdev#3942)

The sidebar's three folder alignment guides have regressed four times
(kirodotdev#1211, kirodotdev#3766, kirodotdev#3903, and twice on paper inside kirodotdev#3905), every time via a
Tailwind-class derivation that omitted the 2px FOLDER_BODY_INSET_PX
container differential between the folder header's box and the nested
body's box. The jsdom test (ChatSidebar.folderAlignment.test.tsx) cannot
catch that class of break: jsdom has no layout engine, so it asserts
class tokens and an arithmetic identity between constants, never the
rendered geometry.

Add a Playwright spec to the `E2E (stub ACP backend, offline)` gate that
seeds one folder, one subfolder, and sessions in both plus one ungrouped
session via the harness gateway API, then asserts the guides on
getBoundingClientRect().left of the real rendered elements:

- guide 1: folder glyph on its border-l connector line (depth 1 and 2)
- guide 2: folder name on the agent label / title of its sessions
  (depth 1 and 2)
- guide 3: nested folder glyph on its sibling sessions' content column,
  and the root-lane identity (ungrouped content on the root glyph)
- depth invariance: the depth-2 connector on depth 1's content column

Falsified against the historical regression class: rebuilding with
FOLDER_BODY_INSET_PX bumped 2 -> 4 fails the spec with
"fGlyph=259 vs fConnector=261" while the jsdom test stays green. The
missing-selector diagnostics were falsified the same way (a broken
selector fails with "missing: [aAgent, ...]", not a bare timeout).

Pre-push review (GPT + Opus model-pinned): no blocking. Fixed advisory
findings: absolute coherence anchors so difference-only assertions cannot
hold vacuously at left=0; seeding requests assert response.ok() so a
4xx fails as a seeding fault, not an alignment fault; the settle poll
subsumes the render wait (budget fits the 30s test timeout) and names
missing selectors; the serial-run dependency on the wipe discipline in
session-tags-folders.spec.ts is documented in the header.

The tool-call subtitle is not asserted: it needs a live agent turn to
render, is a sibling of the title inside the same block container (equal
left by construction), and its class parity is pinned by the jsdom test.

MIN_EXECUTED_SPECS raised 219 -> 220 for the added spec.

Closes kirodotdev#3914

Co-authored-by: Joe Guo <zejiangg@amazon.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants