Skip to content

feat(task): add field expansion and aggregation to task list#91

Merged
amondnet merged 3 commits into
mainfrom
amondnet/agent-interface-benchmark-task-list-lacks-field
Jul 6, 2026
Merged

feat(task): add field expansion and aggregation to task list#91
amondnet merged 3 commits into
mainfrom
amondnet/agent-interface-benchmark-task-list-lacks-field

Conversation

@amondnet

@amondnet amondnet commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements the interface-gap fixes from the agent-interface benchmark in #88: task list now supports field expansion, exclusive completion filters, unassigned filtering, and precomputed aggregates, collapsing scan-style questions from N×task get round-trips to a single call.

  • --fields completed,assignee,due_on — pulls extra fields into the listing via opt_fields (assignee flattened to a display name, missing values kept as null for aligned tabular output)
  • --incomplete-only / --completed-only — exclusive completion filters (--incomplete-only maps to the server-side completed_since=now; conflicts are rejected with a structured CONFLICTING_OPTIONS error)
  • --assignee none — unassigned-only; assignee filtering now also works for project listings (me is resolved client-side via users.me)
  • --count and --group-by assignee|completed — return { summary: { total, groups } } instead of rows (AXI principle 4), so the benchmark's aggregation task costs 1 round-trip
  • -c/--completed is deprecated: its help text claimed it includes completed tasks while the implementation passed completed_since=now (excluding them). Wire behavior is preserved; the help text now tells the truth and points to --incomplete-only.

The legacy compact listing (no scan option) is unchanged — no opt_fields is sent and the raw rows are printed as before.

Test plan

  • test/lib/task-list-query.test.ts — 25 unit tests over the pure query helpers (parsing/validation, opt_fields construction, filters, row flattening, aggregation)
  • test/commands/task-list-scan.test.ts — 8 command-level tests with a mocked client verifying both the request parameters (opt_fields, completed_since) and shaped output, including the legacy-request regression guard
  • Full suite: 556 pass, eslint clean

Closes #88


Summary by cubic

Adds field expansion, exclusive completion filters, unassigned filtering, and aggregation to task list so N×task get scans become a single request. Supports dotted fields (e.g., assignee.name) and leaves the legacy compact listing unchanged.

  • New Features

    • --fields completed,assignee,due_on expands opt_fields; supports dotted paths like assignee.name; flattens assignee to a display name; missing values are null.
    • --incomplete-only and --completed-only are exclusive; incomplete uses completed_since=now where possible.
    • --assignee none filters unassigned; -a me is resolved client-side for project listings; assignee filters now work for projects.
    • --count and --group-by assignee|completed return { summary: { total, groups } } instead of rows.
  • Migration

    • -c/--completed is deprecated and documented as excluding completed tasks; use --incomplete-only instead.

Written for commit 9b7ddf4. Summary will update on new commits.

Summary by CodeRabbit

  • New Features
    • Task listings now support filtering by completion state, assignee, and selected fields.
    • Added count and group-by summaries for task lists, including grouped totals.
  • Bug Fixes
    • Task list output now handles unassigned tasks and completion filters more clearly.
    • Improved validation for invalid field names, conflicting options, and unsupported grouping values.
  • Documentation
    • Updated task management docs with new list/filter examples and deprecation guidance for the older completed option.

amondnet added 2 commits July 6, 2026 18:14
- --fields pulls extra fields (completed, assignee, due_on, ...) into the
  listing via opt_fields, removing the need for per-task `task get` calls
- --incomplete-only / --completed-only exclusive completion filters
- --assignee none filters unassigned tasks; assignee filtering now also
  works for project listings (resolves "me" client-side)
- --count and --group-by assignee|completed return precomputed aggregates
- deprecate -c/--completed (help text now matches its actual behavior of
  excluding completed tasks)

Closes #88
@vercel

vercel Bot commented Jul 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
asana Ready Ready Preview, Comment Jul 6, 2026 9:30am

Request Review

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds field expansion, completion/assignee filtering, and count/group-by aggregation to the task list command. A new src/lib/task-list-query.ts module handles query parsing, opt_fields construction, filtering, column selection, and summarization, wired into a refactored task.ts command with new error ids, type fields, tests, and docs.

Changes

Task List Scan Features

