Skip to content

fix(ui): persistent session banner for boot + session context#359

Merged
dimakis merged 6 commits into
mainfrom
fix/session-banner-persistent
May 29, 2026
Merged

fix(ui): persistent session banner for boot + session context#359
dimakis merged 6 commits into
mainfrom
fix/session-banner-persistent

Conversation

@dimakis
Copy link
Copy Markdown
Owner

@dimakis dimakis commented May 29, 2026

Summary

  • Move boot context (ContexGin pill) and session context (Telos/inbox item) out of the scrollable chat message list into a new SessionBanner component
  • Banner renders between the header and chat area — always visible, never scrolls away
  • Collapsed (default): compact one-liner showing source count, token budget, and session context snippet
  • Expanded: full session context + nested boot context details, max-height 40vh with independent scroll
  • Full markdown modal retained for deep inspection

Fixes the mobile UX issue where boot/session context would clip, become unscrollable, and disappear entirely as chat messages accumulated.

Test plan

  • Start a session from a Telos item — verify session context shows in collapsed banner
  • Tap banner to expand — verify session context + boot context details render with scroll
  • Send several messages — verify banner stays pinned, doesn't scroll away
  • Verify full markdown modal (⧉) still works
  • Test on mobile viewport — banner should not exceed 40vh when expanded
  • Start a plain session (no Telos item) — verify boot context pill still shows alone

🤖 Generated with Claude Code

… scroll away

Move BootContextPill and ContextBlock out of the scrollable chat-messages
container into a new SessionBanner component rendered between the header
and message area. The banner is always visible, defaults to a compact
one-liner, and expands with its own scroll (max 40vh) for full details.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dimakis
Copy link
Copy Markdown
Owner Author

dimakis commented May 29, 2026

Centaur Review

Found 4 issue(s) (1 critical) (2 warning).

frontend/src/pages/DesktopChatView.tsx

Critical regression: DesktopChatView will fail to compile because it still passes removed ChatArea props and is missing the new SessionBanner component.

  • 🔴 regressions (L251): DesktopChatView still passes sessionContext and bootContext props to ChatArea, but these were removed from ChatAreaProps. This will cause a TypeScript compilation error. Additionally, DesktopChatView is missing the new <SessionBanner> component — desktop users lose visibility into boot/session context entirely. [fixable]

frontend/src/components/SessionBanner.tsx

Critical regression: DesktopChatView will fail to compile because it still passes removed ChatArea props and is missing the new SessionBanner component.

  • 🟡 missing_tests: New 219-line component with multiple interactive states (expand/collapse, boot details toggle, trimmed sections toggle, full-markdown modal with Escape-key handler) has no test coverage. The project requires TDD per CLAUDE.md. [fixable]
  • 🟡 bugs (L131): The 'View full markdown' button is nested inside the boot-toggle <button>. A <button> inside a <button> is invalid HTML and leads to unpredictable behavior across browsers. The inner button uses e.stopPropagation() to prevent the outer toggle, but DOM nesting is still invalid. Extract the inner button outside the outer <button> element. [fixable]

frontend/src/components/BootContextPill.tsx

Critical regression: DesktopChatView will fail to compile because it still passes removed ChatArea props and is missing the new SessionBanner component.

  • 🔵 style: BootContextPill and ContextBlock components are now unused — they were the old inline renderers replaced by SessionBanner. Consider removing them (or their CSS under the '/* legacy */' comment) to avoid dead code. [fixable]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Owner Author

@dimakis dimakis left a comment

Choose a reason for hiding this comment

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

Centaur Review

Found 5 issue(s) (2 warning).

frontend/src/components/BootContextPill.tsx

Clean structural refactor moving session context out of the scroll container. Main issues: two orphaned component files (BootContextPill, ContextBlock) should be deleted, nested button is invalid HTML, and no test coverage for the new component.

  • 🟡 style: BootContextPill.tsx is now dead code — no remaining imports anywhere in the codebase after ChatArea stopped using it. Should be deleted in this PR along with its CSS (.boot-context-pill styles in global.css). [fixable]

frontend/src/components/ContextBlock.tsx

Clean structural refactor moving session context out of the scroll container. Main issues: two orphaned component files (BootContextPill, ContextBlock) should be deleted, nested button is invalid HTML, and no test coverage for the new component.

  • 🟡 style: ContextBlock.tsx is now dead code — no remaining imports. Its CSS (.context-block styles, kept as '— legacy' in global.css) and the file itself should be removed in this PR. [fixable]

frontend/src/components/SessionBanner.tsx

