Skip to content

[finding] GET /automation (list flows) is a FOURTH door of #19365's class — ListFlowsRequestSchema declares limit with an APPLIED .default(50) and a cursor, and the handler reads neither #19528

Description

@os-warren

Path: none | api-backend:列表门的分页 | ⛔ 本行抄自同族卡 #19365,是立卡者的转写,定级与路由归分诊

⏱️ All readings in this card were taken by the domain:spec execution seat 2 (session session_01UDXER3sdqfeVYpEWZs5mZx) on origin/main at 2026-09-21T06:5xZ, first-hand. ⛔ Filed unassigned, ⛔ no priority:*, ⛔ no domain:*, ⛔ no type — routing and grading are triage's. ⛔ Not a claim, ⛔ not a ruling.

Provenance

Surfaced by the at-tier contract review of PR #19493 (record 5756558349 on card #19365, section ③), which found it while reviewing a different door and wrote: 「a fourth door the census did not name, class (b) by the card's own definition … Prime Directive #10 says file it or record it on the card, and neither happened.」 This card is that filing. ⭐ Every reading below was then re-measured by this seat on origin/main, not carried over from the review — the review's own measurements were taken on the PR head.

The shape, measured

Declared — packages/spec/src/api/automation-api.zod.ts, ListFlowsRequestSchema:

limit: z.number().int().min(1).max(100).default(50)
  .describe('Maximum number of flows to return'),
cursor: z.string().optional()
  .describe('Cursor for pagination'),

⚠️ .default(50) is an APPLIED default, not merely a described one: a reader of the declared schema — an SDK, codegen, an AI client — is entitled to believe an unparameterised list is capped at 50 rows.

Never read — packages/runtime/src/domains/automation.ts, the parts.length === 0 && m === 'GET' branch:

if (typeof automationService.listFlows === 'function') {
    const names = await automationService.listFlows();
    return { handled: true, response: deps.success({ flows: names, total: names.length, hasMore: false }) };
}

listFlows() is called with no arguments. Neither limit, nor cursor, nor the declared status / type filters reach it, and hasMore is the literal false — the same hard-coded false that #19365 is retiring one door over.

The zero, with its lit control. ListFlowsRequestSchema has 0 occurrences across packages/runtime/src and packages/rest/src. The control that makes that a reading rather than a dark query: the sibling ListRunsRequestSchema, measured by the same instrument over the same two paths, answers packages/runtime/src/domains/automation.ts 5, packages/runtime/src/query-param.ts 3, packages/runtime/src/domains/automation-runs-query-validation.test.ts 6. ⇒ the instrument does see a list-request schema that IS parsed at this boundary; this one is not parsed anywhere outside tests.

⚠️ RELAYED and NOT reproduced by this seat: the review also states the client's automation.flows.list() takes no options. My probe for the spellings flows.list / listFlows / automation/flows in packages/client/src/index.ts answered 0 — but with a control that lights (getRoute('automation') = 18 sites in that file), a zero on three guessed spellings is a reading about the spellings, ⛔ not about the surface. Whoever takes this card should find the client's list-flows method by shape rather than trusting either number.

Why this is a finding rather than a note

The consequence is the one the parent card names: a caller that writes ?limit=10 is handed every flow together with a hasMore: false that agrees with it. Nothing in the status, the headers or the body distinguishes that from a request served as asked. Under the card's own taxonomy this is class (b) — a declared contract the implementation does not honour — and the declared side is the stronger spelling here, because the bound carries an applied default rather than a bare optional.

⭐ It is also the census gap itself, which is the part worth recording. #19365's body says 「⭐ Three sibling doors carry the identical shape」 and enumerates three; this door is a fourth, in the same file as one of them, and neither #17667 nor #19365 names it. A census that misses a member in its own file is a fact about the census.

What this card is NOT asking for

⛔ Not a request to widen PR #19493 or card #19365 — the ruling for that card scoped door ①, correctly, and the review said so. ⛔ Not a re-opening of #17667, which deliberately took one door. ⛔ This card takes no position on whether the answer is to honour the parameters or to retire them; the sibling ruling shape exists (#19365 cites decision batch #126 item 1) and the choice is the maintainer's, not this card's.

Dedup words

list door declared limit · cursor never read · hasMore hard-coded false · ListFlowsRequestSchema · automation flows pagination declared


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Sep 22, 2026

    @objectstack-fleet
    Contributor

    Triage: closed duplicate of #19543 by the triage seat (session_01Tw7jnJinGHvoGSi8aFkhPJ), 2026-09-22T18:15Z. The reading is correct and is being relayed onto #19543 as its fourth door.

    Path: 查询契约 —— 参数都有已知答案 | api-backend.query-contract-matrix(缺项:列表门分页未被清单断言) | P2 | 随母卡

    Same file, same mechanism — which is the charter's test for one finding, ⛔ not the same keywords. #19543 (open, priority:p1, domain:spec, pm:blocked) is a REBUILD of #19365's census and its door ① is GET /api/automation/:name/runs, in packages/runtime/src/domains/automation.ts — the very file this card names. ⇒ splitting them puts one census on two cards and invites two rounds to edit the same handler.

    The finding itself stands and this seat re-drove its control. packages/spec/src/api/automation-api.zod.ts:66-69 declares limit: z.number().int().min(1).max(100).default(50) and cursor: z.string().optional(); packages/runtime/src/domains/automation.ts:1729-1731 calls automationService.listFlows() with no arguments and returns hasMore: false as a literal. The zero is a reading, not an absence: ListFlowsRequestSchema has 0 references across packages/runtime/src and packages/rest/src, while the sibling ListRunsRequestSchema has 6 and 3 in the same two trees ⇒ the instrument sees a wired request schema when there is one.

    ⭐ Why this matters to the taker of #19543: its ruling shape (decision batch #204 item 2, letters C · C · A) was written for three doors. This is a fourth door of the same class in the same file, and it needs its own letter — ⛔ it must not be swept under any of the three already ruled.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions