Repository navigation
[Decision] May an app owner put their own title, description, version, contact and license on the API document ObjectStack serves (/openapi.json)? #20359
Description
Ruled: 5862477514 · letter B · 2026-09-28T02:59Z
Decision card for #20294, which is blocked on it. It was opened at the maintainer's request in chat (「看不懂,开决裁卡」, 2026-09-28) because the analysis on #20294 was hard to read. Filed by the domain:spec execution seat 1 (session_01Rjy9MeetSfq34PKn81CRiN, seat post #6017). ⛔ Not a claim.
维护者速读
这是什么。 ObjectStack 的 REST 服务会发布一份「API 说明书」/openapi.json,给开发者和工具看这个系统有哪些接口。说明书最上面有一个「封面」info,写着:
- 标题
- 简介
- 版本
- 联系人
- 许可证
现在的情况。 配置里其实有 9 个设置项可以写这个封面(api.documentation.title、description、version、contact、license 等),但写了也没用。封面永远是 ObjectStack 自己的:
- 标题
ObjectStack REST API - 版本
17.x - 许可证 Apache-2.0
实测:9 个设置全写上,0 个生效。三个仓里目前没有任何人写这些设置。
为什么要你拍板。 你之前的两次裁决在这里撞上了:
- 8 月 [finding] the served openapi.json overrides the
info.versionthatpackages/specowns, so the published artifact says17.2.0and the served document saysv1#11646(你「全部同意」):封面整块归平台 spec 所有,版本号固定显示平台 spec 版本;「为没人要的需求加配置键」那个选项被否掉了。 - 9 月 [Decision] Route declared≠enforced work by the SEAM, not the layer — a
Seam:line on filing, vertical dispatch by default in the spec lane, automatic parent + sub-issues for spec↔objectui seams, Journey as a filter, bulk retirement per spec family, Console Pin Gate back to required (the maintainer's 「同意」 on the five-line batch, 2026-09-18) #18900(你的判据):每个功能看主流平台有没有这个能力,有就把它做实。分诊按这条判了「做实」(ENFORCE)。Azure API Management、Apigee、ServiceNow 都让 API 所有者给自己的 API 设封面。
两条放在一起,就是:要不要让在 ObjectStack 上做应用的客户,给自己发布的 API 说明书写上自己的标题、简介、联系人、许可证和版本?
三个选项
- A(席位推荐):能写,写了才生效。
- 客户写了哪项,封面就显示哪项。
- 什么都不写,封面和今天一模一样。
- 平台内部的路由版本、运行时版本照旧永远不会跑到封面上。
- B:能写,但版本号不行。 版本永远显示平台 spec 版本,和 8 月的决定一字不差;其余 8 项生效,「版本」这一项删掉,写了会报错。
- C:不能写。 封面永远归平台,9 个设置全部删掉,写了会报错。8 月的决定原样保持。
席位意见:A。 客户给自己的 API 起名字、留联系人是主流平台都有的基本能力,而且不写就完全不变,零风险。8 月那次否掉的是「给路由版本号占用封面」,A 不碰那个。如果你认为封面上的版本必须永远等于平台版本,就选 B。如果你觉得这个能力现在不需要,就选 C,也最省事。
你要做的(一个动作): 回一个字母,A / B / C。
Governing text (verbatim, retrieved by the seat)
- [finding] the served openapi.json overrides the
info.versionthatpackages/specowns, so the published artifact says17.2.0and the served document saysv1#11646, maintainer ruling5405070350: 「theinfoblock returns to being whollypackages/spec-owned」 … 「A (keep the two-meanings split) and C (a config key for a demand nobody expressed) are dead.」 - [Decision] Route declared≠enforced work by the SEAM, not the layer — a
Seam:line on filing, vertical dispatch by default in the spec lane, automatic parent + sub-issues for spec↔objectui seams, Journey as a filter, bulk retirement per spec family, Console Pin Gate back to required (the maintainer's 「同意」 on the five-line batch, 2026-09-18) #18900, maintainer criterion5727134555: 「每族该问的是:主流平台有没有这个能力 —— 有 ⇒ 补消费端(一次做对)」. - rest: the served OpenAPI document's
infoblock comes fromapi.documentation(9 keys) #20294, triage grade5859594397: 「Verdict: ENFORCE, by the maintainer's criterion」.
Evidence
- The dev's measurement on rest: the served OpenAPI document's
infoblock comes fromapi.documentation(9 keys) #20294 (theos-dev-reportcomment): both serving doors ignore all nine authored keys, and the unset cases equal the artifact. - The seat's first analysis, the four facets and the two folded sub-questions (title default, whole-block
contact/license), are on rest: the served OpenAPI document'sinfoblock comes fromapi.documentation(9 keys) #20294, on theRelease:comment of 2026-09-28.
Execution after the answer
- A: re-dispatch rest: the served OpenAPI document's
infoblock comes fromapi.documentation(9 keys) #20294 on the dev's ready resume plan. Its worktree is kept. - B: re-dispatch rest: the served OpenAPI document's
infoblock comes fromapi.documentation(9 keys) #20294 as eight keys ENFORCE plusdocumentation.versionRETIRE. - C: rest: the served OpenAPI document's
infoblock comes fromapi.documentation(9 keys) #20294 is re-graded RETIRE for all nine keys.
Activity
objectstack-fleet commentedon Sep 28, 2026
Ruling: batch #231 item 1 · letter B · maintainer 「同意 B」 2026-09-28T02:58Z
Director seat (objectstack#12708, summon #30 续 2,
session_01AsCNgFBs8HCjwhyHQsFbx3). Provenance: maintainer, live PM chat with the director seat, 2026-09-28, replying to batch #231 (this card, item 1, recommendation B, presented with the full four-axis body); verbatim 「同意 B」.Ruled: B. The eight identity members of
api.documentation—title,description,termsOfService,contact.name/contact.url/contact.email,license.name/license.url— are ENFORCED: an authored value overlays the servedinfoon both doors (/api/v1/openapi.jsonand the environment-scoped door); nothing authored ⇒ the servedinfois byte-identical to the artifact.documentation.versionis RETIRED: the servedinfo.versionstaysSPEC_VERSION, exactly as #11646 (5405070350) ruled, and an authoredversionis refused at publish time by aretiredKey()tombstone whose message names the protocol version as the one source and points an app's own release number todescription. A (all nine overlay, version included) and C (retire all nine) are not taken.Readings that decided it:
packages/spec; the cover's name, contact, terms and licence are the publisher's identity. One truth per field. [finding] the served openapi.json overrides theinfo.versionthatpackages/specowns, so the published artifact says17.2.0and the served document saysv1#11646's motive stands — an integrator must be able to read which protocol version they are talking to — and [Decision] Route declared≠enforced work by the SEAM, not the layer — aSeam:line on filing, vertical dispatch by default in the spec lane, automatic parent + sub-issues for spec↔objectui seams, Journey as a filter, bulk retirement per spec family, Console Pin Gate back to required (the maintainer's 「同意」 on the five-line batch, 2026-09-18) #18900's criterion (5727134555) is applied to the identity keys, where the API-management mainstream lets the owner sign the cover. A would makeinfo.versiona contested field again, in a third meaning; C would tell an app owner the document they publish is always signed ObjectStack.api.documentationin the three repos; the change is small in every direction, so cost did not decide.retiredKey()tombstone (enabled, spec(api): retireapi.responseFormatandapi.documentation.enabled(4 keys); the envelope is fixed andenableOpenApialready decides the document #20295), so a mixed block is the repo's existing pattern, not a new one.Execution parameters (ruled in the same stroke; no further decision card):
infoblock comes fromapi.documentation(9 keys) #20294 is re-dispatched on the dev's kept worktree and resume plan as the seat's own B: eight keys ENFORCE +documentation.versionRETIRE. Lanedomain:spec,priority:p3unchanged; apackages/restsub-issue only if triage's anchoring rule requires one. Clause-② yes (behaviour change on a public document;titlebecomes.optional(),versiontombstoned) ⇒@objectstack/specminor,@objectstack/restper its bump policy;CONTRACT_REVIEW_TIER.titlebecomes.optional()(the materialized default'ObjectStack API'was never served; the artifact's'ObjectStack REST API'is the default).contactandlicensereplace the bundled block whole, never member by member (an MIT name at the Apache URL would be a false statement in a machine-read contract). The overlay lives inregisterOpenApiEndpointsand applies on both doors. The API route version (api.version) and the runtime version never enterinfo.version.api.documentation.version(familyrest-api-documentation); the liveness-ledger rows of the eight keys flip to enforced with the pin as evidence, theversionrow retires with the key.infoon both doors carries them andinfo.versionis stillSPEC_VERSION; (2) nothing authored,documentation: {}, and one key alone ⇒infoequals the artifact except the authored member — the [finding] the served openapi.json overrides theinfo.versionthatpackages/specowns, so the published artifact says17.2.0and the served document saysv1#11646 pin (rest-openapi-route.test.ts) stays as the control; (3) an authoreddocumentation.versionis refused at parse with the tombstone message; (4) an authoredlicensewithouturlserves nourl.info.versionthatpackages/specowns, so the published artifact says17.2.0and the served document saysv1#11646 (zero readers of the servedinfo.versionby value) was measured then and is not reopened.State:
needs-user-decisionremoved here; nopm:*state on this card — it is the ruling carrier, not the work card. #20294:pm:blocked→pm:queue, itsBlocked-by: #20359resolved by this comment (note there in the same stroke). The PR that lands #20294 closes this card too.objectstack-fleet commentedon Sep 28, 2026
Claim: PM loop round 3 (closure claim: this card is closed by #20294's landing PR, as its ruling orders)
Session:
session_01ARcDurZ5j34RdqsGgc4jgHAccount:
os-warren(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-20294-openapi-info-overlayWorktree:
objectstack-issue-20294Domain:
domain:specSeat:
domain:spec#4(seat post #18917)File surface: none of its own. This card is the ruling carrier, not a work card. The diff that executes its ruling B is #20294's, under claim
5876330236on that card, as PR #20512. The ruling says: 「The PR that lands #20294 closes this card too.」 So PR #20512 carriesFixes #20359, and this claim records that the closer owns the card, which is what the closing-target claim guard reads.Container & model: as #20294's claim
5876330236. An at-tier contract review of PR #20512 is owed before enqueue.Clause-②: yes
Thread-read: 5862477514
Serial constraints cleared: as #20294's claim
5876330236.Ruling carried:
5862477514· batch #231 item 1 · letter B · maintainer 「同意 B」.domain:specseat 4 · #18917 ·session_01ARcDurZ5j34RdqsGgc4jgHfeat(spec,rest)!: the served OpenAPI info carries the publisher's api…