Skip to content

feat: 修复由于sql调整导致的代码调整 - #2200

Merged
qdaxb merged 3 commits into
wecode-ai:mainfrom
Micro66:human/penguin-20260724-091250
Jul 24, 2026
Merged

feat: 修复由于sql调整导致的代码调整#2200
qdaxb merged 3 commits into
wecode-ai:mainfrom
Micro66:human/penguin-20260724-091250

Conversation

@Micro66

@Micro66 Micro66 commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • Bug Fixes
    • Improved MySQL compatibility by treating sentinel “unset” timestamps and empty sentinel values as unset across deliveries and task bindings.
    • Updated delivery and loop-item task binding logic to use dialect-aware “unset” detection for unlinked_at/timestamps.
    • Normalized empty-string/zero/epoch-style inputs to null in API responses (IDs, users, snapshots, attachments, content types, and delivered/unlinked times).
    • Improved cloud project creation conflict handling with clearer message and exception logging.
  • Tests
    • Added schema tests validating MySQL sentinel-to-null normalization and dialect-specific adaptation behavior.

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f15a5349-2951-443a-890c-de197da037e2

📥 Commits

Reviewing files that changed from the base of the PR and between 12af41f and d875803.

📒 Files selected for processing (1)
  • backend/app/services/loop_items/service.py

📝 Walkthrough

Walkthrough

The PR adds MySQL sentinel adaptation for LoopNode persistence, normalizes sentinel API values to nullable fields, updates delivery binding queries, and improves cloud-project integrity-error logging and responses.

Changes

Backend delivery normalization