Clean structural refactor moving session context out of the scroll container. Main issues: two orphaned component files (BootContextPill, ContextBlock) should be deleted, nested button is invalid HTML, and no test coverage for the new component.

  • 🔵 missing_tests: New 217-line component with expand/collapse, modal, and conditional rendering has no test file. A basic test covering: renders null when both props are null, renders banner header when bootContext provided, renders session context summary when sessionContext provided, and expand toggle would prevent regressions. [fixable]
  • 🔵 bugs (L143): The nested button (.session-banner-view-full '⧉') inside the outer button (.session-banner-boot-toggle) is invalid HTML (buttons cannot nest). While e.stopPropagation prevents functional issues in most browsers, screen readers and HTML validators will flag this. Consider using a span with role='button' and tabIndex/onKeyDown, or restructure so the outer element is a div with onClick. [fixable]
  • 🔵 style (L48): The component manages 4 independent boolean states (expanded, showBootDetails, showTrimmed, showModal). These never reset when props change — if a user expands details for one session, switches to another session with different context, the expand states persist from the prior session. Consider adding a useEffect that resets expand states when bootContext/sessionContext identity changes. [fixable]

{showBootDetails && (
<div className="session-banner-boot-content">
<div className="session-banner-sub-label">Sources</div>
{bootContext.sources.map((src, idx) => (
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🔵 bugs: The nested button (.session-banner-view-full '⧉') inside the outer button (.session-banner-boot-toggle) is invalid HTML (buttons cannot nest). While e.stopPropagation prevents functional issues in most browsers, screen readers and HTML validators will flag this. Consider using a span with role='button' and tabIndex/onKeyDown, or restructure so the outer element is a div with onClick. [fixable]

return first.length > 80 ? first.slice(0, 77) + '...' : first;
}

export function SessionBanner({ bootContext, sessionContext }: Props) {
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🔵 style: The component manages 4 independent boolean states (expanded, showBootDetails, showTrimmed, showModal). These never reset when props change — if a user expands details for one session, switches to another session with different context, the expand states persist from the prior session. Consider adding a useEffect that resets expand states when bootContext/sessionContext identity changes. [fixable]

dimakis and others added 3 commits May 29, 2026 17:14
- Delete orphaned BootContextPill.tsx and ContextBlock.tsx
- Remove all legacy .context-block and .boot-context-pill CSS
- Fix nested button (invalid HTML) — use div[role=button] for boot toggle
- Reset expand states on session switch via useEffect
- Add SessionBanner test suite (5 tests)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dimakis
Copy link
Copy Markdown
Owner Author

dimakis commented May 29, 2026

/centaur-review

Copy link
Copy Markdown
Owner Author

@dimakis dimakis left a comment

Choose a reason for hiding this comment

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

Centaur Review

Found 3 issue(s) (1 warning).

frontend/src/components/SessionBanner.tsx

Clean consolidation of two components into one persistent banner. No regressions in callers or tests. Minor a11y nit with nested interactive control inside role="button" and a weak context-change key.

  • 🟡 bugs (L141): A <button> ("view full markdown") is nested inside a <div role="button"> (boot-toggle). While this fixes the previous invalid <button> inside <button>, the ARIA spec still flags interactive controls inside role="button" as problematic for assistive technology. Consider moving the ⧉ button outside the toggle div, e.g. as a sibling in a wrapper flex row. [fixable]
  • 🔵 unsafe_assumptions (L65): contextKey uses tokenCount + '|' + sessionContext to detect session switches. If two sessions share the same tokenCount and sessionContext, the expand states won't reset. A more robust key could include sourceCount or the first source path, e.g. bootContext?.sources[0]?.path. [fixable]

frontend/src/components/__tests__/SessionBanner.test.tsx

Clean consolidation of two components into one persistent banner. No regressions in callers or tests. Minor a11y nit with nested interactive control inside role="button" and a weak context-change key.

  • 🔵 missing_tests: Tests cover collapsed rendering and first-level expand, but don't cover: boot context details expansion (showBootDetails toggle), trimmed sections toggle, the full-markdown modal open/close, or the Escape key handler. These are interactive paths ported from the deleted BootContextPill and could regress silently. [fixable]

Boot Context ({isContexgin ? 'ContexGin' : 'Fallback'})
</span>
{bootContext.fullMarkdown && (
<button
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🟡 bugs: A <button> ("view full markdown") is nested inside a <div role="button"> (boot-toggle). While this fixes the previous invalid <button> inside <button>, the ARIA spec still flags interactive controls inside role="button" as problematic for assistive technology. Consider moving the ⧉ button outside the toggle div, e.g. as a sibling in a wrapper flex row. [fixable]

}, [showModal]);

// Reset expand states when context identity changes (e.g. session switch)
const contextKey = (bootContext?.tokenCount ?? '') + '|' + (sessionContext ?? '');
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🔵 unsafe_assumptions: contextKey uses tokenCount + '|' + sessionContext to detect session switches. If two sessions share the same tokenCount and sessionContext, the expand states won't reset. A more robust key could include sourceCount or the first source path, e.g. bootContext?.sources[0]?.path. [fixable]

…ests

- Move ⧉ button outside role="button" div as sibling in flex row
- Strengthen contextKey with sourceCount + first source path
- Add tests for boot details toggle, modal open/close, Escape key

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dimakis dimakis merged commit da6e95e into main May 29, 2026
1 check passed
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.

1 participant