Repository navigation
docs(skills): objectstack-api stops teaching an app to mount routes on http.server (#23787) - #23807
Conversation
…n http.server (#23787) Ruling C′ item 2 on #23128 retired the imperative `http.server` mount as an app-author surface. The skill's decision table now points code at a `type: 'flow'` endpoint whose `script` node runs a stack function or whose `connector_action` node calls a declared connector, names the inbound `type: 'api'` flow hook, and states the three cases with no app surface today. The "Code routes" section is deleted; eval 3 expects that answer. ADR-0088 gains an Amended status entry and its `router` row points at it. Claude-Session: https://claude.ai/code/session_01VqGhCg9wdsBXPz54uAEWg7 Co-authored-by: Claude <noreply@anthropic.com>
维护者速读改了什么
为什么改
风险与代价(含回滚)
席位意见
你要做的
席位核对Seat Implemented-by:
Generated by Claude Code |
Contract reviewServed-tier: Reviewed 2026-10-16T04:15Z. Inputs: card #23787 body and all seven comments (6206661348, 6207123004, 6207374288, 6207401165, 6207466146, 6207749987, 6207817517); PR #23807 body, file list and ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
|
Review labels cleared · director seat (summon #43,
Generated by Claude Code |
Fixes #23787
Clause-②: no
What changed
Ruling C′ item 2 on #23128 (record 6142279866, the maintainer's 「同意」) retired the imperative
http.servermount as an app-author surface: an app declaresapis:, computes in a flow, and registers code as a stack function or a connector; thehttp.serverservice itself stays the platform plugins' own door. This PR is the skill half of that item plus the ADR-0088 row the filer added. The spec half is PR #23785 (#23216); none of its files are touched here, and the skill wording follows its retire texts where they say the same thing.skills/objectstack-api/SKILL.mdapis:and a code handler": thehttp.server mount (plugin code)row is replaced by A flow that runs your code — point atype: 'flow'endpoint at a flow whosescriptnode names a stack function (defineStack({ functions })), or whoseconnector_actionnode calls a declared connector (outbound). Theapis:row is unchanged.type: 'api'flow hook (a pointer to objectstack-automation → Inbound webhook (api) triggers, which already teacheshookId/secret), states that an app never mounts onhttp.server(same reasons as PR docs(spec): the routes / App.apis retire text stops sending app authors to an imperative http.server route (ruling C′ item 2) #23785's retire texts: no caller identity, auth gate, rate limit, namespace carve-out or OpenAPI entry), and names the three cases with no app surface today instead of inventing a door.http.server" (26 lines including its leading separator) is deleted, with the deprecated-alias,kernel:listeningand Hono-sealing notes.skills/objectstack-api/evals/endpoints-auth-routes.json, eval id 3. The Stripe prompt is kept (it is the realistic lure for the retired door) and the eval now expects the skill's statement of the gap plus what holds for code:expected_outputrewritten;must_contain=x-objectstack-signature,functions;must_not_contain=http.server,kernel:ready,getService. Chosen over re-targeting at a served case because the eval's job is to catch an authoring AI reaching for the retired door on exactly this prompt; evals 1 and 2 already cover the servedapis:cases.docs/adr/0088-metadata-kind-admission-and-retirement.md: one**Amended**entry on the Status line (2026-10-16, skills(objectstack-api): the "Choosing betweenapis:and a code handler" table and the "Code routes" section still teach app authors to mount onhttp.server, which ruling C′ (#23128) retired as an app-author surface #23787, citing showcase: the "Recalculate Estimate" / "Recalculate Selection" api actions answer 500 — recalc-endpoint.ts calls ctx.ql.update with no execution context, which the security layer refuses as a principal-less write #23128 ruling C′ item 2, record 6142279866), and therouterrow points at it. TherouterKIND's retirement is unchanged; the amendment narrows only the delivered form "imperativehttp.servermounts" to the platform plugins. No other ADR edit..changeset/23787-api-skill-retired-route-door.md:@objectstack/skillspatch withClause-②: no. Measured:skills/**ships throughpackages/skills(files[]=dist,README.md,CHANGELOG.md;scripts/sync-catalog.mjscopiesskills/**intodist/skills/), so the text edit publishes.docs/adr/**ships in no package'sfiles[](every trackedpackage.jsonscanned at b485122: zeroadr/docsentries), so the ADR edit owes nothing.Measurements behind the new text (base b485122)
apis:types:packages/spec/src/api/endpoint.zod.ts:174— onlyobject_operationandflowexecute;script/proxyare refused at publish (endpoint-publish-gate.ts:370-371). The describe text already sends script logic to "a flow whose script node runs your registered function" and outbound calls to "a flow using a declared connector".scriptnode'sconfig.functionresolves throughengine.resolveFunction()todefineStack({ functions })(packages/services/service-automation/src/builtin/screen-nodes.ts:31-33, 409-419;engine.ts:4266-4275;packages/spec/src/stack.zod.ts:992-1047). Atype: 'flow'endpoint runs that flow (packages/runtime/src/endpoint-executor.ts:253-262, 484-585).connector-imap,-mcp,-openapi,-rest,-slack) are outbound only — theyregisterConnector/registerConnectorProviderwith the automation service so a flow'sconnector_actionnode can dispatch to them; imap is a read-only session that registers noconnector_actionhandler. Zero hits forhttp.server,IHttpServeror.post(underpackages/connectors/*/src.packages/triggers/trigger-api/src/api-trigger.tsarmsPOST /api/v1/automation/hooks/:flowName/:hookIdfor atype: 'api'flow; the start node'sconfig.secretis required (engine.ts:10807-10825); it verifies only ObjectStack'sx-objectstack-signaturein the timestamped form through core'sverifyHttpSignature(api-trigger.ts:142-170, 346-348), requires a JSON object body (400 otherwise) and answers 202 queued. It is app-authorable (a flow is app metadata;skills/objectstack-automation/SKILL.md:340-354teaches it), so the skill names it — for a sender that signs with ObjectStack's own scheme.endpoint-executor.tsanswers{ status, body: { success: true, data } }for both executing types (:291,:567-585); there is no streaming path.examples/app-showcasemounts no route handler of its own; its recalc is a declared flow endpoint (src/coverage.ts:133,objectstack.config.ts:259).Three cases with no app surface today — open questions for the maintainer
The seat puts these on the card; they are stated in the skill as gaps, not routed to the retired door.
INVALID_SIGNATUREto any post without a validx-objectstack-signature(api-trigger.ts:321-348), and a flow — whether started by the hook or by atype: 'flow'endpoint — receives the parsed JSON body as its trigger record, never the raw bytes or the request headers (api-trigger.ts:357-366;endpoint-executor.ts:567passesctx.bodytobuildAutomationContext). A stack function therefore cannot verifyStripe-Signature.endpoint-executor.ts:291, 585).http.serveris an HTTP door in any case.skills/**readingsskills/objectstack-api/SKILL.mdskills/objectstack-api/evals/endpoints-auth-routes.jsonskills/*/SKILL.md)node scripts/check-skills-token-ratchet.mjsverdict lines:✓ check-skills-token-ratchet: skills/objectstack-api/SKILL.md is 4754 tokens (ceiling 6314; headroom 1560).·✓ check-skills-token-ratchet: skills/objectstack-api/evals/endpoints-auth-routes.json is 1042 tokens (ceiling 1042; headroom 0).✓ check-skills-token-ratchet: skills/objectstack-api/SKILL.md is 4642 tokens (ceiling 6314; headroom 1672).·✓ check-skills-token-ratchet: skills/objectstack-api/evals/endpoints-auth-routes.json is 1039 tokens (ceiling 1042; headroom 3).No
CEILINGSrow moves. The eval's growth is paid inside the file by content, not re-wrapping (its line count is unchanged; the byte count fell 4165 → 4156).Verification (local, head b4ea190)
Derived after the final commit with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(no paths): 49 commands — the PM's 37 at 46ca793 plus 12 changeset-family gates the new.changeset/*.mdpulls in. Every command was run with its exit code captured before any pipe and reconciled:dispatch-gates --ran→ "49 derived famil(ies) accounted for — 45 run, 4 NOT-MEASURED (4 DERIVED from a recorded exit 3)", exit 0, 0 UNRUN.check-skills-token-ratchet(+--self-test),check:skill-docs,check:adr-anchors,check-adr-links(+--self-test),check-adr-symbol-anchors,check:skill-identifier-liveness,check:skill-frame-sync,check:skill-compatibility,check:role-word,check:doc-authoring,check:pm-skill-id-lint,check:nul-bytes,check:published-files,check-empty-changeset,check-changeset-no-major,check-adr-0087-registration, andcheck:doc-formula-expressions(first exit 3 for an unbuilt@objectstack/lint; rebuilt withpnpm exec turbo run build --filter=@objectstack/formula --filter=@objectstack/lint --concurrency=2underos-verify-lock.sh,VERDICT command-exit 0, 88 s held; rerun exit 0).check:dts-closure,check:dual-build-cjs-loads,check:lean-entry-closure,check:sourcemap-no-sources-content. They read the whole repository'sdist/; a fresh worktree has none, and this diff touches no package, so the whole-repo build is not owed here. They enter the derivation only through ci.yml's Build Core job filter onskills/**, and CI measures them after its full build.Acceptance notes
skills/objectstack-platform/rules/plugin-lifecycle.md:134readsctx.getService('http-server'), the deprecated alias; the api-skill text deleted here recorded that the alias is absent on the provider path that registers no alias. Platform-plugin teaching outside this card's file list.kernel:ready/kernel:listeningmentions inskills/(objectstack-platform, objectstack-i18n) teach plugin lifecycle to platform-plugin authors, the primitive the ruling leaves untouched. Out of scope.endpoint.zod.ts:174-175,openapi-endpoints.ts:218); the skill keeps that spelling at its L154 for consistency with the spec. Not this card.维护者速读(草稿)
改了什么:
objectstack-api技能不再教应用作者把路由挂到http.server上。决策表的「需要代码」一行改为:声明type: 'flow'端点,代码以 stack function(defineStack({ functions }))由 flow 的script节点运行,或以 connector 由connector_action节点调用;新增一句指向type: 'api'入站 webhook;整节「Code routes」删除。eval 3 改为期待这套说法。ADR-0088 状态行加一条 Amended,router行指向它。附@objectstack/skillspatch changeset。为什么改:#23128 裁决 C′ 第 2 条(记录 6142279866)已把
http.server的命令式挂载从应用作者面退役;发布的技能文本和它的 eval 仍在教这扇门,写元数据的 AI 会照表执行。spec 半边在 PR #23785,本 PR 是技能半边加 ADR 行。风险与代价(含回滚):只改文本,运行时零变化;技能行数与 token 都下降(SKILL.md 434→415 行、4754→4642 tokens;eval 1042→1039 tokens,天花板不动)。风险在于三类场景(第三方自带签名的回调、流式响应、平台不说的协议)今天确实没有应用可声明的落点,技能如实写明「没有」而不发明门;若维护者另有裁定,只需改那一句。回滚 = revert 本 PR 一个 commit。
席位意见:(留空)
你要做的:审批 Tier H(
skills/**+docs/adr/**);并回答一个问题 —— 上述三类无落点场景(尤其 Stripe 这类自带签名、需原始请求体的回调)是否要给应用一个声明式入口,还是维持「平台插件自建门」的现状。Generated by Claude Code