Layer / File(s) Summary
MySQL persistence adaptation
backend/app/models/delivery.py, backend/app/services/loop_items/service.py
LoopNode inserts and dialect-sensitive updates replace None with MySQL sentinels; unset datetime predicates match both SQL NULL and sentinel timestamps.
Nullable response normalization
backend/app/schemas/*.py, backend/tests/schemas/test_delivery.py
Pydantic validators convert empty strings, zero identifiers, empty snapshots, and sentinel datetimes to None; MySQL and SQLite behavior is tested.
Service query integration and error handling
backend/app/services/delivery/service.py, backend/app/services/loop_items/service.py, backend/app/services/cloud_projects/service.py
Delivery binding queries use dialect-aware unset checks, lifecycle guards use truthiness checks, and cloud-project integrity errors are logged with a generic conflict response.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Database
  participant LoopItemService
  participant LoopNode
  participant DeliverySchema
  LoopItemService->>LoopNode: write dialect-adapted values
  LoopNode->>Database: persist MySQL sentinel values
  Database-->>DeliverySchema: return sentinel fields
  DeliverySchema-->>LoopItemService: normalize sentinels to None
Loading

Suggested reviewers: qdaxb

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.16% 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 title is related to the SQL/MySQL-driven code changes, though it is awkward and not very specific.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@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: 2

🧹 Nitpick comments (1)
wework/e2e/desktop/task-flow.e2e.mjs (1)

4277-4280: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Begin the TODO flow with a snapshot assertion.

Use waitForSnapshot for the initial cloud-todo-workspace check instead of starting with waitFor, so this flow follows the required snapshot-first verification pattern.

Proposed fix
-  await control.command('waitFor', '[data-testid="cloud-todo-workspace"]', {
-    timeoutMs: WORKBENCH_READY_TIMEOUT_MS,
-  })
+  await waitForSnapshot(
+    control,
+    snapshot => snapshot.testIds.includes('cloud-todo-workspace'),
+    'The cloud TODO workspace did not render',
+    WORKBENCH_READY_TIMEOUT_MS
+  )

As per coding guidelines, “begin verification with snapshot”.

🤖 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 `@wework/e2e/desktop/task-flow.e2e.mjs` around lines 4277 - 4280, Update the
initial cloud-todo-workspace verification in the TODO flow after the navigate
command to use control.command('waitForSnapshot', ...) instead of waitFor,
preserving the existing selector and WORKBENCH_READY_TIMEOUT_MS timeout.

Source: Coding guidelines

🤖 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/app/models/delivery.py`:
- Around line 189-250: Update _MYSQL_NON_NULL_DEFAULTS and
adapt_loop_node_values_for_dialect so nullable relationship fields, including
parent_id, loop_item_id, delivery_id, local_project_id, and backend_task_id,
preserve SQL NULL instead of receiving synthetic sentinels; add the required
Alembic schema migration with upgrade and rollback verification. In
backend/app/services/loop_items/service.py:290-292, retain the adaptation call
unchanged because it is corrected by the helper fix. In
backend/tests/schemas/test_delivery.py:45-56, assert nullable relationship IDs
remain None and limit sentinel checks to non-relational scalar fields such as
unset datetimes.

In `@wework/e2e/desktop/task-flow.e2e.mjs`:
- Around line 2226-2235: Update the remote-picker expectation in
verifyCloudProjectFlow to use this.remoteHome, matching the WEGENT_EXECUTOR_HOME
value configured in remoteEnv, instead of join(resultDir,
'cloud-executor-home').

---

Nitpick comments:
In `@wework/e2e/desktop/task-flow.e2e.mjs`:
- Around line 4277-4280: Update the initial cloud-todo-workspace verification in
the TODO flow after the navigate command to use
control.command('waitForSnapshot', ...) instead of waitFor, preserving the
existing selector and WORKBENCH_READY_TIMEOUT_MS timeout.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3f9d7aa9-ce8c-45c3-a9ed-dfa8d01ebf08

📥 Commits

Reviewing files that changed from the base of the PR and between 271834f and 4a4da67.

📒 Files selected for processing (9)
  • backend/app/models/delivery.py
  • backend/app/schemas/cloud_file.py
  • backend/app/schemas/cloud_project.py
  • backend/app/schemas/delivery.py
  • backend/app/services/cloud_projects/service.py
  • backend/app/services/delivery/service.py
  • backend/app/services/loop_items/service.py
  • backend/tests/schemas/test_delivery.py
  • wework/e2e/desktop/task-flow.e2e.mjs

Comment on lines +189 to +250
_MYSQL_NON_NULL_DEFAULTS: dict[str, object] = {
"cloud_project_id": "",
"parent_id": "",
"loop_item_id": "",
"delivery_id": "",
"public_id": "",
"project_key": "",
"name": "",
"title": "",
"storage_prefix": "",
"sequence_number": 0,
"created_by_user_id": 0,
"updated_by_user_id": 0,
"assignee_user_id": 0,
"user_id": 0,
"added_by_user_id": 0,
"source": "",
"status": "",
"priority": "",
"due_at": _MYSQL_UNSET_DATETIME,
"current_delivery_id": "",
"local_project_id": 0,
"device_id": "",
"is_default": False,
"task_user_id": 0,
"task_id": "",
"task_title": "",
"backend_task_id": 0,
"linked_by_user_id": 0,
"linked_at": _MYSQL_UNSET_DATETIME,
"unlinked_at": _MYSQL_UNSET_DATETIME,
"path": "",
"kind": "",
"display_name": "",
"relative_path": "",
"object_key": "",
"content_type": "",
"size_bytes": 0,
"sha256": "",
"source_task_binding_id": "",
"source_task_snapshot": {},
"markdown_object_key": "",
"chat_object_key": "",
"manifest_object_key": "",
"metadata_json": {},
"completed_at": _MYSQL_UNSET_DATETIME,
"delivered_at": _MYSQL_UNSET_DATETIME,
}


def adapt_loop_node_values_for_dialect(
values: dict[str, object], dialect_name: str
) -> dict[str, object]:
"""Convert explicit nulls to sentinels required by the production schema."""
if dialect_name != "mysql":
return values
adapted = values.copy()
for attribute, default in _MYSQL_NON_NULL_DEFAULTS.items():
if attribute in adapted and adapted[attribute] is None:
adapted[attribute] = (
default.copy() if isinstance(default, dict) else default
)

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.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Preserve SQL NULL for relationship fields instead of synthetic sentinels. Empty strings and zero IDs are not nullable foreign keys: top-level TODO insertion and parent removal can fail FK validation.

  • backend/app/models/delivery.py#L189-L250: remove foreign-key/relationship fields such as parent_id, loop_item_id, delivery_id, local_project_id, and backend_task_id from MySQL sentinel substitution; migrate the physical schema to allow NULL where the model declares it nullable.
  • backend/app/services/loop_items/service.py#L290-L292: retain this adaptation call only after the helper no longer rewrites parent_id=None.
  • backend/tests/schemas/test_delivery.py#L45-L56: assert that nullable relationship IDs remain None; keep sentinel assertions limited to non-relational scalar fields such as unset datetimes.

As per coding guidelines, persistent backend model changes require an Alembic migration with upgrade and rollback verification.

📍 Affects 3 files
  • backend/app/models/delivery.py#L189-L250 (this comment)
  • backend/app/services/loop_items/service.py#L290-L292
  • backend/tests/schemas/test_delivery.py#L45-L56
🤖 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/app/models/delivery.py` around lines 189 - 250, Update
_MYSQL_NON_NULL_DEFAULTS and adapt_loop_node_values_for_dialect so nullable
relationship fields, including parent_id, loop_item_id, delivery_id,
local_project_id, and backend_task_id, preserve SQL NULL instead of receiving
synthetic sentinels; add the required Alembic schema migration with upgrade and
rollback verification. In backend/app/services/loop_items/service.py:290-292,
retain the adaptation call unchanged because it is corrected by the helper fix.
In backend/tests/schemas/test_delivery.py:45-56, assert nullable relationship
IDs remain None and limit sentinel checks to non-relational scalar fields such
as unset datetimes.

Source: Coding guidelines

Comment thread wework/e2e/desktop/task-flow.e2e.mjs Outdated
@qdaxb
qdaxb merged commit bd397bc into wecode-ai:main Jul 24, 2026
25 of 27 checks passed

@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

🤖 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 `@wework/e2e/desktop/task-flow.e2e.mjs`:
- Around line 5303-5320: The firstTaskOpenedTerminal flag must match the
terminalOpened condition used by waitForSnapshot. Update its check to require
workspace-terminal-window and exclude workspace-tool-launcher, so
terminal-plus-launcher snapshots follow the limited-tools validation path.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 537f1ac8-0eba-4128-89d3-2d8b85a63c06

📥 Commits

Reviewing files that changed from the base of the PR and between 4a4da67 and 12af41f.

📒 Files selected for processing (1)
  • wework/e2e/desktop/task-flow.e2e.mjs

@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.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🤖 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 `@wework/e2e/desktop/task-flow.e2e.mjs`:
- Around line 5303-5320: The firstTaskOpenedTerminal flag must match the
terminalOpened condition used by waitForSnapshot. Update its check to require
workspace-terminal-window and exclude workspace-tool-launcher, so
terminal-plus-launcher snapshots follow the limited-tools validation path.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 537f1ac8-0eba-4128-89d3-2d8b85a63c06

📥 Commits

Reviewing files that changed from the base of the PR and between 4a4da67 and 12af41f.

📒 Files selected for processing (1)
  • wework/e2e/desktop/task-flow.e2e.mjs
🛑 Comments failed to post (1)
wework/e2e/desktop/task-flow.e2e.mjs (1)

5303-5320: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep the terminal-state flag consistent with the wait predicate.

Line 5318 treats any terminal element as success, while the predicate defines terminal success as a terminal without the launcher. A terminal-plus-limited-launcher snapshot takes the wrong restoration branch and skips validating the limited-tools state.

Proposed fix
-    const firstTaskOpenedTerminal = firstTaskBottomWorkspaceSnapshot.testIds.includes(
-      'workspace-terminal-window'
-    )
+    const firstTaskOpenedTerminal =
+      firstTaskBottomWorkspaceSnapshot.testIds.includes('workspace-terminal-window') &&
+      !firstTaskBottomWorkspaceSnapshot.testIds.includes('workspace-tool-launcher')
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    const firstTaskBottomWorkspaceSnapshot = await waitForSnapshot(
      control,
      value => {
        const terminalOpened =
          value.testIds.includes('workspace-terminal-window') &&
          !value.testIds.includes('workspace-tool-launcher')
        const localTerminalUnavailable =
          value.testIds.includes('workspace-tool-launcher') &&
          value.testIds.includes('workspace-local-device-limited-tools')
        return terminalOpened || localTerminalUnavailable
      },
      'The first task bottom workspace panel did not open a terminal or limited-tools launcher',
      UI_TIMEOUT_MS,
      ACTIVE_WORKBENCH_SELECTOR
    )
    const firstTaskOpenedTerminal =
      firstTaskBottomWorkspaceSnapshot.testIds.includes('workspace-terminal-window') &&
      !firstTaskBottomWorkspaceSnapshot.testIds.includes('workspace-tool-launcher')
🤖 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 `@wework/e2e/desktop/task-flow.e2e.mjs` around lines 5303 - 5320, The
firstTaskOpenedTerminal flag must match the terminalOpened condition used by
waitForSnapshot. Update its check to require workspace-terminal-window and
exclude workspace-tool-launcher, so terminal-plus-launcher snapshots follow the
limited-tools validation path.

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.

2 participants