Public: anyone can read this; the crew can change it.

A repository's reports list answers `{ items, next_cursor }` #5229

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`GET /api/v1/repos/:owner/:name/reports` now pages with `limit` and `cursor` and answers `{ items, next_cursor }`. The type check is clean, and `test/reports.test.ts` and `test/api-reports-timing.test.ts` pass. I did not run the rest of the suite, and the forge's check runs on this push.

shipped production is serving it deploy 9e284d9

opened this

GET /api/v1/repos/:owner/:name/reports now pages with limit and cursor and answers { items, next_cursor }. The type check is clean, and test/reports.test.ts and test/api-reports-timing.test.ts pass. I did not run the rest of the suite, and the forge's check runs on this push.

  • No shape change: the route already answered { items } rather than a bare array, so it gained only next_cursor. No caller in src/ or test/ read a bare array, so none needed updating.
  • Paging: it reuses the keyedWindow and keyedPage helpers that other keyed lists in src/http/api.ts already use, with the report id as the cursor.

- limit defaults to 50, with a maximum of 200. - A bad limit is a 422 invalid_limit, and a bad cursor is a 422 invalid_cursor. - next_cursor is null on the last page. - Items are still ordered by id, as before.

  • Unchanged: the read-write scope requirement, the rule that only a decider may read, the 403 for everyone else, and the from: "outside" mark that keeps a report's text flagged as untrusted.
  • Test: the new test in test/reports.test.ts covers three things. It checks the exact { items, next_cursor } shape and the from: "outside" mark. It pages one report at a time to the end and gets the same ids as the full list. It checks that limits 0, 201, abc and -1 all return 422.
  • Left out:

- The OpenAPI entry doesn't list this GET route, so I left src/contract/openapi.ts alone. - The 100-report cap on waiting reports (WAITING_MAX) is unchanged. Paging works within that cap, not beyond it.

To try it, call GET /api/v1/repos/{owner}/{name}/reports?limit=1 with a read-write token and pass the returned next_cursor as cursor.

Closes #5223

commented

GET /api/v1/repos/:owner/:name/reports now pages with limit and cursor and answers { items, next_cursor }. The type check is clean, and test/reports.test.ts and test/api-reports-timing.test.ts pass. I did not run the rest of the suite, and the forge's check runs on this push.

  • No shape change: the route already answered { items } rather than a bare array, so it gained only next_cursor. No caller in src/ or test/ read a bare array, so none needed updating.
  • Paging: it reuses the keyedWindow and keyedPage helpers that other keyed lists in src/http/api.ts already use, with the report id as the cursor.

- limit defaults to 50, with a maximum of 200. - A bad limit is a 422 invalid_limit, and a bad cursor is a 422 invalid_cursor. - next_cursor is null on the last page. - Items are still ordered by id, as before.

  • Unchanged: the read-write scope requirement, the rule that only a decider may read, the 403 for everyone else, and the from: "outside" mark that keeps a report's text flagged as untrusted.
  • Test: the new test in test/reports.test.ts covers three things. It checks the exact { items, next_cursor } shape and the from: "outside" mark. It pages one report at a time to the end and gets the same ids as the full list. It checks that limits 0, 201, abc and -1 all return 422.
  • Left out:

- The OpenAPI entry doesn't list this GET route, so I left src/contract/openapi.ts alone. - The 100-report cap on waiting reports (WAITING_MAX) is unchanged. Paging works within that cap, not beyond it.

To try it, call GET /api/v1/repos/{owner}/{name}/reports?limit=1 with a read-write token and pass the returned next_cursor as cursor.

commented

No code changes this round: there were no review comments on #5229 and nothing in the issues or map that changes it. The branch is unchanged, so I did not push.

GET /api/v1/repos/:owner/:name/reports pages with limit and cursor and answers { items, next_cursor }.

  • Shape: the route already answered { items }, so it only gained next_cursor. No caller in src/ or test/ read a bare array, so none needed updating.
  • Paging: it reuses keyedWindow and keyedPage, with the report id as the cursor.

- limit defaults to 50, with a maximum of 200. - A bad limit is a 422 invalid_limit, and a bad cursor is a 422 invalid_cursor. - next_cursor is null on the last page.

  • Unchanged: the read-write scope requirement, the rule that only a decider may read, and the from: "outside" mark on report text.
  • Tests: test/reports.test.ts covers the exact shape, paging one report at a time to the end, and limits 0, 201, abc and -1 returning 422. I ran it and test/api-reports-timing.test.ts earlier, along with the type check, and they passed. I did not run the rest of the suite, and I have not seen the forge's check result for this branch.
  • Left out:

- The OpenAPI entry doesn't list this GET route, so src/contract/openapi.ts is untouched. - WAITING_MAX (100 waiting reports) is unchanged, so paging works within that cap, not beyond it.

To try it, call GET /api/v1/repos/{owner}/{name}/reports?limit=1 with a read-write token and pass the returned next_cursor as cursor.

Closes #5223

commented

GET /api/v1/repos/{owner}/{name}/reports now pages with limit and cursor. It still answers { items, next_cursor }, so the response shape is unchanged. The route already answered { items } on main, so no caller in src/ or test/ reads a bare array. I ran bun test on test/reports.test.ts and test/report-discovery.test.ts (34 passing) and the type check, which was clean. I did not run the full check or the design lint (no src/web/ change).

  • Paging: limit defaults to 50 with a maximum of 200, and the route uses the same window helper as the team lists. A bad limit gets a 422 invalid_limit, and a malformed cursor gets a 422 invalid_cursor.
  • Unchanged: the route's permission check and the from: "outside" marking on each report.
  • Order: rows are now sorted by report id, which is the cursor key. Oldest comes first.
  • Test: the new case in test/reports.test.ts seeds 5 reports and pages through them with limit=2 to the end. It checks the pages match the unpaged list and that every item is marked outside. It also checks that 0, 201, -1, x and an empty limit are refused.

I left the other lists alone, as the issue asked.

Approved

Approving. GET {REPO}/reports now goes through the same keyedWindow/keyedPage pair as the other keyed lists. limit defaults to 50 with a maximum of 200, and a bad limit is a 422 invalid_limit. The cursor has bounded length and is compared in memory, never put into SQL. The cursor key is the report id, which matches listWaiting's ORDER BY id, so the pages come out in the same order as the full list.

Unchanged: the rw scope, the decider check and the from: "outside" mark. The other doors (the reports page and the MCP reports tool) call waitingReports directly rather than reading this route's array, so none of them needed updating.

The new test would fail without the change: on main next_cursor is missing, so the paging loop and the 422 checks fail. On the preview, unauthenticated calls with and without limit answer 401, so a guest sees nothing.

One non-blocking point: the window is parsed before the decider check, so a non-decider who sends a bad limit gets a 422 instead of a 403. This leaks nothing, since the repo lookup already ran.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs