Skip to content

feat(ui): polish paper operations surface#193

Merged
Whiteks1 merged 1 commit intomainfrom
codex/paper-ui-ops-polish
Mar 27, 2026
Merged

feat(ui): polish paper operations surface#193
Whiteks1 merged 1 commit intomainfrom
codex/paper-ui-ops-polish

Conversation

@Whiteks1
Copy link
Copy Markdown
Owner

@Whiteks1 Whiteks1 commented Mar 27, 2026

Summary

This PR sharpens the local paper-operations surface in the research UI while keeping it fully read-only.

Changes included:

  • add a dedicated paper operations panel in the Ops view
  • add a read-only /api/paper-sessions-alerts endpoint in
    esearch_ui/server.py
  • fetch paper health plus paper alerts together in the UI
  • surface freshness, running-session count, stale threshold, latest success, and latest issue context
  • render active paper alerts directly in the Ops view instead of only showing a compact count
  • add focused server tests for the new paper alerts payload

Why

QuantLab already had strong paper-session artifacts and CLI inspection, but the local UI still treated paper ops as a small summary card.

At the current state of the repo, that underrepresented one of the most operator-facing parts of QuantLab. This slice makes paper ops easier to read at a glance without inventing controls or drifting away from the artifact-first design.

Scope

This PR does not:

  • add write actions or paper controls in the UI
  • change paper-session runtime behavior
  • change broker or Hyperliquid execution logic

It focuses only on improving read-only paper-session visibility and freshness signaling.

Validation

Validated with:

  • python -m pytest -q test/test_research_ui_server.py
  • python -m py_compile research_ui/server.py

ode --check research_ui/app.js

  • git diff --check

Notes

  • the paper ops panel is intentionally artifact-driven and read-only
  • there is a separate unrelated local modification in desktop/renderer/index.html; it is not included in this PR

Closes #80

Summary by Sourcery

Introduce a richer, read-only paper operations surface in the research UI powered by a new paper alerts API payload.

New Features:

  • Expose a new /api/paper-sessions-alerts endpoint that summarizes paper session alerts and freshness state.
  • Add a dedicated paper operations panel in the Ops view that surfaces paper health, alerts, and session statistics.

Enhancements:

  • Update the Ops summary and surface summary text to reflect active paper alerts when present.
  • Expand the UI styling with signal chips, stat cards, and alert rows to better communicate paper-session status.

Tests:

  • Add focused tests for the paper alerts payload to cover empty and populated paper-session roots.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Mar 27, 2026

Reviewer's Guide

Adds a dedicated, read-only paper operations surface in the research UI by introducing a new paper alerts API endpoint, wiring it into the frontend state/rendering, and styling a richer paper-ops panel, along with focused server tests for the new payload.

Sequence diagram for loading paper health and alerts in the Ops view

sequenceDiagram
    actor Operator
    participant BrowserApp as Browser_AppJS
    participant Server as Research_UI_Server
    participant FS as FileSystem_paper_sessions

    Operator->>BrowserApp: Open Ops view / refresh
    BrowserApp->>BrowserApp: fetchAll(showNotice, silent)
    BrowserApp->>Server: GET /api/paper-sessions-health
    BrowserApp->>Server: GET /api/paper-sessions-alerts
    BrowserApp->>Server: GET /api/broker-submissions-health

    Server->>FS: build_paper_health_payload(project_root)
    FS-->>Server: Read paper_sessions data
    Server-->>BrowserApp: 200 JSON paperHealth

    Server->>FS: build_paper_alerts_payload(project_root)
    FS-->>Server: build_paper_sessions_alerts(paper_root)
    Server-->>BrowserApp: 200 JSON paperAlerts

    Server-->>BrowserApp: 200 JSON brokerHealth

    BrowserApp->>BrowserApp: Update state.paperHealth
    BrowserApp->>BrowserApp: Update state.paperAlerts

    BrowserApp->>BrowserApp: renderOps()
    BrowserApp->>BrowserApp: buildPaperMeta(health, alerts)
    BrowserApp->>BrowserApp: buildPaperSummary(health, alerts)
    BrowserApp->>BrowserApp: buildPaperPanel(health, alerts)

    BrowserApp->>Operator: Updated Ops view with paper panel
Loading

File-Level Changes

Change Details Files
Introduce paper alerts API endpoint and payload builder for paper sessions
  • Add /api/paper-sessions-alerts route in the research UI server that returns paper alert summaries
  • Implement build_paper_alerts_payload to read paper session outputs, return zero-state when missing, and wrap build_paper_sessions_alerts output
  • Ensure error handling returns a structured payload with status and availability flags
research_ui/server.py
Fetch paper alerts in the frontend and integrate them into ops rendering and summaries
  • Extend CONFIG and global state to include paperAlertsPath and paperAlerts
  • Update fetchAll to request paper alerts alongside paper health and populate state with a default fallback payload
  • Pass paperAlerts into renderOps and update paper-related DOM bindings and ops summary text to reflect alert presence
research_ui/app.js
Render a richer paper operations panel showing health, freshness, and alerts
  • Add new helpers to compute paper meta, summary, and a detailed paper panel combining health and alerts
  • Introduce relative time formatting, alert tone mapping, and small stat-card helpers for the paper panel
  • Update top-level surface summary copy to indicate when paper attention is required
research_ui/app.js
Add styles for chips and the new paper ops panel layout
  • Define chip tone classes for calm, running, and attention states
  • Add layout and typography styles for the ops signal strip, stat grid/cards, and alert list rows
  • Make ops-stat-grid responsive in existing media queries
research_ui/styles.css
Expose a dedicated paper operations panel in the Ops view markup
  • Insert a new ops-panel section for paper operations with header, summary container, and panel body placeholder
  • Wire DOM ids used by the JS render functions for summary text and panel body content