Layer / File(s) Summary
Type and error id contracts
src/types/index.ts, src/constants/errorIds.ts
TaskListOptions gains fields, completedOnly, incompleteOnly, count, groupBy; completed marked deprecated. ERROR_IDS gains INVALID_FIELD_NAME, INVALID_GROUP_BY, CONFLICTING_OPTIONS.
task-list-query helper module
src/lib/task-list-query.ts
New module providing parseTaskListQuery, needsClientAssigneeFilter, buildOptFields, applyCompletionFilter, applyAssigneeFilter, effectiveColumns, toTaskRows, and summarizeTasks.
task list command refactor
src/commands/task.ts
Adds fetchTaskPage helper; replaces -c/--completed with --completed-only/--incomplete-only, adds --count/--group-by; rewires listing action to use the new query helpers and adds summary output paths.
Tests for query helper and CLI command
test/lib/task-list-query.test.ts, test/commands/task-list-scan.test.ts
Adds unit tests for the query helper functions and CLI integration tests covering fields, filters, count, and group-by scenarios.
Documentation updates
docs/content/en/2.features/1.task-management.md, docs/content/ko/2.features/1.task-management.md, .gitignore
Documents completion filtering, assignee filtering, field expansion, and count/group-by usage in English and Korean; adds .impeccable/ to .gitignore.

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

Sequence Diagram(s)

sequenceDiagram
  participant CLI as task list command
  participant Query as parseTaskListQuery
  participant Fields as buildOptFields
  participant API as fetchTaskPage
  participant Filter as applyCompletionFilter/applyAssigneeFilter
  participant Summary as summarizeTasks

  CLI->>Query: parse CLI options
  Query-->>CLI: TaskListQuery
  CLI->>Fields: buildOptFields(query, clientAssignee)
  Fields-->>CLI: opt_fields string
  CLI->>API: fetchTaskPage(options, opt_fields)
  API-->>CLI: raw tasks
  CLI->>Filter: apply completion/assignee filters
  Filter-->>CLI: filtered tasks
  alt count or group-by requested
    CLI->>Summary: summarizeTasks(tasks, groupBy)
    Summary-->>CLI: total/groups summary
  else
    CLI->>CLI: toTaskRows and render columns
  end
Loading

Possibly related PRs

  • pleaseai/asana#35: Both PRs modify the task list command in src/commands/task.ts, adjusting output/formatter selection and listing logic.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The .gitignore change to ignore .impeccable/ is unrelated to the task-list benchmark fix. Move the .gitignore update to a separate housekeeping PR unless it is required for this feature.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes implement the requested --fields, completion filters, unassigned filtering, and count/group-by aggregation described in #88.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: task list field expansion and aggregation support.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch amondnet/agent-interface-benchmark-task-list-lacks-field

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.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces advanced scan-style options to the task list command, including filtering by completion state, assignee, field expansion, and aggregation (counting and grouping). It also updates the documentation and adds comprehensive tests. The code review feedback correctly identifies a high-severity issue in toTaskRows where nested field paths (such as assignee.name) specified in --fields will fail to resolve and return null due to simple bracket notation, and provides a solid suggestion to resolve nested properties dynamically.

Comment thread src/lib/task-list-query.ts
@greptile-apps

greptile-apps Bot commented Jul 6, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds scan-style query capabilities to task list: field expansion via --fields, exclusive completion filters (--incomplete-only / --completed-only), unassigned filtering (--assignee none), and aggregate output (--count / --group-by). The logic is cleanly separated into a new task-list-query.ts module and is well-covered by 33 new unit and integration tests.

  • src/lib/task-list-query.ts is a new helper module that handles parsing, opt_fields construction, client-side assignee/completion filtering, row flattening, and aggregation — keeping the command layer thin.
  • src/commands/task.ts integrates the new helpers; --incomplete-only maps to completed_since=now server-side while --completed-only is filtered client-side only; --assignee me is resolved to a GID client-side for project listings and server-side for workspace listings.
  • The previously reported dotted-path output bug (task['assignee.name'] always null) is fixed in this PR via the new getFieldValue path resolver, verified by a dedicated test.

Confidence Score: 4/5

The new scan-mode paths are correct and well-covered by tests; the --completed-only flag has no server-side filter equivalent and pulls all tasks before discarding the incomplete ones client-side, which will be slow and expensive against large projects or workspaces.

