Skip to content

fix: correct Strix model to github_models/gpt-4o - #222

Merged
11 commits merged into
masterfrom
fix/strix-model-gpt4o
May 24, 2026
Merged

fix: correct Strix model to github_models/gpt-4o#222
11 commits merged into
masterfrom
fix/strix-model-gpt4o

Conversation

@seonghobae

@seonghobae seonghobae commented May 24, 2026

Copy link
Copy Markdown
Contributor

Fixes Strix scanner failure caused by unsupported gpt-5.4 model.

Summary by CodeRabbit

  • New Features

    • WebDAV integration: connect document storage accounts and browse project folders in-app.
    • Email UI: badges for pending replies and schedule conflicts (Korean labels).
    • Tasks: richer assigned/delegated task views and detailed task panel.
    • CalDAV writeback targeting and self‑hosted connector support.
    • Local infra: Keycloak dev service for local setups.
  • Tests

    • Mobile hamburger E2E and WebDAV API tests added; unit tests for CalDAV/ontology.
  • Documentation

    • Architecture and branding implementation plans added.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 24, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@seonghobae, we couldn't start this review because you've used your available PR reviews for now.

Your plan includes 5 reviews of capacity. Refill in 23 minutes and 14 seconds.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more review capacity refills, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than trial, open-source, and free plans. In all cases, review capacity refills continuously over time.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 150a5723-54c3-47f0-b2b1-161b3d9a0d08

📥 Commits

Reviewing files that changed from the base of the PR and between 911a69e and 7e44cf0.

📒 Files selected for processing (1)
  • frontend/tests/e2e/mobile-hamburger.spec.ts

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key: "version"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
📝 Walkthrough

Walkthrough

This PR adds email analysis and ontology services, CalDAV writeback routing, a self-hosted WebSocket connector, WebDAV API/service/models with tests, frontend WebDAV/UI wiring and email badges, infra/docs updates, and a Strix CI model identifier change.

Changes

Email metadata, CalDAV routing, WebSocket connector, WebDAV integration, and frontend UI wiring

Layer / File(s) Summary
Strix CI model governance
.github/workflows/strix.yml, AGENTS.md
Strix model identifier changed to github_models/gpt-4o in workflow and governance doc.
Self-hosted WebSocket connector with optional dependency
backend/runner/connector.py, backend/requirements.txt
Adds SelfHostedConnector (optional websockets import) with bearer-token auth, async connect/listen loop, message handler stub, response sender, and websockets==14.1 dependency.
Connector registration and gateway config schemas
backend/schema/connector.py
Pydantic models for connector registration request/response and OIDC gateway config with strict extra-field handling and typed fields.
Email processing helpers and ontology service
backend/services/email_service.py, backend/services/ontology_service.py, backend/tests/test_ontology.py
Adds fingerprinting, reply-tracking, and self-to-self detection; OntologyService.analyze_sender_relationship classifies Newsletter/Colleague/Unknown and is unit-tested.
CalDAV writeback target routing
backend/services/caldav_service.py, backend/tests/test_caldav.py
CalDavService.determine_writeback_target matches exact source email domain among connected accounts, falls back to primary account or default_system_caldav; tests cover substring-collision and no-accounts cases.
WebDAV API, service, database models, and tests
backend/api/webdav.py, backend/services/webdav_service.py, backend/db/models.py, backend/main.py, backend/tests/test_webdav_api.py
Adds /api/webdav router with /accounts and /folders endpoints backed by a mocked WebDavService; introduces WebdavAccount and ProjectFolder ORM models (encrypted credentials) and tests validating responses.
Email list and detail UI metadata badges
frontend/src/components/EmailDetail.tsx, frontend/src/components/EmailList.tsx
Extends email data shapes with requires_reply and schedule_conflict; renders conditional Korean badges and localizes search input labels.
Frontend DataLayout WebDAV wiring and TasksLayout view implementations
frontend/src/components/DataLayout.tsx, frontend/src/components/TasksLayout.tsx
DataLayout fetches and displays WebDAV accounts and project folders; TasksLayout enriches mock tasks and implements three concrete non-Kanban views with filtering and status UI.
Mobile hamburger menu and safe-area E2E tests
frontend/tests/e2e/mobile-hamburger.spec.ts
Playwright spec for mobile hamburger menu open/close behavior and bottom-navigation safe-area padding.
Keycloak service, implementation plans, observability tests, and metadata
docker-compose.infra.yml, docs/plans/2026-05-24-architecture-implementation.md, docs/plans/2026-05-24-branding-implementation.md, .vooster/project.json, backend/tests/test_apm_observability.py
Adds Keycloak dev service to infra compose, new implementation plan docs, project metadata file, and fixes APM observability test path resolution.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 I nibble logs and badges in a breeze,

websockets hum and WebDAV leaves,
CalDAV paths I gently trace,
tests and docs in tidy place.
Hop — merge, then I snack on keys.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix: correct Strix model to github_models/gpt-4o' accurately reflects the primary change in the changeset, which is updating the Strix model identifier from gpt-5.4 to gpt-4o across workflow and documentation files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/strix-model-gpt4o

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented May 24, 2026

Copy link
Copy Markdown
Contributor