research_ui/index.html
Add tests for the paper alerts payload behavior
  • Test zero-state behavior when the paper sessions root directory is missing
  • Test summarization behavior when successful and failed paper sessions exist, including counts and latest alert metadata
test/test_research_ui_server.py

Assessment against linked issues

Issue Objective Addressed Explanation
#80 Improve the paper-operations visual hierarchy and status signaling in the research UI while keeping it read-only.
#80 Enhance paper-session health, alerts, freshness, and empty/error states (including clearer paper-session signals and smoother ops/run interaction) in the dashboard.
#80 Preserve the artifact-driven, low-coupling, read-only nature of the local research UI without adding execution controls or broker/runtime changes.

Possibly linked issues

  • Stage C.1: polish research UI for paper operations #80: The PR implements the requested polished paper-ops UI, adding detailed paper health, alerts, and freshness signals.
  • #unknown: PR implements the paper-session health and alerts UI refresh and server helpers requested for Stage C.1.
  • #: They both add a deterministic local paper-session alert surface, including success/failure and stale/running visibility via JSON endpoint.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 2 security issues, and 1 other issue

Security issues:

  • User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in a elements.paperPanelBody.innerHTML is an anti-pattern that can lead to XSS vulnerabilities (link)
Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="test/test_research_ui_server.py" line_range="319-328" />
<code_context>
+    assert payload["alerts"] == []
+
+
+def test_build_paper_alerts_payload_summarizes_existing_alerts(tmp_path: Path):
+    paper_root = tmp_path / "outputs" / "paper_sessions"
+    _write_session(paper_root, "paper_001", "success")
+    _write_session(paper_root, "paper_002", "failed")
+
+    payload, status = research_ui_server.build_paper_alerts_payload(tmp_path)
+
+    assert status == 200
+    assert payload["status"] == "ok"
+    assert payload["available"] is True
+    assert payload["total_sessions"] == 2
+    assert payload["has_alerts"] is True
+    assert payload["alert_status"] == "critical"
+    assert payload["latest_success_session_id"] == "paper_001"
+    assert payload["latest_alert_session_id"] == "paper_002"
+    assert payload["latest_alert_code"] == "PAPER_SESSION_FAILED"
+    assert payload["alert_counts"]["critical"] == 1
+
+
</code_context>
<issue_to_address>
**issue (testing):** Add a test for the error path when alert summarization fails, ensuring the 500 status and error payload are exercised.

Currently we only verify the missing-root and successful-summarization paths. Since `build_paper_alerts_payload` catches exceptions from `research_ui_server.build_paper_sessions_alerts` and returns a 500 with `{"status": "error", "available": False, "root_dir": ..., "message": str(exc)}`, please add a test that monkeypatches `build_paper_sessions_alerts` to raise. That test should assert the 500 status and that the payload has `status == "error"`, `available is False`, and the expected `root_dir` so the error branch is covered.
</issue_to_address>

### Comment 2
<location path="research_ui/app.js" line_range="715" />
<code_context>
    elements.paperPanelBody.innerHTML = buildPaperPanel(paperHealth, paperAlerts);
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-document-method):** User controlled data in methods like `innerHTML`, `outerHTML` or `document.write` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 3
<location path="research_ui/app.js" line_range="715" />
<code_context>
    elements.paperPanelBody.innerHTML = buildPaperPanel(paperHealth, paperAlerts);
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-innerhtml):** User controlled data in a `elements.paperPanelBody.innerHTML` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +319 to +328
def test_build_paper_alerts_payload_summarizes_existing_alerts(tmp_path: Path):
paper_root = tmp_path / "outputs" / "paper_sessions"
_write_session(paper_root, "paper_001", "success")
_write_session(paper_root, "paper_002", "failed")

payload, status = research_ui_server.build_paper_alerts_payload(tmp_path)

assert status == 200
assert payload["status"] == "ok"
assert payload["available"] is True
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (testing): Add a test for the error path when alert summarization fails, ensuring the 500 status and error payload are exercised.

Currently we only verify the missing-root and successful-summarization paths. Since build_paper_alerts_payload catches exceptions from research_ui_server.build_paper_sessions_alerts and returns a 500 with {"status": "error", "available": False, "root_dir": ..., "message": str(exc)}, please add a test that monkeypatches build_paper_sessions_alerts to raise. That test should assert the 500 status and that the payload has status == "error", available is False, and the expected root_dir so the error branch is covered.

elements.paperHealthMeta.textContent = buildPaperMeta(paperHealth);
elements.paperHealthMeta.textContent = buildPaperMeta(paperHealth, paperAlerts);
elements.paperSummary.textContent = buildPaperSummary(paperHealth, paperAlerts);
elements.paperPanelBody.innerHTML = buildPaperPanel(paperHealth, paperAlerts);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security (javascript.browser.security.insecure-document-method): User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

elements.paperHealthMeta.textContent = buildPaperMeta(paperHealth);
elements.paperHealthMeta.textContent = buildPaperMeta(paperHealth, paperAlerts);
elements.paperSummary.textContent = buildPaperSummary(paperHealth, paperAlerts);
elements.paperPanelBody.innerHTML = buildPaperPanel(paperHealth, paperAlerts);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security (javascript.browser.security.insecure-innerhtml): User controlled data in a elements.paperPanelBody.innerHTML is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

@Whiteks1 Whiteks1 merged commit 877f33e into main Mar 27, 2026
1 of 2 checks passed
@Whiteks1 Whiteks1 deleted the codex/paper-ui-ops-polish branch March 27, 2026 23:02
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.

Stage C.1: polish research UI for paper operations

1 participant