All of the new --fields, --incomplete-only, --count, --group-by, and --assignee none paths are implemented correctly and are well-tested across 33 unit and command-level tests. The previously reported dotted-path resolution bug is fixed via getFieldValue. The --completed-only path remains without a server-side filter, meaning it fetches every task in the project or workspace before the client discards the incomplete ones — a real cost issue on large datasets that is still open.

The server-side filter gap for --completed-only lives in src/lib/task-list-query.ts (the buildOptFields / applyCompletionFilter interaction) and the completed_since logic in src/commands/task.ts.

Important Files Changed

Filename Overview
src/lib/task-list-query.ts New module with all scan-mode helpers. Dotted-path resolution is correctly implemented via getFieldValue. --completed-only has no server-side filter (all tasks pulled, client filters), which is a known open issue from the previous review round. All other paths look correct and are well-tested.
src/commands/task.ts Command layer correctly wires the new query helpers: ValidationError is caught before handleAsanaError, --assignee me is resolved via users.me() only when needed, and legacy compact listing is preserved. --completed-only server-side gap carries over from the library layer.
test/lib/task-list-query.test.ts 25 focused unit tests covering all public helpers including the dotted-path fix, conflict validation, assignee/completion filters, and group-by aggregation. Coverage is thorough.
test/commands/task-list-scan.test.ts 8 command-level integration tests with a mocked Asana client. Verifies both request parameters (opt_fields, completed_since) and shaped output. Includes a regression guard that the legacy path never sends opt_fields.
src/types/index.ts Extends TaskListOptions with the five new option fields; deprecated completed is documented in a JSDoc comment.
src/constants/errorIds.ts Adds three new structured error IDs: INVALID_FIELD_NAME, INVALID_GROUP_BY, CONFLICTING_OPTIONS.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant CLI as CLI (task list)
    participant PQ as parseTaskListQuery
    participant BOF as buildOptFields
    participant FTP as fetchTaskPage
    participant API as Asana API
    participant CF as applyCompletionFilter / applyAssigneeFilter
    participant SUM as summarizeTasks / toTaskRows

    CLI->>PQ: options (fields, completedOnly, incompleteOnly, count, groupBy, assignee)
    PQ-->>CLI: TaskListQuery (validated/normalized) or throws ValidationError

    CLI->>BOF: query + clientAssignee flag
    BOF-->>CLI: opt_fields string (or undefined for legacy path)

    CLI->>FTP: client, options, workspace, params, clientAssignee
    FTP->>API: findByProject / findAll with opt_fields + completed_since
    API-->>FTP: task data
    FTP-->>CLI: task[]

    alt "clientAssignee = true"
        CLI->>API: "users.me() (only if assignee = me)"
        API-->>CLI: current user GID
        CLI->>CF: applyAssigneeFilter(tasks, gid or none)
        CF-->>CLI: filtered tasks
    end

    CLI->>CF: applyCompletionFilter(tasks, query)
    CF-->>CLI: filtered tasks

    alt --count or --group-by
        CLI->>SUM: summarizeTasks(tasks, groupBy?)
        SUM-->>CLI: "{total, groups?}"
        CLI->>CLI: "formatOutput({summary})"
    else scan mode
        CLI->>SUM: toTaskRows(tasks, columns)
        SUM-->>CLI: flattened rows
        CLI->>CLI: "formatOutput({tasks})"
    else legacy mode
        CLI->>CLI: "formatOutput({tasks}) raw"
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant CLI as CLI (task list)
    participant PQ as parseTaskListQuery
    participant BOF as buildOptFields
    participant FTP as fetchTaskPage
    participant API as Asana API
    participant CF as applyCompletionFilter / applyAssigneeFilter
    participant SUM as summarizeTasks / toTaskRows

    CLI->>PQ: options (fields, completedOnly, incompleteOnly, count, groupBy, assignee)
    PQ-->>CLI: TaskListQuery (validated/normalized) or throws ValidationError

    CLI->>BOF: query + clientAssignee flag
    BOF-->>CLI: opt_fields string (or undefined for legacy path)

    CLI->>FTP: client, options, workspace, params, clientAssignee
    FTP->>API: findByProject / findAll with opt_fields + completed_since
    API-->>FTP: task data
    FTP-->>CLI: task[]

    alt "clientAssignee = true"
        CLI->>API: "users.me() (only if assignee = me)"
        API-->>CLI: current user GID
        CLI->>CF: applyAssigneeFilter(tasks, gid or none)
        CF-->>CLI: filtered tasks
    end

    CLI->>CF: applyCompletionFilter(tasks, query)
    CF-->>CLI: filtered tasks

    alt --count or --group-by
        CLI->>SUM: summarizeTasks(tasks, groupBy?)
        SUM-->>CLI: "{total, groups?}"
        CLI->>CLI: "formatOutput({summary})"
    else scan mode
        CLI->>SUM: toTaskRows(tasks, columns)
        SUM-->>CLI: flattened rows
        CLI->>CLI: "formatOutput({tasks})"
    else legacy mode
        CLI->>CLI: "formatOutput({tasks}) raw"
    end