PR governance metadata gate is not ready for 7e44cf0fe92356877a8964a7713e74b354970371:

  • Review decision is CHANGES_REQUESTED; address requested changes before merge.
  • 6 unresolved current review thread(s) remain.
  • Current-head CodeRabbit issue comment has blocking warning/failure evidence on 7e44cf0.
  • Current-head CodeRabbit review comment has blocking warning/failure evidence on 7e44cf0.

Comment thread backend/runner/connector.py Fixed
Comment thread backend/api/caldav_sync.py Fixed
@@ -0,0 +1,18 @@
import pytest
@@ -0,0 +1,11 @@
import pytest

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Nitpick comments (2)
backend/tests/test_caldav.py (1)

4-18: ⚡ Quick win

Add regression cases for exact-domain matching and empty-account fallback.

Current coverage misses the two highest-risk branches: rejecting substring domain collisions and returning "default_system_caldav" when no accounts exist.

Suggested additions
 def test_determine_writeback_target():
@@
     assert target_2 == "account1"
+
+    # Should not match substring domain collisions
+    task_context_3 = {"source_email": "attacker@evilcompany.com"}
+    target_3 = caldav_service.determine_writeback_target(task_context_3, connected_accounts)
+    assert target_3 == "account1"  # fallback, not domain match
+
+def test_determine_writeback_target_no_accounts():
+    task_context = {"source_email": "boss@company.com"}
+    target = caldav_service.determine_writeback_target(task_context, [])
+    assert target == "default_system_caldav"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/tests/test_caldav.py` around lines 4 - 18, Add two regression tests
for caldav_service.determine_writeback_target: one to verify exact-domain
matching (create connected_accounts with an account for "company.com" and
another for "mycompany.com" or "notcompany.com", call determine_writeback_target
with source_email "user@company.com" and assert it returns the "company.com"
account_id to avoid substring collisions), and one to verify empty-account
fallback (call determine_writeback_target with connected_accounts = [] and any
task_context and assert it returns "default_system_caldav"); update the
test_determine_writeback_target in backend/tests/test_caldav.py to include these
assertions referencing caldav_service.determine_writeback_target.
backend/tests/test_ontology.py (1)

4-11: ⚡ Quick win

Add a mixed-case domain regression assertion.

This test currently won’t catch case-related domain classification regressions.

Proposed test addition
 def test_analyze_sender_relationship():
@@
     result2 = ontology_service.analyze_sender_relationship("seongho@company.com", "boss@company.com", "Hello")
     assert result2["type"] == "Colleague"
     assert result2["confidence"] == 0.85
+
+    result3 = ontology_service.analyze_sender_relationship("seongho@company.com", "Boss@Company.com", "Hello")
+    assert result3["type"] == "Colleague"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/tests/test_ontology.py` around lines 4 - 11, The test should include
a mixed-case domain input to ensure domain classification is case-insensitive:
update test_analyze_sender_relationship to call
ontology_service.analyze_sender_relationship with a sender like
"SeongHo@Company.COM" or recipient "Newsletter@Marketing.COM" (matching the
existing newsletter case) and assert the same expected outputs (e.g., type
"Newsletter" and confidence 0.9) as the lowercase case; reference the existing
test function name test_analyze_sender_relationship and the method
ontology_service.analyze_sender_relationship to locate where to add this
assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/api/caldav_sync.py`:
- Around line 6-15: The new register_writeback_intent endpoint duplicates the
/writeback-intent contract and bypasses the existing typed/authorized flow;
remove this function or refactor it to reuse the existing contract and
auth/context from backend/api/calendar.py by accepting the same Pydantic request
model and the same auth dependency (owner/source-scoped context), perform
validation using that model instead of raw Dict[str, Any], and return the same
typed response shape; reference the register_writeback_intent function and the
/writeback-intent route here to either delete the duplicate or wire it into the
existing calendar.py request/response and authorization utilities.
- Around line 4-7: The router currently exposes private endpoints (e.g.,
register_writeback_intent) without the required signed-session auth; update the
router to enforce get_auth_context as a default dependency (e.g., construct
APIRouter with dependencies including Depends(get_auth_context)) and ensure
get_auth_context (and fastapi.Depends) is imported; this will apply the
signed-session auth to all handlers on router (including
register_writeback_intent) per backend API auth baseline.

In `@backend/runner/connector.py`:
- Around line 31-33: The except block in the connect/listen path that currently
uses "except Exception as e:" should be replaced by catching expected connection
errors (e.g., ConnectionRefusedError, OSError, asyncio.TimeoutError, and
websocket-specific exceptions such as
websockets.exceptions.InvalidURI/InvalidHandshake) and handling them by setting
self.is_connected = False and logging the full traceback with
logger.exception(...) (instead of logger.error). For any truly unexpected
exceptions re-raise them (or let them propagate) so programming errors aren't
swallowed; update the block around the connect/listen code that contains
logger.error(...) and self.is_connected to implement these specific exception
handlers.
- Line 27: Change the websockets.connect call in the connector (where
self.connection is assigned) to use additional_headers=headers instead of
extra_headers to be compatible with websockets==14.1, and replace the bare
"except Exception" block with targeted handling: re-raise
asyncio.CancelledError, and catch only expected connection errors (e.g.,
websockets.InvalidHandshake, websockets.InvalidStatusCode,
websockets.WebSocketException and OSError) to log/handle them while letting
other programming errors surface.

In `@backend/services/caldav_service.py`:
- Around line 16-19: The current loop uses substring matching
(account.get("domain") in source_email) which can misroute accounts; instead
extract and normalize the sender domain from source_email (e.g., split on '@',
lower() and strip) and compare it for exact equality against a normalized
account domain (normalize account.get("domain") similarly) when iterating
connected_accounts; return account.get("account_id") only on exact match and
handle malformed or missing source_email by returning None/empty as appropriate.

In `@backend/services/email_service.py`:
- Around line 12-15: Normalize nullable or non-string email fields before
performing string ops: ensure email_data.get("body") is coerced to a string (or
default to "") before slicing to create body_snippet, and similarly coerce date
and other fields (sender, subject) before calling str() or other string methods;
update the assignments for body_snippet, date, sender, and subject to
validate/type-coerce the values (e.g., use a safe_str(value) pattern or explicit
checks) so slicing and str() cannot raise when body is None or non-string.
- Around line 31-35: The current self-to-self detection uses substring matching
on sender and recipients (variables sender, recipients, user_email) which
misclassifies addresses; change it to parse exact email addresses using
email.utils.getaddresses (or similar) to extract normalized addresses from
sender and recipients, then check user_email against the parsed sender address
and the set of parsed recipient addresses (use equality/membership, not
substring). Update the conditional in the function/method where logger.info is
called (the block referencing sender, recipients, user_email, logger) to use the
parsed addresses and remove the old substring check so the Ruff F541 lint error
is resolved.

In `@backend/services/ontology_service.py`:
- Around line 24-27: Normalize the email domains to a consistent case before
comparing them so domain comparison is case-insensitive: when extracting
user_domain and sender_domain in the function where those variables are set
(user_domain = user_email.split("@")[1], sender_domain =
sender_email.split("@")[1]), call a case-normalizing method (e.g., .lower() or
.casefold()) on both domains and then compare them; if equal, set
relationship_type = "Colleague" as before.

In `@docker-compose.infra.yml`:
- Around line 56-61: Remove the hardcoded KEYCLOAK_ADMIN and
KEYCLOAK_ADMIN_PASSWORD values and require external injection by replacing the
literals with compose variable substitutions (e.g., KEYCLOAK_ADMIN:
"${KEYCLOAK_ADMIN:?KEYCLOAK_ADMIN is not set}" and KEYCLOAK_ADMIN_PASSWORD:
"${KEYCLOAK_ADMIN_PASSWORD:?KEYCLOAK_ADMIN_PASSWORD is not set}") so the service
will fail fast if not provided; update the environment block that currently sets
KEYCLOAK_ADMIN and KEYCLOAK_ADMIN_PASSWORD and ensure any deployment/CI docs or
secrets management supplies these variables instead of committing credentials.

---

Nitpick comments:
In `@backend/tests/test_caldav.py`:
- Around line 4-18: Add two regression tests for
caldav_service.determine_writeback_target: one to verify exact-domain matching
(create connected_accounts with an account for "company.com" and another for
"mycompany.com" or "notcompany.com", call determine_writeback_target with
source_email "user@company.com" and assert it returns the "company.com"
account_id to avoid substring collisions), and one to verify empty-account
fallback (call determine_writeback_target with connected_accounts = [] and any
task_context and assert it returns "default_system_caldav"); update the
test_determine_writeback_target in backend/tests/test_caldav.py to include these
assertions referencing caldav_service.determine_writeback_target.

In `@backend/tests/test_ontology.py`:
- Around line 4-11: The test should include a mixed-case domain input to ensure
domain classification is case-insensitive: update
test_analyze_sender_relationship to call
ontology_service.analyze_sender_relationship with a sender like
"SeongHo@Company.COM" or recipient "Newsletter@Marketing.COM" (matching the
existing newsletter case) and assert the same expected outputs (e.g., type
"Newsletter" and confidence 0.9) as the lowercase case; reference the existing
test function name test_analyze_sender_relationship and the method
ontology_service.analyze_sender_relationship to locate where to add this
assertion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a78f85a9-344c-4bce-908e-6adb66db8dec

📥 Commits

Reviewing files that changed from the base of the PR and between d693e4e and ebb45e0.

⛔ Files ignored due to path filters (50)
  • backend/__pycache__/import_fixtures.cpython-310.pyc is excluded by !**/*.pyc
  • backend/__pycache__/main.cpython-310.pyc is excluded by !**/*.pyc
  • backend/api/__pycache__/accounts.cpython-310.pyc is excluded by !**/*.pyc
  • backend/api/__pycache__/dav.cpython-310.pyc is excluded by !**/*.pyc
  • backend/api/__pycache__/emails.cpython-310.pyc is excluded by !**/*.pyc
  • backend/api/__pycache__/ontology.cpython-310.pyc is excluded by !**/*.pyc
  • backend/api/__pycache__/runner_ws.cpython-310.pyc is excluded by !**/*.pyc
  • backend/core/__pycache__/config.cpython-310.pyc is excluded by !**/*.pyc
  • backend/db/__pycache__/models.cpython-310.pyc is excluded by !**/*.pyc
  • backend/scripts/__pycache__/bootstrap_db.cpython-310.pyc is excluded by !**/*.pyc
  • backend/scripts/__pycache__/import_fixtures.cpython-310.pyc is excluded by !**/*.pyc
  • backend/services/__pycache__/access_policy.cpython-310.pyc is excluded by !**/*.pyc
  • backend/services/__pycache__/archive.cpython-310.pyc is excluded by !**/*.pyc
  • backend/services/__pycache__/calendar_sync.cpython-310.pyc is excluded by !**/*.pyc
  • backend/services/__pycache__/knowledge_extractor.cpython-310.pyc is excluded by !**/*.pyc
  • backend/services/__pycache__/text_safety.cpython-310.pyc is excluded by !**/*.pyc
  • backend/services/__pycache__/threading_service.cpython-310.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_access_policy.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_accounts_api.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_apm_observability.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_archive.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_auth_real.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_bootstrap_db.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_calendar_api.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_calendar_service.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_calendar_sync.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_config.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_dav_api.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_email_client.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_email_client_smtp.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_email_parser.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_emails_api.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_import_fixtures.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_knowledge_extractor.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_llm_api.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_llm_providers_api.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_llm_service.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_main.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_network_api.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_ontology_api.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_prompts_api.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_release_governance.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_repo_hygiene.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_runtime_config_api.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_search.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_tasks_api.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_tenant_config_api.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_tenant_config_model.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_text_safety.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_threading_service.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
📒 Files selected for processing (13)
  • .github/workflows/strix.yml
  • AGENTS.md
  • backend/api/caldav_sync.py
  • backend/requirements.txt
  • backend/runner/connector.py
  • backend/services/caldav_service.py
  • backend/services/email_service.py
  • backend/services/ontology_service.py
  • backend/tests/test_caldav.py
  • backend/tests/test_ontology.py
  • docker-compose.infra.yml
  • frontend/src/components/EmailDetail.tsx
  • frontend/src/components/EmailList.tsx

Comment thread backend/api/caldav_sync.py Outdated
Comment thread backend/api/caldav_sync.py Outdated
Comment thread backend/runner/connector.py Outdated
Comment thread backend/runner/connector.py Outdated
Comment thread backend/services/caldav_service.py Outdated
Comment thread backend/services/email_service.py Outdated
Comment thread backend/services/email_service.py Outdated
Comment thread backend/services/ontology_service.py Outdated
Comment thread docker-compose.infra.yml
import pytest
from fastapi.testclient import TestClient
from main import app
from db.session import get_db
Comment thread backend/api/webdav.py
@@ -0,0 +1,28 @@
from fastapi import APIRouter, Depends, HTTPException, status
Comment thread backend/tests/test_apm_observability.py Fixed
async def handle_message(self, message: str | bytes):
# Dispatch message to internal SMTP/IMAP proxy handlers
logger.debug(f"Received instruction from gateway: {message}")
pass
@seonghobae

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 24, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@seonghobae
seonghobae enabled auto-merge May 24, 2026 21:00

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
backend/tests/test_ontology.py (1)

13-15: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Assert confidence for the case-insensitive colleague scenario as well.

Line 14 validates only type, so a confidence regression in the same path would pass unnoticed. Add assert result3["confidence"] == 0.85.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/tests/test_ontology.py` around lines 13 - 15, Add an assertion for
the confidence value in the case-insensitive colleague test: after calling
ontology_service.analyze_sender_relationship (the call assigned to result3), add
an assertion that result3["confidence"] == 0.85 so the test validates both type
and confidence for the "seongho@company.com" vs "Boss@Company.com" scenario and
will catch regressions to the confidence score.
frontend/src/components/TasksLayout.tsx (1)

