Skip to content

fix/task id handling#2023

Merged
luoyangxing merged 6 commits into
larksuite:mainfrom
ILUO:fix/task-id-handling
Jul 23, 2026
Merged

fix/task id handling#2023
luoyangxing merged 6 commits into
larksuite:mainfrom
ILUO:fix/task-id-handling

Conversation

@ILUO

@ILUO ILUO commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Improve the existing Task +update and +complete shortcuts without adding a new shortcut. The change distinguishes Task OpenAPI GUIDs from client display IDs, accepts Task applinks directly, and returns server-confirmed mutation state to reduce redundant follow-up reads.

Changes

  • Add strict Task ID parsing:
    • Accept opaque Task OpenAPI GUIDs.
    • Extract guid from Task applinks.
    • Reject client display IDs such as t104121 with a typed invalid_argument error.
  • Validate every ID in a batch update before issuing the first PATCH, preventing partial updates caused by an invalid later ID.
  • Extend +update output with:
    • updated_fields
    • Per-task confirmed values taken only from the server response.
  • Preserve the idempotent pre-read in +complete and extend its output with:
    • status
    • completed_at
    • already_completed
  • Update the Task skill workflow:
    • Use a known tasklist GUID directly.
    • Search only when only a tasklist name or keyword is available.
    • Keep the native task tasklists tasks command instead of adding a new shortcut.
    • Avoid routine tasks get calls when mutation output already confirms the required state.
  • Add unit and dry-run E2E coverage for GUID/applink equivalence, invalid display IDs, batch pre-validation, and server-confirmed output.

Test Plan

  • go test -race -count=1 ./shortcuts/task
  • go test ./tests/cli_e2e/task -run TestTaskIDHandlingDryRun -count=1
  • go vet ./shortcuts/task ./tests/cli_e2e/task
  • Dry-run verification confirms GUID and applink inputs generate the same Task API request paths.
  • Invalid display IDs fail before emitting a mutation request.

Related Issues

  • None

Summary by CodeRabbit

  • New Features
    • Task commands now accept task applinks as --task-id, extracting the GUID from guid= when provided.
    • Task completion output now includes status, completed_at, and already_completed.
    • Task update output now reports updated_fields and per-task server-confirmed values.
  • Bug Fixes
    • Invalid or display-style task IDs are rejected with typed validation guidance before any requests.
    • Multiple --task-id values are validated up front to prevent partial updates.
  • Documentation
    • Updated task v2 guidance and examples to reflect applink-based --task-id and the expanded result fields.

@github-actions github-actions Bot added domain/task PR touches the task domain size/M Single-domain feat or fix with limited business impact labels Jul 23, 2026
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Task shortcuts now accept GUIDs or task applinks containing guid, reject display-number identifiers, normalize IDs before API calls, expose completion and update confirmation state, and document the revised workflows with unit and end-to-end tests.

Changes

Task identifier workflows