Loading

Reviews (2): Last reviewed commit: "chore: apply AI code review suggestions" | Re-trigger Greptile

Comment thread src/lib/task-list-query.ts
Comment thread src/lib/task-list-query.ts
Comment thread src/lib/task-list-query.ts Outdated

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

🧹 Nitpick comments (1)
src/lib/task-list-query.ts (1)

205-215: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Nested ternary flagged by static analysis.

Cosmetic only; extracting to an if/else would satisfy the linter without behavior change.

♻️ Suggested refactor
   for (const task of tasks) {
-    const key = groupBy === 'completed'
-      ? (task.completed ? 'completed' : 'incomplete')
-      : (task.assignee?.name ?? task.assignee?.gid ?? 'unassigned')
+    let key: string
+    if (groupBy === 'completed') {
+      key = task.completed ? 'completed' : 'incomplete'
+    }
+    else {
+      key = task.assignee?.name ?? task.assignee?.gid ?? 'unassigned'
+    }
     counts.set(key, (counts.get(key) ?? 0) + 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 `@src/lib/task-list-query.ts` around lines 205 - 215, The task grouping logic
in the task list query uses a conditional expression inline to choose the
grouping key, which is what the linter is flagging. Refactor the key selection
in the task iteration within task-list-query’s grouping flow into a simple
if/else (or equivalent local variable assignment) before updating the counts
Map, and keep the rest of the count aggregation, sorting, and groups mapping
behavior unchanged.

Source: Linters/SAST tools

🤖 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 `@src/lib/task-list-query.ts`:
- Around line 29-31: The `toTaskRows` mapper is treating dotted field names like
`assignee.name` as direct properties, so nested values are coming back null even
though `buildOptFields` allows them. Update `toTaskRows` to resolve column
values via dotted-path lookup for any field name it receives, or add explicit
handling for each supported nested field, and keep the existing
`FIELD_NAME_PATTERN`/`buildOptFields` behavior aligned with that lookup logic.

---

Nitpick comments:
In `@src/lib/task-list-query.ts`:
- Around line 205-215: The task grouping logic in the task list query uses a
conditional expression inline to choose the grouping key, which is what the
linter is flagging. Refactor the key selection in the task iteration within
task-list-query’s grouping flow into a simple if/else (or equivalent local
variable assignment) before updating the counts Map, and keep the rest of the
count aggregation, sorting, and groups mapping behavior 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b4132551-8df8-48f9-bd35-0a0be2b61512

📥 Commits

Reviewing files that changed from the base of the PR and between 8fd23dd and 176e717.

📒 Files selected for processing (9)
  • .gitignore
  • docs/content/en/2.features/1.task-management.md
  • docs/content/ko/2.features/1.task-management.md
  • src/commands/task.ts
  • src/constants/errorIds.ts
  • src/lib/task-list-query.ts
  • src/types/index.ts
  • test/commands/task-list-scan.test.ts
  • test/lib/task-list-query.test.ts

Comment thread src/lib/task-list-query.ts

@cubic-dev-ai cubic-dev-ai 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.

1 issue found across 9 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/lib/task-list-query.ts">

<violation number="1" location="src/lib/task-list-query.ts:184">
P2: Nested `--fields` values (for example `assignee.name`) currently render as `null` in task rows, so field expansion is incomplete for dotted opt_fields. This happens because `toTaskRows` uses direct bracket lookup for non-`assignee` columns instead of resolving dot paths.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant CLI as CLI Runner
    participant Cmd as task list Command
    participant Parser as parseTaskListQuery
    participant Client as Asana Client
    participant API as Asana REST API
    participant Users as users.me
    participant Output as Output Formatter

    Note over CLI,Output: Task List Request Flow with Scan Options

    CLI->>Cmd: execute "task list" with options
    Cmd->>Parser: parseTaskListQuery(options)
    alt Conflicting completion filters
        Parser-->>Cmd: CONFLICTING_OPTIONS error
    else Invalid field name
        Parser-->>Cmd: INVALID_FIELD_NAME error
    else Invalid group-by
        Parser-->>Cmd: INVALID_GROUP_BY error
    else Valid query
        Parser-->>Cmd: TaskListQuery { fields, assignee, ... }
    end

    Cmd->>Cmd: needsClientAssigneeFilter(query, hasProject)
    alt Client-side assignee filter needed (project or "none")
        Note over Cmd: assignee filter runs post-fetch
    end

    Cmd->>Cmd: buildOptFields(query, clientAssignee)
    alt Scan options active
        Note over Cmd: Sets opt_fields: [name, completed, assignee.name, assignee.gid, due_on, ...]
    else Legacy compact mode
        Note over Cmd: No opt_fields sent (undefined)
    end

    Cmd->>Cmd: Determine API parameters (completed_since for incomplete-only)

    Cmd->>Client: fetchTaskPage(client, options, params, clientAssignee)
    alt Project listing
        Client->>API: tasks.findByProject(projectGid, params)
        API-->>Client: Raw task array
    else Workspace with concrete assignee
        Client->>API: tasks.findAll({ assignee, workspace, ...params })
        API-->>Client: Raw task array
    else Workspace only
        Client->>API: tasks.findAll({ workspace, ...params })
        API-->>Client: Raw task array
    end
    Client-->>Cmd: taskList (raw tasks)

    alt Client-side assignee filter needed
        opt Resolve "me" to GID
            Client->>Users: users.me()
            Users-->>Client: { gid: "10", name: "Alice" }
        end
        Cmd->>Cmd: applyAssigneeFilter(tasks, assignee)
        Note over Cmd: Filters tasks by assignee.gid or "none" (unassigned)
    end

    opt Completion filter set (and not satisfied server-side)
        Cmd->>Cmd: applyCompletionFilter(tasks, query)
        Note over Cmd: Filters tasks by completed: true/false
    end

    alt Count or group-by mode
        Cmd->>Cmd: summarizeTasks(tasks, groupBy)
        Note over Cmd: Returns { summary: { total, groups[] } }
        Cmd->>Output: formatOutput({ summary }, format)
        Output-->>CLI: JSON/YAML summary
    else No tasks found
        Cmd-->>CLI: Yellow "No tasks found" message
    else Table mode with field expansion
        Cmd->>Cmd: effectiveColumns(query, clientAssignee)
        Cmd->>Cmd: toTaskRows(tasks, columns)
        Note over Cmd: Flattens assignee to name, null for missing
        Cmd->>Output: formatOutput({ tasks }, format)
        Output-->>CLI: Formatted table/JSON
    else Legacy compact mode
        Cmd->>Output: formatOutput({ tasks: rawList }, format)
        Output-->>CLI: Default listing (no opt_fields)
    end
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/lib/task-list-query.ts
- resolve dotted --fields paths (e.g. assignee.name) in toTaskRows via a
  nested getter instead of a flat key lookup
- correct the module docblock: validation helpers print to stderr before
  throwing, so they are not pure
@amondnet

amondnet commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

/gemini review

@sonarqubecloud

sonarqubecloud Bot commented Jul 6, 2026

Copy link
Copy Markdown

@gemini-code-assist

Copy link
Copy Markdown

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@amondnet amondnet merged commit a9a0649 into main Jul 6, 2026
16 checks passed
@amondnet amondnet deleted the amondnet/agent-interface-benchmark-task-list-lacks-field branch July 6, 2026 12:36
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.

Agent-interface benchmark: task list lacks field expansion and aggregation, causing turn blow-up on scan-style tasks

1 participant