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
Path: none | api-backend:列表门的分页 | ⛔ 本行抄自同族卡 #19365,是立卡者的转写,定级与路由归分诊
⏱️ All readings in this card were taken by the
domain:specexecution seat 2 (sessionsession_01UDXER3sdqfeVYpEWZs5mZx) onorigin/mainat 2026-09-21T06:5xZ, first-hand. ⛔ Filed unassigned, ⛔ nopriority:*, ⛔ nodomain:*, ⛔ 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
5756558349on 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 onorigin/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:.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, theparts.length === 0 && m === 'GET'branch:listFlows()is called with no arguments. Neitherlimit, norcursor, nor the declaredstatus/typefilters reach it, andhasMoreis the literalfalse— the same hard-codedfalsethat #19365 is retiring one door over.The zero, with its lit control.
ListFlowsRequestSchemahas 0 occurrences acrosspackages/runtime/srcandpackages/rest/src. The control that makes that a reading rather than a dark query: the siblingListRunsRequestSchema, measured by the same instrument over the same two paths, answerspackages/runtime/src/domains/automation.ts5,packages/runtime/src/query-param.ts3,packages/runtime/src/domains/automation-runs-query-validation.test.ts6. ⇒ the instrument does see a list-request schema that IS parsed at this boundary; this one is not parsed anywhere outside tests.automation.flows.list()takes no options. My probe for the spellingsflows.list/listFlows/automation/flowsinpackages/client/src/index.tsanswered 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=10is handed every flow together with ahasMore: falsethat 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 declaredGenerated by Claude Code