Skip to content

Commit dfcd664

Browse files
committed
docs(adr-0121): 声明式端点的路由归属与通道分工落档 —— 命名空间制 + actions/apis 按调用方分工 + type: flow 保留 (#5060)
维护者 2026-08-04 三项裁决的持久记录。docs-only:不改任何代码或 schema, 执行体由 #5040 的 E 系列(E7 翻转 PR 落 publish 门)实施。 D1/D2 命名空间制:`ApiEndpointSchema.path` 今天只约束首字符为斜杠,应用元数据 因此可以合法认领 `/api/v1/data/…` 或与另一个已安装包互撞。路径收紧为 `<运行前缀>/apps/<命名空间>/<子路径>`——`apps` 是平台保留的唯一切出段(已实核: domain registry 前缀集与 LEGACY_CHAIN_PREFIXES 中均无 `/apps`),命名空间段派生自 `manifest.namespace`(stack 上唯一同时 URL 安全、带实例内唯一性契约、且已作为每个 对象名前缀被强制的身份键;`App.apis` 已于 spec 17.0.0 退役并留墓碑,声明单位是 stack 不是 app)。撞内建域与跨应用互撞由此在构造上消失,#5040 设计 §1 的保留前缀 pin 清单与 spec/runtime 双端一致性测试整体作废。 D3 通道分工:调用方在平台内(会话、平台方言:UI 按钮、AI/MCP、SDK)→ actions; 调用方在平台外(第三方 webhook、合作方系统)→ apis。判据的维度是调用方在哪, 不是「做什么」——后者会退化成口味之争。 D4-D6 `type: flow` 保留,配三条纪律:判据入两侧 describe(spec 车道执行项)、 同管线红线(flow 端点纯委派 automation 服务,选错通道只是风格问题不是行为问题)、 匿名端点防呆门(`authRequired: false` 必须伴随 `rateLimit`)。签名验证明示为将来 词表候选,不预支。 替代方案按两轴收录 O1(自由路径 + 保留前缀门)与 O3(actions 全面替代 / Dataverse 模式)及否决理由。 编号取 0121:0120 已被开放 PR #5054 占用(origin/main + 开放 PR 双查)。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EYGdmvWP1ieZSLqvAW6uyd
1 parent 94f7b6a commit dfcd664

2 files changed

Lines changed: 391 additions & 0 deletions

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
---
3+
4+
docs(adr-0121): record the 2026-08-04 maintainer ruling on declarative endpoint routing — namespace-scoped paths, the actions/apis channel split, and keeping `type: flow` (#5060).
5+
6+
Three decisions, drafted onto the zero-cost window #4936 opened. v17 hard-rejects a non-empty `apis:` (the loud-reject route ruled on 2026-08-04 00:20Z), so no stack can carry a declarative endpoint into 17.x — which makes this the one moment the path shape can be tightened with no migration to pay.
7+
8+
**Namespace, not arbitrary routes.** `ApiEndpointSchema.path` constrains nothing today but a leading slash, so app metadata can legally claim `/api/v1/data/…` or collide with another installed package. The path narrows to `<prefix>/apps/<namespace>/<subpath>`: `apps` is the platform's one reserved cut-out segment (verified free — it is in neither the domain registry's prefix set nor `LEGACY_CHAIN_PREFIXES`), the namespace segment derives from `manifest.namespace` (the only stack identity key that is URL-safe by charset, carries an instance-uniqueness contract, and is already enforced as every object name's prefix), and the author names only the subpath. Endpoint-vs-builtin and cross-app collisions become structurally impossible rather than list-checked, which retires #5040 design §1's reserved-prefix pin list and its spec/runtime consistency test — a mechanism that needed a test to keep it from rotting.
9+
10+
**actions vs apis, by where the caller is.** Caller inside the platform (session, platform dialect — UI buttons, AI/MCP, SDK) → `actions`; caller outside (third-party webhooks, partner systems) → `apis`. actions is the mature command channel (ADR-0104 params, ADR-0066 D4 gates, #3962 HTTP-semantic failures, `ActionAiSchema`), but structurally cannot serve the three hard traits of an outside caller: the payload shape is theirs (`inputMapping`), there is no platform session (`authRequired: false` + endpoint `rateLimit`), and the URL is a contract written into their system (stable + OpenAPI).
11+
12+
**`type: flow` stays**, with three disciplines: the split criterion goes into both schemas' `describe()` (spec-lane item), flow endpoints purely delegate to the automation service so picking the wrong channel is a style question and never a behavior question, and `authRequired: false` must declare `rateLimit` or publish rejects. Signature verification is named a future vocabulary candidate and deliberately not promised — adding keys no executor consumes is the ADR-0078 shape this ADR exists to avoid.
13+
14+
Alternatives recorded with the two-axis analysis: O1 (free paths + a reserved-prefix gate) is rejected because it compensates at the consumer for a producer-side problem and forces every author to learn which prefixes the platform happens to occupy; O3 (actions replaces apis / the Dataverse single-channel model) is rejected because it drives third-party webhook reception out of metadata and into ungoverned handler code.
15+
16+
Documentation only; releases nothing. The executable half lands via #5040's E-series (E7 carries the publish gates).

0 commit comments

Comments
 (0)