37-55: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Dragged tasks keep their old status value after column move.

Line 49 pushes movedTask as-is into the new column, so task.status becomes inconsistent with its actual column and downstream views render stale status badges.

Minimal fix
       const [movedTask] = sourceList.splice(taskIndex, 1);
-      targetList.push(movedTask);
+      targetList.push({ ...movedTask, status: targetCol });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/TasksLayout.tsx` around lines 37 - 55, The drop
handler currently pushes movedTask unchanged so its status remains the old
column; in handleDrop update the task's status to the target column before
adding it to targetList (e.g. create a newTask = { ...movedTask, status:
targetCol } rather than pushing movedTask) to avoid stale status badges and to
avoid mutating the original object; then push newTask into targetList and return
the updated state via setTasks as you already do.
♻️ Duplicate comments (3)
backend/services/caldav_service.py (1)

17-18: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use right-split for safer domain extraction.

Line 18 uses split("@")[1], which can select the wrong segment when multiple @ exist and cause misrouting. Use rsplit("@", 1)[-1] on normalized input.

Proposed fix
-        if isinstance(source_email, str) and "@" in source_email:
-            source_domain = source_email.split("@")[1].lower().strip()
+        if isinstance(source_email, str) and "@" in source_email:
+            source_domain = source_email.strip().lower().rsplit("@", 1)[-1]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/services/caldav_service.py` around lines 17 - 18, The domain
extraction using source_email.split("@")[1] is unsafe for emails containing
multiple '@'; update the logic that computes source_domain (where source_email
is checked with isinstance(source_email, str) and "@" in source_email) to
normalize the input (lower().strip()) and then use rsplit("@", 1)[-1] to
reliably take the rightmost domain segment (retain the existing isinstance and
"@" guard and assign back to source_domain).
backend/services/email_service.py (1)

