feat: complete issue list filters, sort, and fields (task 0002) #5

Merged
alexion merged 4 commits from task-0002-issue-list-filters-and-fields into main 2026-07-12 09:29:35 -04:00
Owner

Task: .claude/tasks/0002-issue-list-filters-and-fields.md

Completes the issue list flag surface left minimal by the tracer slice.

  • Server-side filters--label (comma-separated names, passed through), --assignee, --author, --milestone, mapped to Gitea's labels, assigned_by, created_by, milestones params. All four filter server-side in a single request, alongside the existing type=issues guard.
  • Client-side --sort <created|updated|comments> — always descending, over the fully paginated set (ADR 0005). The count line keeps T from X-Total-Count, since sorting reorders without changing membership.
  • --fields <a,b,c> — appends body, closedAt, labels, milestone, updatedAt, url via the FieldDef extractors.
  • --search is refused with a VALIDATION_ERROR (exit 2) redirecting to search issues, in its valued, inline, and bare forms.

Deviations

Exhaustive pagination landed as a shared src/paginate.ts rather than a detail of this command, because ADR 0005 makes it a policy that pr list and the dashboard will reuse. lookup.ts's listAllLabels hand-rolled the same loop and now calls the shared helper. The helper carries the 20-page cap those local constants encoded, matching the 1000-item ceiling Principle 8 sets on exhaustive pagination — without it, a server that ignores paging would loop forever.

Two count-line details the acceptance criteria did not spell out. Under --sort, --limit caps the sorted result rather than the fetch, so pages are read at the full page size of 50 and the limit selects the top N by the sort key. Also under --sort, when an instance omits X-Total-Count, the total falls back to the size of the fully paginated set rather than degrading to count: N (showing first N) — everything was fetched in order to sort it, so the total is known, and Principle 4 says a total is always reported.

--state and --sort shared an enum-parsing shape, now extracted as parseEnumFlag in flags.ts.

Review

Risk

Overall: Medium

  • Blast radius — Low. Confined to issue list plus a new paginate.ts; the one existing caller changed (lookup.ts) keeps its behaviour.
  • Reversibility — Low. Pure addition, no migrations or persisted state; the new flags are additive CLI surface.
  • Test coverage — Low. Fixture-server tests cover every filter mapping, all three sort keys, multi-page pagination, the page cap, the --limit interaction, --fields, and the --search refusal in all three flag forms.
  • Sensitive domain — Low. Read-only issue listing; no auth, permissions, or concurrency.
  • Size & complexity — Medium. issueList now branches between a single-page and a fetch-everything path, whose sort and limit semantics differ.
  • Runtime criticality — Medium. issue list is a primary command, and --sort walks every page on a large repo (now bounded at 20 pages).

Unaddressed findings

Spec — --fields body renders raw and untruncated. This is what the task and the spec's command surface ask for ("body (raw)"), and it matches the already-merged issue create --fields body. It contradicts Principle 3 ("Body text is truncated at 500 characters in all contexts (list and detail alike)"): a 30-row list with --fields body can now emit 30 full bodies, the exact cost Principle 3 exists to prevent. Left as specified rather than fixed here, because truncating in issue list alone would make it disagree with issue create — the conflict wants one ruling applied to both commands, not a silent divergence in this slice.

Task: `.claude/tasks/0002-issue-list-filters-and-fields.md` Completes the `issue list` flag surface left minimal by the tracer slice. - **Server-side filters** — `--label` (comma-separated names, passed through), `--assignee`, `--author`, `--milestone`, mapped to Gitea's `labels`, `assigned_by`, `created_by`, `milestones` params. All four filter server-side in a single request, alongside the existing `type=issues` guard. - **Client-side `--sort <created|updated|comments>`** — always descending, over the fully paginated set (ADR 0005). The count line keeps `T` from `X-Total-Count`, since sorting reorders without changing membership. - **`--fields <a,b,c>`** — appends `body`, `closedAt`, `labels`, `milestone`, `updatedAt`, `url` via the FieldDef extractors. - **`--search` is refused** with a `VALIDATION_ERROR` (exit 2) redirecting to `search issues`, in its valued, inline, and bare forms. ## Deviations Exhaustive pagination landed as a shared `src/paginate.ts` rather than a detail of this command, because ADR 0005 makes it a policy that `pr list` and the dashboard will reuse. `lookup.ts`'s `listAllLabels` hand-rolled the same loop and now calls the shared helper. The helper carries the 20-page cap those local constants encoded, matching the 1000-item ceiling Principle 8 sets on exhaustive pagination — without it, a server that ignores paging would loop forever. Two count-line details the acceptance criteria did not spell out. Under `--sort`, `--limit` caps the *sorted* result rather than the fetch, so pages are read at the full page size of 50 and the limit selects the top N by the sort key. Also under `--sort`, when an instance omits `X-Total-Count`, the total falls back to the size of the fully paginated set rather than degrading to `count: N (showing first N)` — everything was fetched in order to sort it, so the total is known, and Principle 4 says a total is always reported. `--state` and `--sort` shared an enum-parsing shape, now extracted as `parseEnumFlag` in `flags.ts`. ## Review ### Risk **Overall: Medium** - **Blast radius — Low.** Confined to `issue list` plus a new `paginate.ts`; the one existing caller changed (`lookup.ts`) keeps its behaviour. - **Reversibility — Low.** Pure addition, no migrations or persisted state; the new flags are additive CLI surface. - **Test coverage — Low.** Fixture-server tests cover every filter mapping, all three sort keys, multi-page pagination, the page cap, the `--limit` interaction, `--fields`, and the `--search` refusal in all three flag forms. - **Sensitive domain — Low.** Read-only issue listing; no auth, permissions, or concurrency. - **Size & complexity — Medium.** `issueList` now branches between a single-page and a fetch-everything path, whose sort and limit semantics differ. - **Runtime criticality — Medium.** `issue list` is a primary command, and `--sort` walks every page on a large repo (now bounded at 20 pages). ### Unaddressed findings **Spec — `--fields body` renders raw and untruncated.** This is what the task and the spec's command surface ask for ("`body` (raw)"), and it matches the already-merged `issue create --fields body`. It contradicts Principle 3 ("Body text is truncated at **500 characters** in all contexts (list and detail alike)"): a 30-row list with `--fields body` can now emit 30 full bodies, the exact cost Principle 3 exists to prevent. Left as specified rather than fixed here, because truncating in `issue list` alone would make it disagree with `issue create` — the conflict wants one ruling applied to both commands, not a silent divergence in this slice.
alexion added 1 commit 2026-07-11 23:06:14 -04:00
feat: complete issue list filters, sort, and fields (task 0002)
All checks were successful
CI / test (pull_request) Successful in 28s
605c46f73a
Finish the `issue list` flag surface left minimal by the tracer slice:

- Server-side filters `--label`, `--assignee`, `--author`, `--milestone`,
  mapped to Gitea's `labels`, `assigned_by`, `created_by`, `milestones`.
- Client-side `--sort <created|updated|comments>`, always descending, over
  the fully paginated set (ADR 0005); `--limit` caps the sorted result.
- `--fields` exposing body, closedAt, labels, milestone, updatedAt, url.
- `--search` refused with a VALIDATION_ERROR redirecting to `search issues`.

Exhaustive pagination lands as a shared `paginate.ts`, since ADR 0005 makes
it a policy later slices reuse; `lookup.ts` drops its hand-rolled copy of the
same loop. The helper carries the 20-page cap that copy encoded, matching the
1000-item ceiling Principle 8 sets.
alexion added 1 commit 2026-07-11 23:06:32 -04:00
docs: prefer gitea-axi over tea for opening pull requests
All checks were successful
CI / test (pull_request) Successful in 27s
9a902d2d37
alexion added 1 commit 2026-07-12 09:26:01 -04:00
docs: capture the --fields body truncation conflict as task 0021
All checks were successful
CI / test (pull_request) Successful in 28s
13883fa6e1
alexion added 1 commit 2026-07-12 09:28:47 -04:00
Merge branch 'main' into task-0002-issue-list-filters-and-fields
All checks were successful
CI / test (pull_request) Successful in 26s
19018772d7
alexion merged commit 3c581b7c0e into main 2026-07-12 09:29:35 -04:00
alexion deleted branch task-0002-issue-list-filters-and-fields 2026-07-12 09:29:36 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: alexion/gitea-axi#5