Layer / File(s) Summary
Task identifier parsing
shortcuts/task/shortcuts.go, shortcuts/task/shortcuts_test.go
Adds shared parsing for trimmed GUIDs and task applinks, with structured validation for empty, malformed, and display-number identifiers.
Completion state handling
shortcuts/task/task_complete.go, shortcuts/task/task_complete_test.go
Normalizes completion inputs, avoids PATCH requests for already-completed tasks, and returns status, completed_at, and already_completed.
Multi-task update flow
shortcuts/task/task_update.go, shortcuts/task/task_update_test.go
Normalizes and validates comma-separated IDs before writes, then returns updated_fields and per-task confirmed values.
Workflow guidance and end-to-end validation
skills/lark-task/*, tests/cli_e2e/task/*
Documents GUID/applink usage and result-driven verification, with dry-run and workflow coverage for equivalent inputs and rejected display IDs.

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

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant TaskIDParser
  participant TaskShortcut
  participant TaskAPI
  CLI->>TaskIDParser: validate --task-id
  TaskIDParser-->>TaskShortcut: normalized task GUID(s)
  TaskShortcut->>TaskAPI: GET or PATCH task
  TaskAPI-->>TaskShortcut: task state and confirmed fields
  TaskShortcut-->>CLI: structured completion or update output
Loading

Possibly related PRs

  • larksuite/cli#218: Modifies completion handling around completed_at before PATCH requests.
  • larksuite/cli#1231: Overlaps with typed validation and task shortcut error handling.

Suggested reviewers: tengchengwei

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% 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
Title check ✅ Passed The title is concise and points to the main area of change: task ID handling.
Description check ✅ Passed The description follows the template and covers summary, changes, test plan, and related issues.
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

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 (3)
shortcuts/task/task_update.go (1)

58-84: 🗄️ Data Integrity & Integration | 🔵 Trivial | 🏗️ Heavy lift

Partial writes on mid-batch failure aren't surfaced.

If a task later in taskIDs fails PATCH, earlier tasks in the same call have already been mutated, but Execute returns only the error with no indication of which tasks already succeeded. This loop body predates this PR, but it's directly relevant to this PR's "server-confirmed mutation state" objective — worth considering returning partial results (e.g. which task GUIDs succeeded before the failure) rather than discarding them.

🤖 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 `@shortcuts/task/task_update.go` around lines 58 - 84, The Execute loop should
surface partial success when a later task PATCH fails instead of returning only
the error. Track the task GUIDs successfully mutated through callTaskAPITyped,
and include those results or identifiers with the failure while preserving the
existing immediate error behavior for failures before any successful mutation.
shortcuts/task/task_complete.go (1)

70-94: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate "is completed" check.

The completedAtStr != "" && completedAtStr != "0" truthy check is duplicated for alreadyCompleted (line 72) and status (lines 92-94). Consider extracting a small helper to avoid the two independent copies drifting.

♻️ Optional helper extraction
+func isTaskCompleted(completedAt string) bool {
+	return completedAt != "" && completedAt != "0"
+}
+
 ...
-		alreadyCompleted := completedAtStr != "" && completedAtStr != "0"
+		alreadyCompleted := isTaskCompleted(completedAtStr)
 ...
-		status := "todo"
-		if completedAt != "" && completedAt != "0" {
-			status = "done"
-		}
+		status := "todo"
+		if isTaskCompleted(completedAt) {
+			status = "done"
+		}
🤖 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 `@shortcuts/task/task_complete.go` around lines 70 - 94, Extract the shared
completed-at truth check used by the alreadyCompleted assignment and the status
calculation into a small helper, then reuse it in both locations. Keep the
existing behavior for empty and "0" values while eliminating the duplicated
condition.
shortcuts/task/shortcuts.go (1)

104-136: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Preserve the URL-parse error as a cause.

The URL-parse failure branch currently formats the lower-layer error into the message string. Attach it with .WithCause(err) so callers can retrieve the underlying cause via errors.Unwrap/errors.Is, while keeping the --task-id metadata and hint intact.

♻️ Proposed fix
 		u, err := url.Parse(input)
 		if err != nil {
-			return "", invalid("invalid task applink: %v", err)
+			return "", invalid("invalid task applink: %v", err).WithCause(err)
 		}
🤖 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 `@shortcuts/task/shortcuts.go` around lines 104 - 136, Update the URL-parse
error branch in parseTaskGUID to attach the original err via WithCause instead
of only interpolating it into the validation message. Preserve the existing
--task-id parameter metadata and hint, along with the current invalid applink
message.

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 `@shortcuts/task/task_update.go`:
- Around line 42-56: Update the DryRun handler to construct a preview containing
one PATCH request for every task ID returned by parseTaskGUIDs, matching the
multi-target behavior of Execute. Preserve the existing request path,
parameters, and body for each escaped ID, while retaining the current error
responses for body-building and ID-parsing failures.

In `@tests/cli_e2e/task/task_id_handling_dryrun_test.go`:
- Around line 16-81: Add a live E2E test alongside TestTaskIDHandlingDryRun
covering task +update and/or +complete with an applink GUID, verifying
successful execution, and display-number input such as t12345, verifying
validation failure and no unintended update. Reuse the existing task CLI setup
and result assertions, while keeping the dry-run equivalence and rejection
coverage unchanged.

---

Nitpick comments:
In `@shortcuts/task/shortcuts.go`:
- Around line 104-136: Update the URL-parse error branch in parseTaskGUID to
attach the original err via WithCause instead of only interpolating it into the
validation message. Preserve the existing --task-id parameter metadata and hint,
along with the current invalid applink message.

In `@shortcuts/task/task_complete.go`:
- Around line 70-94: Extract the shared completed-at truth check used by the
alreadyCompleted assignment and the status calculation into a small helper, then
reuse it in both locations. Keep the existing behavior for empty and "0" values
while eliminating the duplicated condition.

In `@shortcuts/task/task_update.go`:
- Around line 58-84: The Execute loop should surface partial success when a
later task PATCH fails instead of returning only the error. Track the task GUIDs
successfully mutated through callTaskAPITyped, and include those results or
identifiers with the failure while preserving the existing immediate error
behavior for failures before any successful mutation.
🪄 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: d112e359-5cdc-42d4-ae18-f84fcec6ed46

📥 Commits

Reviewing files that changed from the base of the PR and between 67015ee and dfb5c23.

📒 Files selected for processing (10)
  • shortcuts/task/shortcuts.go
  • shortcuts/task/shortcuts_test.go
  • shortcuts/task/task_complete.go
  • shortcuts/task/task_complete_test.go
  • shortcuts/task/task_update.go
  • shortcuts/task/task_update_test.go
  • skills/lark-task/SKILL.md
  • skills/lark-task/references/lark-task-complete.md
  • skills/lark-task/references/lark-task-update.md
  • tests/cli_e2e/task/task_id_handling_dryrun_test.go

Comment thread shortcuts/task/task_update.go
Comment thread tests/cli_e2e/task/task_id_handling_dryrun_test.go
@ILUO ILUO changed the title Fix/task id handling fix/task id handling Jul 23, 2026
tengchengwei
tengchengwei previously approved these changes Jul 23, 2026
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@b32c0f15d9f41c433a74301014f8045027542020

🧩 Skill update

npx skills add ILUO/cli#fix/task-id-handling -y -g

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (3)
shortcuts/task/task_update.go (3)

133-152: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Reject empty entries instead of silently discarding them.

Inputs such as guid-1,,guid-2 or guid-1, currently update only the non-empty IDs. Validate every split token with parseTaskGUID (which already produces a typed validation error for empty input) so the requested batch is preserved exactly.

As per coding guidelines, do not silently discard unsupported input or writes; return a typed validation error instead.

🤖 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 `@shortcuts/task/task_update.go` around lines 133 - 152, Update parseTaskGUIDs
to validate every token from strings.Split through parseTaskGUID, including
whitespace-only and trailing empty entries, instead of skipping them. Return
parseTaskGUID’s typed validation error for any empty token while preserving the
existing successful GUID collection behavior.

Source: Coding guidelines


133-152: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Apply display-number rejection to applink query values.

parseTaskGUIDs delegates to parseTaskGUID, but the supplied shared parser returns an applink’s extracted guid without applying the display-number check. Therefore an applink containing guid=123 bypasses the intended rejection and reaches PATCH as an invalid task identifier. Revalidate the extracted GUID in parseTaskGUID and add an applink regression test.

🤖 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 `@shortcuts/task/task_update.go` around lines 133 - 152, Update parseTaskGUID
to revalidate the GUID extracted from applink query values using the existing
display-number rejection, ensuring values such as guid=123 fail before PATCH
processing. Add a regression test covering an applink with a numeric display
GUID and verify parseTaskGUIDs rejects it.

88-109: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Do not report a successful batch when a task response is missing.

The preceding unchecked type assertion only appends non-nil task objects. A successful PATCH response without data.task can therefore disappear while Execute still returns nil, leaving data.tasks and Meta.Count smaller than the requested batch. Parse the API response into a typed result and return a typed error when the task result or identity is missing instead of silently dropping it.

As per coding guidelines, parse API-bound map[string]interface{} data into typed structs and use typed command-facing errors.

🤖 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 `@shortcuts/task/task_update.go` around lines 88 - 109, The task update flow
around the unchecked task extraction must validate every requested PATCH result
instead of silently skipping missing entries. Parse the API response maps into
typed result structs, require each result to contain a task and its identity,
and return a typed command-facing error when either is absent; only build
`tasks` and return success after all results pass validation.

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.

Outside diff comments:
In `@shortcuts/task/task_update.go`:
- Around line 133-152: Update parseTaskGUIDs to validate every token from
strings.Split through parseTaskGUID, including whitespace-only and trailing
empty entries, instead of skipping them. Return parseTaskGUID’s typed validation
error for any empty token while preserving the existing successful GUID
collection behavior.
- Around line 133-152: Update parseTaskGUID to revalidate the GUID extracted
from applink query values using the existing display-number rejection, ensuring
values such as guid=123 fail before PATCH processing. Add a regression test
covering an applink with a numeric display GUID and verify parseTaskGUIDs
rejects it.
- Around line 88-109: The task update flow around the unchecked task extraction
must validate every requested PATCH result instead of silently skipping missing
entries. Parse the API response maps into typed result structs, require each
result to contain a task and its identity, and return a typed command-facing
error when either is absent; only build `tasks` and return success after all
results pass validation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f8845e79-5347-4eca-966c-66df996319a7

📥 Commits

Reviewing files that changed from the base of the PR and between dfb5c23 and b32c0f1.

📒 Files selected for processing (6)
  • shortcuts/task/shortcuts.go
  • shortcuts/task/shortcuts_test.go
  • shortcuts/task/task_update.go
  • shortcuts/task/task_update_test.go
  • tests/cli_e2e/task/task_id_handling_dryrun_test.go
  • tests/cli_e2e/task/task_id_handling_workflow_test.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/cli_e2e/task/task_id_handling_dryrun_test.go
  • shortcuts/task/shortcuts.go
  • shortcuts/task/shortcuts_test.go
  • shortcuts/task/task_update_test.go

@luoyangxing
luoyangxing merged commit ebc0c53 into larksuite:main Jul 23, 2026
22 of 36 checks passed
@liangshuo-1 liangshuo-1 mentioned this pull request Jul 24, 2026
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain/task PR touches the task domain size/M Single-domain feat or fix with limited business impact

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants