Skip to content

feat(plugin-dev)!: retire the stub table — DevPlugin assembles real plugins, empty slots stay empty (ADR-0115) - #4137

Merged
os-zhuang merged 4 commits into
mainfrom
claude/plugin-dev-stub-slots-eval-hqjox1
Jul 30, 2026
Merged

feat(plugin-dev)!: retire the stub table — DevPlugin assembles real plugins, empty slots stay empty (ADR-0115)#4137
os-zhuang merged 4 commits into
mainfrom
claude/plugin-dev-stub-slots-eval-hqjox1

Conversation

@os-zhuang

@os-zhuang os-zhuang commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Closes #4104. 执行 ADR-0115(PR #4103 裁决)的全部实施。按维护者指示("统一 ADR,并继续完成所有开发"),原定两个实施 PR 收敛为这一个 —— #4089 已被 #4082 在源头修掉,PR 边界失去存在理由。

与在途工作的两次合流:本 PR 开着的时候 main 先后合入 #4112#4087:退役 dispatcher 的 /storage bridge)与 #4126#4093 的 A 档子集:安全三件套删除 + 生产护栏)。两者在 plugin-dev 里的改动都落在本 PR 整体删除的代码内,由删除吸收;重叠处采纳 #4126 的已上线语义 —— 逃逸阀名为 OS_ALLOW_DEV_PLUGIN、护栏为模块级 assertNotProduction()、security 槽位缺失时打一条响亮的 "NOT enforced" boot warn(均已移植进终态,并有测试钉住)。#4126 另开的 #4113(runtime 的 /auth mock fallback)是 plugin-dev 之外的最后一个造假者:本 PR 删 auth stub 既不加重也不修复那条路径(两者同等造假、都产不出身份解析器认可的会话),#4113 保持独立跟踪 —— ADR 对账更新第 4 条记录了这一点。

删掉的(A+B+C 三档一次清空)

dev-plugin.ts 的整张 stub 台面消失:

DEV_STUB_FACTORIES / DEV_STUB_SELF_INFO / SHAPELESS_STUB_SELF_INFO / NO_DEV_STUB_SERVICES / 填充循环全部不复存在 —— ADR 终态 grep 为空。

新增的

文档收敛(D7)

packages.mdx 条目、包 README、class doc、services-checklist.mdx 的 i18n 注册表格全部改为装配现实;ADR-0115 增补 post-#4086 对账更新(含 #4126/#4113 的第 4 条事实)。

验证(两次合流后最新)

  • @objectstack/plugin-dev 10/10 · @objectstack/runtime 923/923 · @objectstack/plugin-hono-server 132/132 · @objectstack/core 415/415 · eslint 干净 · tsup(含 DTS)通过
  • 端到端(真实 DevPlugin 装配起 ObjectKernel + dispatcher + Hono):全部退役槽位 getService 抛错(空槽),/api/v1/automation 404,/api/v1/ai/agents 保留 200 {"agents":[]} 礼遇;file-storage 解析为真实 SwappableStorageServicerealtime 解析为真实 InMemoryRealtimeAdapter;kernel 的 CORE_FALLBACK_FACTORIES 预注入不受影响。
  • 新测试钉住:空槽终态(逐槽位点名,防止台面局部复活)、生产护栏 + 逃逸阀、自动接线的诚实降级路径、security 缺失时的响亮 warn。

过程记录(CI 一度静默)

PR 创建后 GitHub 对 mergeable_state: dirty(与 main 冲突)的 PR 静默跳过 pull_request 工作流 —— 空提交与 close/reopen 都无法触发。两次合入 main 解决冲突后恢复正常。

风险与缓冲

对外部 17.x-rc 消费者 breaking:changeset 表即处方;#4082/#4086 起 discovery 已把这些槽位如实广告为 stub/不可服务,实际影响面已核实为仓库内零调用点(search/workflow/ui)或有真实替代(其余)。

🤖 Generated with Claude Code

https://claude.ai/code/session_01BEM82RNKyyyTNPYHK1VJJS

