Skip to content

Document flaky-tests API conventions and pagination#173

Draft
samgutentag wants to merge 1 commit into
mainfrom
sam-gutentag/api-conventions
Draft

Document flaky-tests API conventions and pagination#173
samgutentag wants to merge 1 commit into
mainfrom
sam-gutentag/api-conventions

Conversation

@samgutentag
Copy link
Copy Markdown
Member

Reopens the work from #57, which was merged then reverted on 2026-06-01 (it was not ready to merge). Content is unchanged from the original branch; needs content verification against source before re-merging. Reverted merge commit removed from main.

…ation, Bundle Upload ID

Expand the Flaky Tests API reference index page with an "API conventions"
section covering behavior that applies across endpoints. Sourced from
recurring customer questions: page_token misuse returning 500s, "missing"
tests that were actually on later pages, rate-limit expectations for
polling automation, and webhook-to-API immediacy.

Also documents three things that weren't surfaced anywhere in narrative
form: Bundle Upload IDs are support-only, auto-analysis has a default
monthly cap during Beta, and the UI's GraphQL endpoint is private.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@samgutentag samgutentag force-pushed the sam-gutentag/api-conventions branch from ea55da9 to 4aaa9a7 Compare June 1, 2026 21:31
@samgutentag
Copy link
Copy Markdown
Member Author

Code verification (2026-06-01): 8 confirmed / 0 contradicted / 1 ambiguous / 1 unverifiable

Claim Verdict Source
page_size capped at 100 confirmed public-api/src/schema.ts:728-736
page_token, next_page_token, prev_page_token, last_page_token, page_query field names confirmed public-api/src/schema.ts:729-784
List endpoints list-unhealthy-tests, list-quarantined-tests, list-failing-tests confirmed public-api/src/routes_protected.ts:2649-2815
First page: omit page_token / pass empty string confirmed public-api/src/schema.ts:737-748
Invalid page_token returns 500 confirmed public-api/src/routes_protected.ts:833-844
Bundle Upload ID printed by trunk-analytics-cli upload confirmed cli/src/upload_command.rs:644-645
Bundle Upload ID not exposed via public API confirmed public-api/src/schema.ts (no bundle_upload_id field)
x-api-token header for auth confirmed public-api/src/routes_protected.ts:687
status_changed webhook, healthy to flaky transition ambiguous docs2 flaky-tests/webhooks/index.mdx:52
No eventual-consistency window between webhook and read APIs unverifiable timing/behavioral claim, no source trace

No contradictions. Nothing blocks publishing on a factual-accuracy basis. Two items the author should tighten before merge:

  1. Webhook event name (ambiguous). The PR calls it "the status_changed webhook" transitioning "from healthy to flaky." The real event type is v2.test_case.status_changed (with an older test_case.monitor_status_changed variant), carrying previous_status / new_status fields. The bare status_changed shorthand is informal, and the exact lowercase status strings healthy / flaky are not enumerated in the webhooks doc or schema (the read API uses uppercase enums like FLAKY / BROKEN). Recommend referencing the full event type v2.test_case.status_changed and softening the literal status-string example, or confirming the exact payload strings with eng.

  2. Immediate-propagation claim (unverifiable). "There is no eventual-consistency window between the webhook and the read APIs" is a timing/behavioral assertion that can't be confirmed from the schema or route code. It needs a backend write/read path trace or an eng confirmation. Consider softening to "typically reflected promptly" unless eng confirms a hard guarantee.


Source #1 — page_size capped at 100 (confirmed)

File: trunk-io/trunk/trunk/services/public-api/src/schema.ts#L728-L736

