10. Lists, cache and lifecycle settings
- A route is a list when it comes from the
listop, or when it setsiteminstead ofoutput.outputalways means the whole body; an arrayoutputon a GET is refused with the fix “useitem”, so an author always knows whether a route is paged. paging: on a list. It names a paging style from thepagingscatalogue (section 14):paging: cursor, or the mapping form{ cursor: { maxLimit: 50 } }, which also takesdefaultLimit,overLimitand, for a style with asincerole,token: opaqueortoken: instant. A list withoutpagingusesconventions.paging.default. A list with neither is a compile error naming both fixes: declare a style inpagingsand name it, or apply a format pack that provides one (A31).paging: noneserves the whole list unpaged, through the format’slistshape. A style with asincerole derives 410 from thegonerole (FR-31, SCN-012, SCN-082, SCN-083).sortable: a list of item fields, each a name or{ key, right }. A key inherits its field’srestrictedTo; an explicit right that disagrees is a compile error, and so issortableon apaging: nonelist, which has nosortrole to send the keys; sorting by a restricted key without the right derives 403 from thesortKeyForbiddenrole (FR-23, SCN-067).filteredBy: <right>: the right the application applies to its query; it reaches OpenAPI and the handler context, and nothing enforces it (SCN-068).degradable: [viewerProgress]: paths of optional properties of the success data (the body of the first 2xx response), a nested one written with dots (stats.views) through object properties, and through a union in every one of its variants; a required one, or a path that names no property (in any variant), is a compile error (SCN-085). When the degraded header is written (conventions.degradedHeader), a property name in a path may hold no comma, no character outside visible ASCII and space, and no leading or trailing space, since the header lists the paths as written; such a path is a compile error.cache: { freshness: minute, anonymous: public, vary: [Accept-Language], etag: true }.freshnessis a family fromconventions.cache.familiesornever(no-store);anonymous(publicorprivate) applies to anonymous callers only, since an identified caller always gets private, and the shared-cache directives of a family (s-maxage) are written for public responses only;etag: truegenerates conditional GET (FR-33, SCN-013, SCN-086). Acachewritten on a route that is not a GET is a compile error; one inherited from a node applies to the GET routes below it only. TheVaryentries for credentials (Cookie,Authorization, an API-key header) are derived from the schemes of the route’s identity;varylists only the other request headers the response depends on. A response that carries asensitivefield isno-store(ADR 0003 section 6), so acachewith a family other thanneveron such a route is a compile error naming the field and the route, with the fix “dropcacheorsensitive”: the contract never says one thing while the wire does another. A sensitive value outside a field of the body (a declared sensitive scalar answered as the whole body or its items, as a map key or as a response header) isno-storethe same way, or a compile error naming the value and the route underconventions.cache.sensitiveElsewhere: refuse(section 13).budget: 300ms: the client’s default timeout and the deadline sent on an identity with adeadlineheader (SCN-043, SCN-078).bodyLimit: 2MiB: overridesconventions.bodyLimit(SCN-041).format: bare: the wire format of the routes below, instead ofconventions.format, for an endpoint whose body a third party fixes (a load balancer’s health probe, a vendor’s callback). It names any declared format.idempotency: { exempt: "<reason>" }: a write without the idempotency key (SCN-042). The generated clients send the key: a client target creates a fresh key per call (a UUID v4) unless the caller passes one, and returns it with the result. A client never replays a write by itself (FR-15); a caller that retries passes the key of the first attempt, so the write runs once.internal: true: keeps the route out of documents withinternal: exclude(product apis only, SCN-044); written on a service api, it is a compile error.upstream: [streaming, catalog]: services from theservicescatalogue, the owning service first. The operation’s maturity derives from the owning service, otherwise fromapi.maturity(FR-34).maturity: experimental, ormaturity: { level: experimental, reason: "<reason>" }to say why: a stated maturity on a node, which wins over the derived level; on the api,maturityis the default every operation derives from. A stated level equal to the derived one is reported by the lint ruleseampact/redundant-maturity, silenced throughlint.allow(SCN-087, SCN-018).deprecated: { since: '2026-12-31', sunset: '2027-06-30', successor: getTask }: derives the deprecation, sunset and successor headers (FR-13, SCN-051);successoronly on a route.since(required) andsunsetare calendar dates,sincenot aftersunset; a successor’s path params are path params of the deprecated route, of the same type. Their names default to RFC 9745’sDeprecation, RFC 8594’sSunsetand aLinkwith relationsuccessor-version, andconventions.deprecationrenames them (A36).tags: [tasks].
# shared/base.yaml (excerpt)services: catalog: { maturity: stable } streaming: { maturity: provisional }