…lugins, empty slots stay empty (ADR-0115, #4104)

Executes ADR-0115 in full. The fill-every-slot stub table is deleted:
the fabricators (data/auth/security.*/ui, plus the ai/automation/
notification trio #4086 left gated-but-registered), the plugin-dev-only
in-memory tier (file-storage/search/realtime/workflow), and the
duplicate metadata copy and createMemory* wrappers (the kernel
pre-injects core's CORE_FALLBACK_FACTORIES for empty core slots, so
behavior is unchanged there).

New: init() refuses NODE_ENV=production (escape hatch
OS_ALLOW_DEV_PLUGIN_IN_PRODUCTION=1, PD #9), and the assembly
auto-wires @objectstack/service-storage (local-disk adapter) and
@objectstack/service-realtime (in-memory adapter) when installed —
the 3b i18n auto-detect pattern, so zero-config dev keeps working
storage/realtime through real implementations.

Docs converge on reality (packages.mdx entry, README, class doc,
services-checklist i18n rows); breaking changeset carries the full
FROM→TO table per retired slot. ADR-0115 gains the post-#4086
reconciliation note (three gated fabricators join Tier A; #4089 closed
at source by #4082; executed as one PR at the maintainer's direction).

Verified: plugin-dev 10/10, runtime 924/924, core 415/415, eslint
clean; end-to-end boot shows retired slots empty (404 / handled=false,
/ai/agents keeps its 200 empty-list courtesy), file-storage resolving
to SwappableStorageService and realtime to InMemoryRealtimeAdapter,
and the kernel's own fallback pre-injection intact.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BEM82RNKyyyTNPYHK1VJJS
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 30, 2026 11:36am

Request Review

…previous head

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BEM82RNKyyyTNPYHK1VJJS
@os-zhuang os-zhuang closed this Jul 30, 2026
@os-zhuang os-zhuang reopened this Jul 30, 2026
claude added 2 commits July 30, 2026 11:17
…0115 wholesale deletion

Main's #4112 (retire the /storage dispatcher bridge, #4087) adjusted the
file-storage stub's self-description and its test; both live inside the
stub table this branch deletes entirely, and the deletion supersedes the
adjustment: the in-memory storage stub is gone and the real
@objectstack/service-storage — which #4112 points at — is auto-wired.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BEM82RNKyyyTNPYHK1VJJS
…e deletion absorbs its subset

Main landed #4126 (the #4093 security-trio + production-guard subset)
while this PR was in flight. Where they overlap, its shipped choices
win: the escape hatch is OS_ALLOW_DEV_PLUGIN, the guard is a
module-level assertNotProduction(), and empty security slots get one
loud 'NOT enforced' boot warn — all ported into this branch's
no-stub end state, which supersedes the rest of its plugin-dev diff
(comments and stub-table edits inside deleted code). ADR-0115's
reconciliation update gains the #4126/#4113 facts; the auth-stub
deletion stands (the runtime /auth mock #4113 tracks is the same
fabrication with or without it).

Verified post-merge: plugin-dev 10/10, runtime 923/923,
plugin-hono-server 132/132, eslint clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BEM82RNKyyyTNPYHK1VJJS
@github-actions github-actions Bot added documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file tests tooling labels Jul 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/plugin-dev.

1 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/plugins/packages.mdx (via @objectstack/plugin-dev)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang marked this pull request as ready for review July 30, 2026 11:59
@os-zhuang
os-zhuang merged commit d0d7464 into main Jul 30, 2026
18 checks passed
@os-zhuang
os-zhuang deleted the claude/plugin-dev-stub-slots-eval-hqjox1 branch July 30, 2026 11:59
os-zhuang pushed a commit that referenced this pull request Jul 30, 2026
…superseded, runtime /ui discovery gate kept

#4137 retired the entire stub table wholesale (Tiers A+B+C), which includes the
data and ui retirements this branch carried incrementally — plugin-dev files
resolve to main's state. What this branch still adds is the runtime seam #4137
deliberately left untouched: discovery's routes.ui/services.ui gate on the
protocol service that actually serves /ui, which matters more post-ADR-0115
because no boot registers a ui-slot occupant at all now.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018UNGqBQcdJ2RYHtWgntJ9B
os-zhuang added a commit that referenced this pull request Jul 30, 2026
… it, not the vestigial ui slot (#4093) (#4146)

domains/ui.ts serves GET /ui/view/:object off the `protocol` service and 503s
without it; the `ui` core-service slot never enters that decision, and nothing
in the platform registers a `ui` service — plugin-dev's shapeless placeholder
was its only occupant ever, and ADR-0115 (#4137) retired it. Gating routes.ui
on slot presence was therefore wrong in both directions: a dev boot with the
placeholder but no protocol advertised a route that could only 503, and every
boot without a placeholder — production always, and all dev boots post-
ADR-0115 — hid a route that serves fine.

routes.ui and services.ui now gate on `typeof protocol?.getUiView ===
'function'` — the domain handler's own guard, byte for byte, the same rule the
mcp advertisement follows (same predicate ⇒ same answer). services.ui reports
the serving implementation (provider metadata-protocol, honoring any
__serviceInfo it declares), and the unavailable message names the actual
remedy — register MetadataPlugin (@objectstack/metadata-protocol) — instead of
svcUnavailable's "install a ui plugin", which names a plugin that does not
exist.

This PR originally also carried plugin-dev's incremental data/ui stub
retirements; ADR-0115 (#4137) retired the whole stub table while the branch
was open, so that half resolved to main's state and the ADR-0076 annotation
now closes out pointing at ADR-0115. The changeset is a runtime-only patch.
The one surviving fabricator is outside plugin-dev: the dispatcher's /auth
mock fallback, #4113.

Tests: with a protocol, /ui is advertised and really serves (getUiView called
with the parsed object/type); without one it is not advertised and the remedy
is named; a ui-slot occupant with no protocol — the old dev-boot shape — stays
un-advertised AND 503s (the slot buys no route); a wrong-shaped protocol
mirrors the domain. runtime 936 / plugin-dev 10 / metadata-protocol 110 pass;
build 71/71; eslint clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation size/xl tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

执行 ADR-0115:退役 plugin-dev 的 stub 台面 —— A 档+护栏 / B 档并 #4089 / C 档 / 文档收敛

2 participants