const MAX_PAGE_SIZE = 100;
export const PAGE_REQUEST_SCHEMA = z
  .object({
    page_size: z
      .number()
      .int()
      .min(1)
      .max(MAX_PAGE_SIZE)
      .openapi({ description: "The number of tests to return per page." }),

Reasoning: PAGE_REQUEST_SCHEMA is the Zod schema applied to page_query on all three flaky-tests list endpoints. page_size is constrained .min(1).max(MAX_PAGE_SIZE) where MAX_PAGE_SIZE = 100. The doc's "capped at 100" matches exactly.

Source #2 — pagination field names (confirmed)

File: trunk-io/trunk/trunk/services/public-api/src/schema.ts#L737-L784

    page_token: z
      .string()
      .optional()
      .openapi({ description: "The page token to use for pagination. ...", examples: [""] }),
...
    next_page_token: z.string().openapi({ ... }),
    prev_page_token: z.string().openapi({ ... }),
    last_page_token: z.string().openapi({ ... }),

Reasoning: Request schema defines page_token; response schema (PAGE_RESPONSE_SCHEMA) defines next_page_token, prev_page_token, last_page_token. The endpoint request schemas wrap these in page_query: PAGE_REQUEST_SCHEMA. All names in the PR match the source casing exactly (snake_case).

Source #3 — list endpoint names (confirmed)

File: trunk-io/trunk/trunk/services/public-api/src/routes_protected.ts#L2649-L2815

    path: "/flaky-tests/list-quarantined-tests",
...
    path: "/flaky-tests/list-unhealthy-tests",
...
    path: "/flaky-tests/list-failing-tests",

Reasoning: All three endpoint paths exist as registered protected routes, each destructuring page_query: { page_size: pageSize, page_token: pageToken }, confirming all three support the documented pagination shape.

Source #4 — first page empty token (confirmed)

File: trunk-io/trunk/trunk/services/public-api/src/schema.ts#L737-L748

    page_token: z
      .string()
      .optional()
      .openapi({
        description:
          "The page token to use for pagination. This is returned from the previous call to this endpoint. For the first page, this should be empty.",
        examples: [""],
      }),

Reasoning: page_token is .optional() and the schema's own doc string says "For the first page, this should be empty," matching the PR's "omit page_token or pass an empty string."

Source #5 — invalid page_token returns 500 (confirmed, behavioral)

File: trunk-io/trunk/trunk/services/public-api/src/routes_protected.ts#L833-L844

  logger.warn("Global error handler caught an error - returning 500", { ... });
  res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
    message: "An unexpected error occurred. Please try again later.",
  });

Reasoning: The route forwards page_token straight to the backend via pgPageQuery.setPageToken(pageToken) (line ~2569) without local validation. A token that didn't come from a prior response fails backend decoding, which surfaces through this global error handler as HTTP 500. This is a behavioral inference (the route has no explicit "invalid token" branch), but the 500 outcome is consistent with source. Note: it's not a clean 400 validation error, so the doc's "returns a 500" is accurate as written.

Source #6 — Bundle Upload ID printed by CLI (confirmed)

File: trunk-io/analytics-cli/cli/src/upload_command.rs#L644-L645

pub fn get_bundle_upload_id_message(bundle_upload_id: &str) -> String {
    format!("🏷️  Bundle Upload ID: {}", bundle_upload_id)
}

Reasoning: The upload command prints exactly Bundle Upload ID: <id> after upload (gated on a non-empty bundle_upload_id). Matches the PR's claim that trunk-analytics-cli upload prints a Bundle Upload ID.

Source #7 — Bundle Upload ID not exposed via public API (confirmed)

File: trunk-io/trunk/trunk/services/public-api/src/schema.ts

(grep for bundle_upload_id / upload_id / bundleUploadId in schema.ts → no matches)

Reasoning: No bundle_upload_id, upload_id, or bundleUploadId field appears anywhere in the canonical public API schema. This supports the PR's claim that the ID is "not exposed via the public API today" and "not URL-searchable."

Source #8 — x-api-token header (confirmed)

File: trunk-io/trunk/trunk/services/public-api/src/routes_protected.ts#L687

    const apiToken = parseResult.data[API_TOKEN_HEADER_KEY];

Reasoning: Protected routes read the org token from API_TOKEN_HEADER_KEY (the x-api-token header), matching the PR's auth requirement. The existing (unchanged) doc line referencing x-api-token is consistent with source.

Source #9 — status_changed webhook / healthy→flaky (ambiguous)

File: trunk-io/docs2/flaky-tests/webhooks/index.mdx#L52-L62

### `v2.test_case.status_changed`

Emitted when a test case changes status (e.g., becomes flaky or is resolved), as triggered by a monitor.

| `type` | string | Always `v2.test_case.status_changed` |
| `previous_status` | string | The prior status of the test case |
| `new_status` | string | The updated status of the test case |

Reasoning: The PR's "status_changed webhook" is a loose reference to v2.test_case.status_changed (older variant: test_case.monitor_status_changed). The webhook doc does not enumerate the literal status strings, so the PR's healthy / flaky lowercase values are not source-confirmed; the read API uses uppercase enums (FLAKY, BROKEN). Recommend using the full event type and confirming the exact payload status strings with eng before publishing.

Source #10 — immediate webhook-to-API propagation (unverifiable)

File: n/a

Reasoning: "There is no eventual-consistency window between the webhook and the read APIs" is a timing guarantee about the backend write/read path, not a name/value/path claim. It cannot be confirmed from the public API schema or route definitions. Needs a backend trace or eng confirmation. Not blocking, but recommend softening unless eng confirms a hard guarantee.

@samgutentag samgutentag added the code-verified-partial verify-docs-against-code: confirmed claims, some unverifiable. label Jun 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

code-verified-partial verify-docs-against-code: confirmed claims, some unverifiable.

Development

Successfully merging this pull request may close these issues.

1 participant