33-34: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle recipient lists without stringifying and normalize before compare.

Line 34 converts recipients to a single string, which can break parsing for list inputs. Line 39 also compares addresses case-sensitively. Normalize both sender/recipient/user addresses and preserve list inputs for getaddresses.

Proposed fix
 def process_self_to_self(email_data: Dict[str, Any], user_email: str) -> bool:
@@
-    sender_raw = str(email_data.get("sender") or "")
-    recipients_raw = str(email_data.get("recipients") or "")
+    sender_raw = str(email_data.get("sender") or "")
+    recipients_raw = email_data.get("recipients") or []
+    recipient_inputs = recipients_raw if isinstance(recipients_raw, list) else [recipients_raw]
+    recipient_inputs = [str(v) for v in recipient_inputs]
@@
-    _, sender_addr = email.utils.parseaddr(sender_raw)
-    parsed_recipients = [addr for _, addr in email.utils.getaddresses([recipients_raw])]
+    _, sender_addr = email.utils.parseaddr(sender_raw)
+    normalized_user = user_email.strip().lower()
+    normalized_sender = sender_addr.strip().lower()
+    parsed_recipients = {
+        addr.strip().lower()
+        for _, addr in email.utils.getaddresses(recipient_inputs)
+        if addr
+    }
@@
-    if user_email == sender_addr and user_email in parsed_recipients:
+    if normalized_user and normalized_user == normalized_sender and normalized_user in parsed_recipients:
         logger.info("Self-to-self email detected. Organizing as knowledge node.")
         return True

Also applies to: 36-40

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/services/email_service.py` around lines 33 - 34, The code currently
stringifies recipients and sender (sender_raw, recipients_raw) which breaks list
inputs and uses case-sensitive comparisons; update the email parsing in
email_service.py to avoid converting recipients to a single string—keep the
original list if present or join safely only for display—and pass the preserved
list into email.utils.getaddresses; normalize all addresses (sender, each
recipient, and the stored user address) to a canonical form (trim whitespace and
lowercase the mailbox part) before comparing in the logic that determines
ownership, and replace direct equality checks with comparisons against the
normalized forms so comparisons are case-insensitive and robust to list inputs.
backend/tests/test_apm_observability.py (1)

1-1: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove unused import.

The import os statement is not used anywhere in the file.

🧹 Proposed fix
-import os
 from pathlib import Path
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/tests/test_apm_observability.py` at line 1, Remove the unused import
statement "import os" from the top of the test file
(backend/tests/test_apm_observability.py); simply delete the line that declares
the os import so there are no unused imports in the module.
🧹 Nitpick comments (3)
backend/tests/test_webdav_api.py (1)

16-30: ⚡ Quick win

These tests are coupled to service fixture data, not just API contract.

If service internals change (e.g., DB-backed values), these tests may fail for the wrong reason. Prefer stubbing webdav_service methods in the test to keep API tests deterministic.

Example refactor
+from services.webdav_service import webdav_service
+
+@pytest.fixture(autouse=True)
+def stub_webdav_service(monkeypatch):
+    monkeypatch.setattr(
+        webdav_service,
+        "get_connected_accounts",
+        lambda user_id: [{"account_id": 1, "server_url": "https://example.test", "username": "alice"}],
+    )
+    monkeypatch.setattr(
+        webdav_service,
+        "get_project_folders",
+        lambda user_id: [{"folder_id": 1, "project_name": "Project A", "webdav_path": "/Projects/A"}],
+    )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/tests/test_webdav_api.py` around lines 16 - 30, The tests
test_get_webdav_accounts and test_get_project_folders are tightly coupled to
service fixture data; replace that coupling by stubbing the webdav_service
methods used by the API (e.g., webdav_service.get_accounts and
webdav_service.get_folders) so the tests assert the API contract only. In each
test, patch the service methods (via monkeypatch or a pytest fixture) to return
deterministic payloads matching the existing assertions, call the endpoints with
auth_client, and keep the same response assertions; ensure you revert/override
the real webdav_service usage so DB or internal changes won't affect these API
contract tests.
frontend/tests/e2e/mobile-hamburger.spec.ts (2)

6-34: 💤 Low value

Consider testing backdrop-click-to-close behavior.

The test validates closing via the dedicated close button, but the backdrop element also has an onClick handler that should close the menu. Consider adding a test case that clicks the backdrop to verify this alternative close path works correctly.

🧪 Suggested additional test case
test('Hamburger menu closes when backdrop is clicked', async ({ page }) => {
  await page.goto('/');
  
  const hamburgerBtn = page.getByRole('button', { name: '워크스페이스 메뉴 열기' });
  await hamburgerBtn.click();
  
  const menu = page.locator('`#mobile-workspace-menu`');
  await expect(menu).toBeVisible();
  
  // Close by clicking backdrop
  const backdrop = page.getByTestId('mobile-workspace-backdrop');
  await backdrop.click();
  
  await expect(menu).not.toBeVisible();
  await expect(hamburgerBtn).toHaveAttribute('aria-expanded', 'false');
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/tests/e2e/mobile-hamburger.spec.ts` around lines 6 - 34, Add a new
E2E test that verifies the backdrop click closes the mobile hamburger menu:
navigate to the root, use the existing hamburgerBtn locator
(page.getByRole('button', { name: '워크스페이스 메뉴 열기' })) to open the menu, assert
menu (locator '`#mobile-workspace-menu`') is visible, then click the backdrop
(page.getByTestId('mobile-workspace-backdrop')) and assert the menu is hidden
and hamburgerBtn has aria-expanded='false'; mirror the style and assertions used
in the existing test to keep consistency.

26-27: 💤 Low value

Remove or implement the TODO comment.

The comment mentions an optional body scroll check. Either implement this validation or remove the comment to keep the test file clean.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/tests/e2e/mobile-hamburger.spec.ts` around lines 26 - 27, In the
mobile-hamburger.spec.ts test remove the TODO-style comment or implement the
body-scroll validation: either delete the two comment lines about the optional
body scroll check, or add an assertion after opening the hamburger/popover that
the page scrolling is prevented (for example assert document.body.style.overflow
contains 'hidden' or attempt a programmatic scroll and verify
document.body.scrollTop/scrollY doesn't change) and then proceed to close via
the close button; update any selectors referenced in the test to the existing
popover/hamburger and close button helpers so the new check runs reliably.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/strix.yml:
- Line 85: The workflow sets the Strix model variable strix_llm to
"github_models/gpt-5.4" (appearing in the Gate Strix secrets, Gate model auth
prerequisites, and Prepare Strix model input file steps); change each occurrence
of the value for strix_llm from "github_models/gpt-5.4" to
"github_models/gpt-4o" so the pipeline uses the required gpt-4o model for Strix
scans and respects the PR intent and coding guidelines.

In `@backend/runner/connector.py`:
- Around line 54-59: The broad except Exception in
SelfHostedConnector._listen_loop is masking programming errors from
handle_message; narrow it to catch only expected shutdown exceptions (e.g.,
websockets.exceptions.ConnectionClosed and asyncio.CancelledError) and handle
them by logging the connection-close path and setting self.is_connected = False,
but for any other Exception log the full traceback (use logger.exception) and
re-raise so bugs aren't suppressed; update _listen_loop to import asyncio if
needed and ensure self.is_connected is cleared in the shutdown path or a finally
block.

In `@backend/services/webdav_service.py`:
- Around line 10-40: Both get_connected_accounts and get_project_folders
currently ignore the user_id parameter and always return shared hardcoded data,
which can cause cross-tenant exposure; update the two functions
(get_connected_accounts and get_project_folders) to scope results to the
provided user_id by using a per-user mock store or filtering the existing mock
list by a user identifier (e.g., add a user_id field to each mock entry or
maintain a dict mapping user_id -> list), return an empty list or raise a clear
error when no data exists for that user, and ensure the returned shapes remain
the same so callers (e.g., /api/webdav/accounts and /api/webdav/folders) receive
user-scoped results.

In `@frontend/src/components/TasksLayout.tsx`:
- Around line 159-205: The detail pane is not bound to the clicked task;
clicking items only calls setViewMode('작업 상세') and the "작업 상세" block renders
hardcoded values. Add a piece of state (e.g. selectedTaskId via useState) and
update the click handlers in both task lists to call setSelectedTaskId(task.id)
before setViewMode('작업 상세'); then, inside the "작업 상세" rendering, look up the
task from the tasks collection (e.g. const task =
Object.values(tasks).flat().find(t => t.id === selectedTaskId) or
tasks[selectedTaskId]) and render its fields (title, id, priority, due,
assignee, status, source) instead of hardcoded strings; also handle null
selectedTaskId (render a placeholder or return) and clear selectedTaskId when
leaving the detail view or switching views.

In `@frontend/tests/e2e/mobile-hamburger.spec.ts`:
- Around line 44-45: The test is checking paddingBottom on the bottomNav element
which is a false positive due to the p-2 class; instead evaluate the element's
positioning: replace the paddingBottom check with reading
window.getComputedStyle(el).bottom (using the bottomNav variable used in the
spec) and assert that the bottom value reflects the safe-area calc (e.g.
contains "calc" or is not "0px"); alternatively assert the element's classList
contains "bottom-[calc(0.75rem+env(safe-area-inset-bottom))]" to ensure the
safe-area positioning is applied.

---

Outside diff comments:
In `@backend/tests/test_ontology.py`:
- Around line 13-15: Add an assertion for the confidence value in the
case-insensitive colleague test: after calling
ontology_service.analyze_sender_relationship (the call assigned to result3), add
an assertion that result3["confidence"] == 0.85 so the test validates both type
and confidence for the "seongho@company.com" vs "Boss@Company.com" scenario and
will catch regressions to the confidence score.

In `@frontend/src/components/TasksLayout.tsx`:
- Around line 37-55: The drop handler currently pushes movedTask unchanged so
its status remains the old column; in handleDrop update the task's status to the
target column before adding it to targetList (e.g. create a newTask = {
...movedTask, status: targetCol } rather than pushing movedTask) to avoid stale
status badges and to avoid mutating the original object; then push newTask into
targetList and return the updated state via setTasks as you already do.

---

Duplicate comments:
In `@backend/services/caldav_service.py`:
- Around line 17-18: The domain extraction using source_email.split("@")[1] is
unsafe for emails containing multiple '@'; update the logic that computes
source_domain (where source_email is checked with isinstance(source_email, str)
and "@" in source_email) to normalize the input (lower().strip()) and then use
rsplit("@", 1)[-1] to reliably take the rightmost domain segment (retain the
existing isinstance and "@" guard and assign back to source_domain).

In `@backend/services/email_service.py`:
- Around line 33-34: The code currently stringifies recipients and sender
(sender_raw, recipients_raw) which breaks list inputs and uses case-sensitive
comparisons; update the email parsing in email_service.py to avoid converting
recipients to a single string—keep the original list if present or join safely
only for display—and pass the preserved list into email.utils.getaddresses;
normalize all addresses (sender, each recipient, and the stored user address) to
a canonical form (trim whitespace and lowercase the mailbox part) before
comparing in the logic that determines ownership, and replace direct equality
checks with comparisons against the normalized forms so comparisons are
case-insensitive and robust to list inputs.

In `@backend/tests/test_apm_observability.py`:
- Line 1: Remove the unused import statement "import os" from the top of the
test file (backend/tests/test_apm_observability.py); simply delete the line that
declares the os import so there are no unused imports in the module.

---

Nitpick comments:
In `@backend/tests/test_webdav_api.py`:
- Around line 16-30: The tests test_get_webdav_accounts and
test_get_project_folders are tightly coupled to service fixture data; replace
that coupling by stubbing the webdav_service methods used by the API (e.g.,
webdav_service.get_accounts and webdav_service.get_folders) so the tests assert
the API contract only. In each test, patch the service methods (via monkeypatch
or a pytest fixture) to return deterministic payloads matching the existing
assertions, call the endpoints with auth_client, and keep the same response
assertions; ensure you revert/override the real webdav_service usage so DB or
internal changes won't affect these API contract tests.

In `@frontend/tests/e2e/mobile-hamburger.spec.ts`:
- Around line 6-34: Add a new E2E test that verifies the backdrop click closes
the mobile hamburger menu: navigate to the root, use the existing hamburgerBtn
locator (page.getByRole('button', { name: '워크스페이스 메뉴 열기' })) to open the menu,
assert menu (locator '`#mobile-workspace-menu`') is visible, then click the
backdrop (page.getByTestId('mobile-workspace-backdrop')) and assert the menu is
hidden and hamburgerBtn has aria-expanded='false'; mirror the style and
assertions used in the existing test to keep consistency.
- Around line 26-27: In the mobile-hamburger.spec.ts test remove the TODO-style
comment or implement the body-scroll validation: either delete the two comment
lines about the optional body scroll check, or add an assertion after opening
the hamburger/popover that the page scrolling is prevented (for example assert
document.body.style.overflow contains 'hidden' or attempt a programmatic scroll
and verify document.body.scrollTop/scrollY doesn't change) and then proceed to
close via the close button; update any selectors referenced in the test to the
existing popover/hamburger and close button helpers so the new check runs
reliably.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b8d2dd03-a0c4-4704-8ec0-128cb3a05f09

📥 Commits

Reviewing files that changed from the base of the PR and between ebb45e0 and 8b148e3.

⛔ Files ignored due to path filters (5)
  • backend/__pycache__/main.cpython-310.pyc is excluded by !**/*.pyc
  • backend/db/__pycache__/models.cpython-310.pyc is excluded by !**/*.pyc
  • backend/scripts/__pycache__/bootstrap_db.cpython-310.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_apm_observability.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
  • backend/tests/__pycache__/test_search.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
📒 Files selected for processing (22)
  • .github/workflows/strix.yml
  • .vooster/project.json
  • backend/api/webdav.py
  • backend/db/models.py
  • backend/main.py
  • backend/runner/connector.py
  • backend/schema/connector.py
  • backend/services/caldav_service.py
  • backend/services/email_service.py
  • backend/services/ontology_service.py
  • backend/services/webdav_service.py
  • backend/tests/test_apm_observability.py
  • backend/tests/test_caldav.py
  • backend/tests/test_ontology.py
  • backend/tests/test_webdav_api.py
  • docker-compose.infra.yml
  • docs/plans/2026-05-24-architecture-implementation.md
  • docs/plans/2026-05-24-branding-implementation.md
  • frontend/src/components/DataLayout.tsx
  • frontend/src/components/EmailList.tsx
  • frontend/src/components/TasksLayout.tsx
  • frontend/tests/e2e/mobile-hamburger.spec.ts

Comment thread .github/workflows/strix.yml Outdated
Comment on lines +54 to +59
except Exception as e:
if websockets and isinstance(e, websockets.exceptions.ConnectionClosed):
logger.warning("Connection closed by remote gateway.")
else:
logger.warning(f"Connection loop ended: {e}")
self.is_connected = False

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Inspect broad catches in connector:"
rg -nP --type=py -C2 '\bexcept\s+Exception\b' backend/runner/connector.py

echo
echo "Inspect listen loop region:"
cat -n backend/runner/connector.py | sed -n '47,70p'

Repository: Seongho-Bae/naruon

Length of output: 1890


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Top of backend/runner/connector.py (imports + class header):"
cat -n backend/runner/connector.py | sed -n '1,120p'

echo
echo "Confirm whether asyncio is imported:"
rg -n --type=py '\bimport\s+asyncio\b|\bfrom\s+asyncio\s+import\b' backend/runner/connector.py

echo
echo "Confirm websockets import:"
rg -n --type=py '\bimport\s+websockets\b|\bfrom\s+websockets\s+import\b' backend/runner/connector.py

Repository: Seongho-Bae/naruon

Length of output: 3720


Narrow SelfHostedConnector._listen_loop exception handling to avoid masking logic bugs.

In backend/runner/connector.py lines 54-59, _listen_loop catches all Exception, logs a warning, and stops the loop—this suppresses failures from handle_message and can hide programming errors.

♻️ Proposed fix
     async def _listen_loop(self):
         if not self.connection:
             return
         try:
             while self.is_connected:
                 message = await self.connection.recv()
                 await self.handle_message(message)
-        except Exception as e:
-            if websockets and isinstance(e, websockets.exceptions.ConnectionClosed):
+        except asyncio.CancelledError:
+            raise
+        except (OSError, asyncio.TimeoutError) as e:
+            logger.warning(f"Connection loop ended: {e}")
+            self.is_connected = False
+        except Exception as e:
+            if websockets and isinstance(e, websockets.exceptions.ConnectionClosed):
                 logger.warning("Connection closed by remote gateway.")
+                self.is_connected = False
             else:
-                logger.warning(f"Connection loop ended: {e}")
-            self.is_connected = False
+                raise
🧰 Tools
🪛 Ruff (0.15.13)

[warning] 54-54: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/runner/connector.py` around lines 54 - 59, The broad except Exception
in SelfHostedConnector._listen_loop is masking programming errors from
handle_message; narrow it to catch only expected shutdown exceptions (e.g.,
websockets.exceptions.ConnectionClosed and asyncio.CancelledError) and handle
them by logging the connection-close path and setting self.is_connected = False,
but for any other Exception log the full traceback (use logger.exception) and
re-raise so bugs aren't suppressed; update _listen_loop to import asyncio if
needed and ensure self.is_connected is cleared in the shutdown path or a finally
block.

Comment thread backend/services/webdav_service.py Outdated
Comment thread frontend/src/components/TasksLayout.tsx
Comment thread frontend/tests/e2e/mobile-hamburger.spec.ts Outdated
@seonghobae

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 24, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Comment thread frontend/tests/e2e/mobile-hamburger.spec.ts Fixed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/tests/e2e/mobile-hamburger.spec.ts (1)

33-54: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove the unused overflow variable.

Line 43 assigns overflow but never uses it. Remove the dead code to clean up the test.

🧹 Proposed fix
-    // Ensure it prevents body scroll
-    const overflow = await page.evaluate(() => document.body.style.overflow);
-    // Depending on implementation, it may use popover or explicit overflow hidden
-    // We will just verify the close button works
-    
     // Close by clicking the close button
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/tests/e2e/mobile-hamburger.spec.ts` around lines 33 - 54, In the
"Hamburger menu closes when close button is clicked" test remove the unused
overflow variable and its evaluation: delete the const overflow = await
page.evaluate(() => document.body.style.overflow); line (and any immediately
related dead comment if you want) so the test no longer defines an unused
symbol; keep the rest of the assertions (menu, closeBtn, hamburgerBtn)
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/tests/e2e/mobile-hamburger.spec.ts`:
- Around line 63-64: The assertion is too weak; instead of checking bottomVal
!== '0px', parse the computed bottom into a numeric pixel value and assert it
meets the minimum safe-area offset (0.75rem ≈ 12px). Update the test around
bottomNav.evaluate so that bottomVal is parsed (e.g., parseFloat or Number) with
a fallback to 0 for non-numeric values like 'auto', then expect the numeric
value to be >= 12 (pixels).

---

Outside diff comments:
In `@frontend/tests/e2e/mobile-hamburger.spec.ts`:
- Around line 33-54: In the "Hamburger menu closes when close button is clicked"
test remove the unused overflow variable and its evaluation: delete the const
overflow = await page.evaluate(() => document.body.style.overflow); line (and
any immediately related dead comment if you want) so the test no longer defines
an unused symbol; keep the rest of the assertions (menu, closeBtn, hamburgerBtn)
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f37302cf-9aa7-43ec-8842-08e175b13e91

📥 Commits

Reviewing files that changed from the base of the PR and between 9f18e94 and 911a69e.

⛔ Files ignored due to path filters (1)
  • backend/tests/__pycache__/test_apm_observability.cpython-310-pytest-9.0.3.pyc is excluded by !**/*.pyc
📒 Files selected for processing (8)
  • backend/services/caldav_service.py
  • backend/services/email_service.py
  • backend/services/webdav_service.py
  • backend/tests/test_apm_observability.py
  • backend/tests/test_ontology.py
  • backend/tests/test_webdav_api.py
  • frontend/src/components/TasksLayout.tsx
  • frontend/tests/e2e/mobile-hamburger.spec.ts
💤 Files with no reviewable changes (1)
  • backend/tests/test_apm_observability.py

Comment thread frontend/tests/e2e/mobile-hamburger.spec.ts Outdated
@seonghobae

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 24, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@seonghobae seonghobae closed this pull request by merging all changes into master in 8a2e162 May 24, 2026
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