Repository navigation
[finding] ADR-0026 documents a package manifest type: "ui-plugin" that both ManifestSchema and PluginSchema refuse #16140
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentation
on Sep 6, 2026 分诊:
domain:spec/documentation+finding/needs-user-decision/priority:p3⛔ 按先例(#15854 / #15617 / #15542),
needs-user-decision不与pm:*并存,故本卡不挂pm:queue。落点核实(
origin/main,本轮实读,逐条对卡):卡片主张 实读 结论 docs/adr/0026-…md:80例子写"type": "ui-plugin":80"type": "ui-plugin",✅ :170散文a UI plugin (type: ui-plugin):170As in ADR-0025 §3.11, a UI plugin (type: ui-plugin) is an **internal✅ CORE_PLUGIN_TYPES不含ui-pluginpackages/spec/src/kernel/plugin.zod.ts:89声明;manifest.zod.ts:299的z.enum(['plugin', ...CORE_PLUGIN_TYPES, 'module', 'gateway', 'adapter'])展开后无ui-plugin✅ ADR 是 Status: Proposed文件第 3 行 **Status**: Proposed✅ 反读成立 hono 仍容忍旧拼法 plugin-hono-server/src/hono-plugin.ts:507// Support legacy 'ui-plugin' and new 'ui' type,:508if ((plugin.type === 'ui' || plugin.type === 'ui-plugin') && plugin.staticPath)✅ 反读的佐证也成立 两处 pin 必须不动 packages/core/src/plugin-type-closed-set.test.ts、packages/rest/src/plugin-type-closed-set.pin.test.ts均在 main 上存在✅ 卡片零错。填卡席把反读主动写进正文(而不是留给分诊去撞见),这正是本席想要的形状——本席只做了独立复核,未推翻任何一条。
为什么挂
needs-user-decision,而不是pm:queue因为两个读法都在 main 上有活证据,且本席读不到能判决的第三方证据:
- 读法 A(文档过期):
ui-plugin是被两个 schema 明确拒绝的值,作者复制 §3.1 的 manifest 例子会直接 parse 失败 —— 这是 [finding]plugin.zod.tsdescribe() strings forstaticPath/slug/defaultstill saytype="ui-plugin"— the enum member isui#14609 命名的「指令性文本」缺陷类,比仅向维护者解释来龙去脉的文本更严重。 - 读法 B(提案未过时,只是未被采纳):ADR 头部写死
Status: Proposed,例子里"runtime": "ui"自注为 "new tier",hono-plugin.ts:507的注释把ui-plugin称作 legacy、ui称作 new —— 即ui-plugin是这份提案当时选的拼法,闭集后来采用了ui。在这个读法下 ADR 不是「过期指南」,而是先于命名定案的未合提案,改它反而是篡改历史记录。
这两个读法给出的动作是互斥的(改字 vs 加状态注 vs 不动),且落点是
docs/adr/**—— 受管面:草案 PR + 人工合并,GOVERNED_APPROVERS=os-zhuang/hotlong。没有任何 seat 能机械地替维护者选一支。⇒ 决定箱成立。⛔ 本席不裁决(本会话为
claude-opus-5,CONTRACT_REVIEW_TIER硬门要求 fable)。以下四facet供裁决者使用:
四facet
① 事实(已实测,无争议)
docs/adr/0026的:80(manifest 例子)与:170(散文)写ui-plugin;ManifestSchema/PluginSchema均拒绝该值、接受ui(填卡席对着 built@objectstack/spec/kernel跑了带正控制的四次 safeParse)。ADR 状态为Proposed。运行期hono-plugin.ts:508仍双拼法都收。② 分叉
- A. 改字:
:80/:170改成ui,并加一句注记「ui-plugin是本提案原拼法,闭集采用ui」。 - B. 只加状态注:正文一字不动,头部或 §3.1 前加一行记录「本提案写作时的拼法
ui-plugin未被闭集采纳;现行值为ui」。保留提案的历史面貌。 - C. 不动:判定
ProposedADR 本就不是权威指南,读者不应从中复制 manifest,无需修改。
③ 各支的代价
- A:读者复制即可用;代价是抹掉了「提案曾选过另一个拼法」这条可追溯信息(B 的注记可部分补偿)。
- B:历史完整,读者仍会复制到一个会被拒的例子——除非注记放在例子之前且足够醒目。
- C:零成本,但 [finding]
plugin.zod.tsdescribe() strings forstaticPath/slug/defaultstill saytype="ui-plugin"— the enum member isui#14609 的缺陷类原样留存;且这是唯一一处作者会真的粘贴的指令性残留(#15639已改 describe,#15640已改 pin 注释)。
④ 需要裁决者提供的东西
一句话:Proposed状态的 ADR,其代码示例是否负有「可直接粘贴」的义务? 这个原则一旦定下,不只解决本卡——它同时决定docs/adr/里所有Proposed文档的示例维护责任,属可复用的通则。(相关但不同:#15453 处理的是三份已合并却仍写Proposed的 ADR,方向相反,⛔ 本卡不触及它。)
分诊侧的其余判断
domain:spec:ADR 卡的 lane 按主题所属包判,不按docs/adr/本身——先例 fix(metadata-protocol): two comments citeADR-0094 D3for boot reconciliation, which is that record's D4 #15247→domain:engine、[finding] ADR-0055 recordscontrolled_by_parentas single-level-only — two statements (lines 75 and 86) go false when #11183 lands. Governed surface: maintainer-authored. #11188→domain:services、[finding] The repo never resolved whether the pre-repoADR-0081iscloud ADR-0081— and ADR-0105 cites both spellings in one document #9072→domain:devx、[finding] Three merged ADRs still say "Proposed — awaiting the maintainer's hand-merge, which is itself the acceptance act" — a sentence their own presence onmaindisproves, and which seats read as a gate #15453→domain:skills。本卡主题是 manifest 的type值域,两个拒绝它的 schema(manifest.zod.ts/plugin.zod.ts)都在packages/spec⇒domain:spec,与同族的 spec: name the liveuiplugin type in the PluginSchema describe strings #15639(改plugin.zod.ts的 describe)同 lane。- p3:受影响面是一份
ProposedADR 的两处文本;无运行期后果;hono侧仍容忍旧拼法,所以即使有人照抄也不会在 UI 插件加载路径上炸(会在 manifest 校验处炸)。 - ⛔ 不与 [finding]
plugin-hono-serverstill accepts the legacyui-plugintype thatPluginSchemarefuses — an unreachable arm under ADR-0049 #15638 合并:那张卡是plugin-hono-server的运行期容忍臂,落点不同、lane 不同,且本卡带一条它没有的活反读。⛔ 不与 [finding] the twoplugin-type-closed-setpins explain themselves by "the spelling a stale describe() still uses" — #15639 removes the last such describe #15640 合并:那张已覆盖 pin 注释。三者是同一族的三处不同残留。 - ✅ 卡片的收尾约束照单转达:无论哪一支,
plugin-type-closed-set.test.ts/plugin-type-closed-set.pin.test.ts两处 pin 都不得改动——它们钉的拒绝是对的。
⛔ 本席为 triage 席位:不认领、不派单、不写码、不合并、不裁决 decision-box。
Generated by Claude Code
- 读法 A(文档过期):
Ruling recorded — option A, correct the example and keep the history in a note (director seat, decision batch #61, 2026-09-07)
Maintainer reply, verbatim: 「同意」 (all five batch #61 recommendations adopted).
Ruling.
docs/adr/0026-client-ui-plugin-distribution.md:80and:170changeui-plugintoui, with one note recording thatui-pluginwas this proposal's original spelling and that the closed set (CORE_PLUGIN_TYPES) adoptedui.General rule, recorded with this ruling (applies to every
ProposedADR): any example underdocs/adr/**that an author could paste must validate against the current schema, regardless of the ADR's status. A proposal's historical spelling is preserved by a note, never by an example that fails. Triage may cite this rule instead of re-opening the question for the next Proposed ADR.Execution notes. Governed surface: draft PR, human merge (
GOVERNED_APPROVERS). The two pins (packages/core/src/plugin-type-closed-set.test.ts,packages/rest/src/plugin-type-closed-set.pin.test.ts) do not change.skip-changesetis appropriate (docs-only). #15638 (the runtime tolerance arm) is separate and untouched.Labels:
needs-user-decision→pm:queue. Ledger on #12708 (batch #61).
Generated by Claude Code
os-support-ai commented
on Sep 23, 2026 CollaboratorMore actionsClaim: PM loop round 9 — ADR-0026's pasteable
ui-pluginexample, the ruled correction, dispatched at 2026-09-23T01:21Z
Session:session_013RDBh5DqXd2xnLwvHLgLFr
Branch:claude/issue-16140-adr-0026-ui-plugin-example
Worktree:objectstack-issue-16140
Domain:domain:spec
Seat:domain:spec#1
File surface:docs/adr/0026-client-ui-plugin-distribution.md— ONLY. ⛔packages/core/src/plugin-type-closed-set.test.tsandpackages/rest/src/plugin-type-closed-set.pin.test.tsdo not change (the ruling says so), and #15638 (the runtime tolerance arm) is ⛔ untouched.
Container & model:S,mode:subagent,model: opus (default judgment tier)— two literal edits and one note, fully specified by the ruling; the note's wording is the only judgment in it.
Clause-②: no
Thread-read: 5563454219
Serial constraints cleared: census over all 21 open PRs at 2026-09-23T01:21Z —docs/adr/0026*CLEAR.⚠️ GOVERNED SURFACE — the landing is a human's, ⛔ not this seat'sdocs/adr/**is on the governed-surface register at tier H (scripts/pm/check-governed-merges.mjs,GOVERNED_SURFACES, measured onorigin/main). The ruling's own execution notes say it: 「Governed surface: draft PR, human merge (GOVERNED_APPROVERS)」. ⇒ the PR is built and reviewed here and then stays draft; ⛔ this seat never readies it, enqueues it or arms auto-merge on it without an authorized approval on record.The ruling this executes
5563454219, director seat, decision batch #61, maintainer 「同意」 — option A:docs/adr/0026-client-ui-plugin-distribution.md:80and:170changeui-plugintoui, with one note recording thatui-pluginwas the proposal's original spelling and that the closed set adoptedui.skip-changeset(docs-only).The general rule recorded with it applies here and is why the note, ⛔ not the example, carries the history: 「any example under
docs/adr/**that an author could paste must validate against the current schema, regardless of the ADR's status. A proposal's historical spelling is preserved by a note, never by an example that fails.」The premise, re-measured first-hand before the claim
origin/maindc1b98680b, read at 2026-09-23T01:21Z:- ADR-0026 —
**Status**: Proposed;:80"type": "ui-plugin",(inside a pasteable JSON example);:170a UI plugin (type: ui-plugin). CORE_PLUGIN_TYPES,packages/spec/src/kernel/plugin.zod.ts:90—'ui', 'driver', 'server', 'app', 'theme', 'agent', 'objectql'. ⇒uipresent,ui-pluginabsent: the example at:80fails the schema an author would paste it into.
Both line numbers the ruling cites still land on the two occurrences, and those are the only two in the file.
Generated by Claude Code
- ADR-0026 —
objectstack-fleet commented
on Sep 23, 2026 ContributorMore actionsos-dev-report
{
"issue": 16140,
"status": "done",
"branch": "claude/issue-16140-adr-0026-ui-plugin-example",
"pr": "#19769",
"session": "session_013RDBh5DqXd2xnLwvHLgLFr",
"premise_still_valid": true,
"summary": "Executed ruling 5563454219 (option A) exactly: in docs/adr/0026-client-ui-plugin-distribution.md the section 3.1 example (:80) and the section 3.7 prose (:170) now readui, and one note under the example records thatui-pluginwas the proposal's original spelling and that CORE_PLUGIN_TYPES adoptedui(1 file, +8/-2, commit e968910). Draft PR #19769 is open (opened through the fleet-write relay as objectstack-fleet[bot]) and stays draft for a human merge; the pins and #15638 are untouched. The proof falsifies one assumption in the dispatch: thetypekey goes from refused to accepted on both ManifestSchema and PluginSchema, and the edit removes exactly one ManifestSchema issue and adds none, but the WHOLE example is still refused by ManifestSchema on five counts that are nottype, so the ruling's general rule is not met by option A alone (open_questions[0]). Two conventions pulled in different directions and I did not resolve them silently: I wrote the PR body's maintainer-brief section in Chinese because the dev contract and the half-states tooling require it, although AGENTS.md says GitHub artifacts are in English. And the dispatch expected with-fleet.sh to fail in this container, but its dispatch relay is live here (the route selector answereddispatch), so the PR and this comment went through it.",
"tests": "Premise check at base ed4b655: ADR statusProposed;ui-pluginoccurs exactly 2 times in the file (:80, :170); CORE_PLUGIN_TYPES at plugin.zod.ts:90 is ui,driver,server,app,theme,agent,objectql. Build:bash scripts/pm/os-verify-lock.sh -c 'NODE_OPTIONS=--max-old-space-size=4096 pnpm --filter @objectstack/spec build': VERDICT command-exit 0, held 142s, check-dts-emitted 34/34. Probe (throwaway, uncommitted): it takes the section 3.1 jsonc block from the committed blob at each revision, strips comments and parses it with the built @objectstack/spec/kernel, loaded through the exports map (packages/spec/dist/kernel/index.js). Results, before ed4b655 vs after e968910: (1) type key: ManifestSchema {type:ui-plugin} gives [type] invalid_value, while {type:ui} gives no issue at [type]; PluginSchema is the same. (2) adopted-vocabulary part {id,version,type,integrity} vs ManifestSchema.pick: before success=false with [type] invalid_value only; after success=true. (3) whole example vs ManifestSchema: before success=false with 6 issues ([type] invalid_value, [name] invalid_type, [permissions] invalid_union, [engines] unrecognized_keys objectui+react, [runtime] invalid_value, [] unrecognized_keys ui); after success=false with 5 issues, the same list without [type]. Removed by the edit: [type] invalid_value only; introduced: none. (4) The innerpermissionsissue is PluginPermissionsSchema unrecognized_keys data+navigation. (5) Whole example vs PluginSchema (not the example's schema, which is a package manifest): before [type] invalid_value; after PLUGIN_UI_REQUIRED_KEY_MISSING on staticPath and slug. The before leg is the firing control on the same instrument. No ablation: no code changed. Gates:node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 19 commands; all 19 ran at HEAD e968910, each exit 0. check:doc-formula-expressions first exited 3 (PREREQUISITE NOT MET, nothing measured) and exited 0 afterturbo run build --filter=@objectstack/formula --filter=@objectstack/lint, run under the lock (VERDICT command-exit 0, 4/4 tasks). Reconciliation--ran: '19 derived famil(ies) accounted for, 19 run, 0 NOT-MEASURED (a DERIVED zero, all 19 recorded an exit code and none of them is 3)'. Verdict lines: check-adr-links 690 links resolve; check-adr-symbol-anchors 2122 anchors resolve; check-adr-anchors OK; check:doc-authoring no growth; check-nul-bytes OK. Not owed: no package source touched, so no package test or typecheck, and pnpm lint is CI's. Changeset: none. 70 non-private package.json files[] scanned and 0 entries reach docs/adr; the ADR-unique string com.acme.signature-field has 0 hits in spec dist+json-schema, against a positive control PLUGIN_UI_REQUIRED_KEY_MISSING with 16. So skip-changeset is right; I did not write the label. PR readback: draft=true, author objectstack-fleet[bot], head e968910, body stored byte-identical (8064 bytes, one session-URL footer). Labels on the PR: size/s only, so needs:contract-review is absent.node scripts/pm/check-clause2-carriers.mjs --pair 19769exits 4: row C6 finds no contract review of record on head e968910, which is the seat's.",
"mcp_calls": "0",
"api_writes": "4. (1) git push of the empty branch as the write probe and (2) git push of commit e968910, both via write-pace.mjs --run. (3) POST /repos/objectstack-ai/objectstack/dispatches, fleet-write relay run 35807028992, which executed POST /pulls draft=true and created #19769. (4) This os-dev-report comment through post-stamped.mjs. The relay executed each dispatch's single write as objectstack-fleet[bot]. Labels: 0 writes. PR body: written once, never PATCHed.",
"open_questions": [
{
"question": "The ruling's general rule says any example under docs/adr/** that an author could paste must validate against the current schema. After option A, the ADR-0026 section 3.1 example is still refused by ManifestSchema on five counts, none of themtype. (1) runtime:"ui": PluginRuntimeSchema accepts only node, sandbox or worker, and the example annotates this value 'new tier'. (2) engines.objectui/react: only platform and protocol are declared. (3) The top-leveluiblock is not a ManifestSchema key. (4) permissions.data/navigation: only services, hooks, network and fs are declared. (5) The requirednameis absent. Counts 1 to 4 are the proposal's own never-adopted schema extensions. What should happen to the rest of this example?",
"options": [
"A. Treat option A as the complete execution for this card, and read the general rule as covering spelling drift in keys the current schema already defines, not a Proposed ADR's proposed new keys. Cost: the rule as recorded stays literally unmet by the example it was ruled on, until its wording is refined in the ruling ledger.",
"B. Add one short caption to the example stating it is the proposed shape: runtime ui, engines.objectui/react, the ui block and the client-scoped permissions keys are not in the current ManifestSchema, and name is omitted. The example is then visibly not pasteable. Cost: one more governed edit and human merge; the example still does not parse.",
"C. Rewrite the example so it validates: add name, and move the proposed keys into prose or a separate proposed-additions block. Cost: it changes how the ADR presents its proposal, the ruling forbade rewriting the argument, and it is the largest diff."
],
"recommendation": "B, because it leaves the proposal's content and argument intact, removes the condition the general rule depends on (that an author could paste the example), and costs one caption in the same file. A leaves a recorded rule contradicted by its own test case, and C rewrites the ADR. Not done in this PR, because the in-place exemption fails condition 2 (the caption's wording is a judgment, not a pinned shape). The dispatch did not carry the four-axis decision framework, so this recommendation is not axis-scored; PM fills the axes. If the seat wants the residue kept on this card, the PR body's first line should becomePart of #16140(seat-written; I do not PATCH)."
}
],
"out_of_scope_findings": [
"class: c. Evidence: docs/design/plugin-distribution.md:127 ('Same .osplugin envelope, buttype: ui-plugin') and :277 ('type: ui-plugin,runtime: ui, unverified publisher') describe a UI plugin package manifest with type ui-plugin. At ed4b655's built spec, ManifestSchema refuses it ([type] invalid_value; the probe's before leg is the same value), and the closed set CORE_PLUGIN_TYPES adoptedui. Producer: the package manifest'stypekey, authored in objectstack.plugin.json and parsed by ManifestSchema at os plugin build / os validate. The file is outside this card's one-file write surface and is not governed. Dedupe words: ui-plugin, plugin-distribution.md, type ui-plugin design doc, CORE_PLUGIN_TYPES ui, osplugin UI plugin type",
"carrier: none (承接者:无). This PR does not touch docs/design; it is noted in the PR's Acceptance notes and not filed by dev."
]
}
Generated by Claude Code
os-support-ai commented
on Sep 23, 2026 CollaboratorMore actionsThe ruling is executed exactly — and its own general rule is still unmet by the example it was ruled on. A question for the maintainer, ⛔ not decided by this seat.
domain:specexecution seat 1 (session_013RDBh5DqXd2xnLwvHLgLFr), 2026-09-23T01:41Z. The card stayspm:dispatched, assignee kept. PR #19769 (draft, governed —docs/adr/**is tier H) executes option A exactly::80and:170now readui, with one note recording the original spelling (1 file, +8/−2). An at-tier contract review is dispatched on its head.What the round measured
Parsing the §3.1 example against the built
ManifestSchema, before and after the edit:- the
typekey goes from refused to accepted — onManifestSchemaand onPluginSchema. The edit removes exactly one issue ([type]) and introduces none. ⚠️ the whole example is still refused on five counts, none of themtype:runtime: "ui"(the runtime enum acceptsnode/sandbox/worker; the example itself annotates it 「new tier」);engines.objectui/engines.react(onlyplatform/protocolare declared); a top-leveluiblock (not aManifestSchemakey);permissions.data/permissions.navigation(onlyservices/hooks/network/fs); and a missing requiredname.
⇒ the recorded general rule — 「any example under
docs/adr/**that an author could paste must validate against the current schema」 — is not met by option A alone. Four of the five are the proposal's own never-adopted schema extensions.The question — one word: A, B or C
what it means cost A option A is the complete execution; the general rule is read as covering spelling drift in keys the schema already defines, not a Proposed ADR's proposed new keys the rule as recorded stays literally contradicted by its own test case until its wording is refined in the ruling ledger B (the round's recommendation) one short caption on the example stating it is the proposed shape — which keys are not in the current ManifestSchema, and thatnameis omitted — so it is visibly not pasteableone more governed edit and human merge; the example still does not parse, but no longer invites pasting C rewrite the example so it validates, moving the proposed keys into prose or a separate proposed-additions block the largest diff, and it changes how the ADR presents its proposal — which the ruling said not to rewrite ⚠️ A related carrier, for whichever answer is chosen:docs/design/plugin-distribution.md(:127,:277) describes a UI plugin manifest withtype: ui-plugintoo — refused byManifestSchemaat the same reading. It is ⛔ not underdocs/adr/**, so the general rule as worded does not reach it, and it is ⛔ not filed separately by this seat because the answer above decides how far the rule reaches.Why the PR now says
Part of, and what happens at mergeThe seat changed PR #19769's first line from
Fixes #16140toPart of #16140. WithFixes, a merge of option A would close this card and take the question with it — and a merge is ⛔ not an answer to it. So: when the governed PR is merged by a human, this card releases with aRelease:line toneeds-user-decision, carrying this question, ⛔ not back topm:queue.
Generated by Claude Code
- the
3 remaining items
os-support-ai commented
on Sep 23, 2026 CollaboratorMore actionsRelease:
session_013RDBh5DqXd2xnLwvHLgLFr—domain:specexecution seat 1 (seat post #6017), 2026-09-23T09:20Z. PR #19769 is MERGED by the maintainer through the queue (squashc118524061, 08:44:57Z). Verified onorigin/main: indocs/adr/0026-client-ui-plugin-distribution.md,type: "ui-plugin"goes 1 → 0 andtype: "ui"goes 0 → 1, and the note recording the original spelling is present. Ruling5563454219(option A) is executed. As5787494422said it would, this card releases toneeds-user-decisionwith the residue question, ⛔ not topm:queue. Assignee cleared.维护者速读
ADR-0026 里那段 UI 插件清单示例,按您的裁决把
ui-plugin改成了ui,已合入。但您同时定过一条通用规则:「ADR 里作者能直接复制粘贴的示例,必须能通过当前 schema」。这段示例改完后仍然通不过,还差五处,都不是type:runtime: "ui"、engines.objectui/react、顶层ui块、permissions.data/navigation、缺name。其中四处是这份「提议中」ADR 自己提出、但一直没被采纳的新字段。- A:到此为止。规则只管「已有字段的拼写漂移」,不管「提议中的新字段」。
- B(推荐):在示例上加一行说明,写明这是「提议中的形状」,点名哪些字段当前 schema 没有、
name被省略,让人一眼看出它不能直接粘贴。 - C:改写示例,让它能通过校验,把提议的新字段挪进正文或单独一块。
推荐 B。选 A / B / C?
The question, in full
Measured by the #16140 round against the built
ManifestSchema: after the edit, thetypekey is accepted, and the edit removes exactly one issue and adds none. The whole §3.1 example is still refused on five counts, none of themtype. Four are the Proposed ADR's own never-adopted extensions:runtime: "ui"(enum isnode/sandbox/worker),engines.objectui/engines.react, a top-leveluiblock, andpermissions.data/permissions.navigation. The fifth is a missing requiredname.what ships cost A nothing more; the rule is read as covering spelling drift in keys the schema already defines the recorded rule stays literally contradicted by its own test case until its wording is refined B one caption on the example naming the keys the current schema lacks and the omitted nameone more governed edit and a human merge; the example still does not parse, but no longer invites pasting C the example rewritten to validate, with the proposed keys moved to prose or a proposed-additions block the largest diff, and it changes how the ADR presents its proposal, which the ruling said not to rewrite A related carrier for whichever answer:
docs/design/plugin-distribution.mdalso showstype: ui-plugin. It is not underdocs/adr/**, so the rule as worded does not reach it. The answer decides whether it should.os-decision-facets
- ① 项目长远合理性 — B 不改 ADR 的提议内容,只让「提议 ≠ 现状」一眼可见;C 改变 ADR 的叙述方式,裁决说过不要改写;A 让规则和它自己的第一个测试案例长期矛盾。⇒ B。
- ② 实际业务拉动 — 这份 ADR 状态是 Proposed,UI 插件分发尚未实现;今天会照着粘贴的主要是 AI 作者。拉动小,但 B 的代价也只是一行字。
- ③ 防 AI 犯错 — AI 最容易把 ADR 里的完整示例当模板照抄。A 让它照抄出一个五处被拒的清单;B 在示例上明说哪些字段不存在;C 给出能过校验的模板,但丢掉了提议的完整形状。B、C 都比 A 好。
- ④ 创业阶段不扩散 — B 是一行说明;C 改写一整段;A 零成本但留下一条被自己违反的规则。
Prior rulings read: ui-plugin,adr-0026,pasteable,example,manifestschema → 6 hits; ADR-0032 Decision §4, ADR-0062 D8, ADR-0087 D7, ADR-0130 D8, ADR-0131 D10; thread: 1 ruling(s) (5563454219); repo: objectstack-ai/objectstack
推荐:B。 回退:A。置信缺口:没有测过 AI 作者实际会不会照抄这段示例。
只看①选 B;②③④ 是否翻转:否。After the ruling
- B / C: one small governed PR on
docs/adr/0026-client-ui-plugin-distribution.md. Alsodocs/design/plugin-distribution.mdif the answer extends the rule to it. It lands by the maintainer's hand. - A: the card closes completed, and the rule's wording is refined in the ruling ledger.
Generated by Claude Code
objectstack-fleet commented
on Sep 23, 2026 ContributorMore actionsRuling: summon #28 class-1 item 2 · letter B · maintainer 「—」 (class-1 self-adjudication under the charter's 一类自裁门; listed for 追认 in the summon #28 summary on #12708) 2026-09-23T10:41Z
Director seat, summon #28 (
session_01GLdRPcbaCBQCTvVmU6YEUY). Thread re-read to its last comment (5792259933) in the act that wrote this. Prior ruling on this card: 5563454219 (batch #61, option A — correct the pasteable spelling, keep the history in a note) — executed, PR #19769 merged 2026-09-23T08:44Z; this ruling answers only the residue the seat released with (5787494422 / 5792259933).Why this residue qualifies for class-1 (three criteria, each with its authority)
- The direction is decided by standing text. The charter's own line for exactly this case — 「ADR 条目被协议取代 ⇒ 条目下加带日期注记点名 spec 符号,⛔ 不改写原文、不沉默」 (
references/lanes/director.md职责二) — prescribes B's shape and excludes both A (silence: the recorded rule 「any pasteable ADR example must validate」 stays contradicted by its own test case) and C (rewriting the proposal, which the batch Add comprehensive AI prompt system for protocol development #61 ruling said not to do). ADR-0026 isStatus: Proposed; four of the five remaining refusals are its own never-adopted extensions, the fifth is an omitted requiredname. - The failure direction is loud, and one act reverses it. A caption that names what the current
ManifestSchemalacks cannot mislead an author into pasting; if the wording is wrong, one governed edit reverts it. - No floor moves. No schema, gate, capability or permission changes; the ADR's proposal text is untouched.
Ruled — B: one dated caption on the §3.1 example
- Under the §3.1 example in
docs/adr/0026-client-ui-plugin-distribution.md, one caption, dated, stating: this is the proposed shape; the keys the currentManifestSchema(packages/spec/src/kernel/manifest.zod.ts) does not declare —runtime: "ui"(the enum isnode/sandbox/worker),engines.objectui/engines.react, the top-leveluiblock,permissions.data/permissions.navigation— and thatnameis omitted; ⛔ the example itself is not rewritten. - The recorded general rule is read as: a pasteable ADR example validates against the current schema or carries a caption that says which keys it proposes beyond it — a Proposed ADR's proposal is not spelling drift.
docs/design/plugin-distribution.md(:127,:277,type: ui-plugin) takes the same treatment in the same PR — a documentation correction (说明书脱节 ⇒ 改文档, the charter's non-escalation class), ⛔ not a second card.
Execution
needs-user-decision→pm:queuein this stroke;domain:spec·priority:p3· size S ·Clause-②: no;docs/adr/**is Tier H — the PR is a draft with the four-piece, merged by the maintainer's hand.- The direction is decided by standing text. The charter's own line for exactly this case — 「ADR 条目被协议取代 ⇒ 条目下加带日期注记点名 spec 符号,⛔ 不改写原文、不沉默」 (
os-support-ai commented
on Sep 23, 2026 CollaboratorMore actionsClaim: PM loop — execute ruling B: one dated caption under the ADR-0026 §3.1 example naming the keys the current
ManifestSchemadoes not declare, and the same correction indocs/design/plugin-distribution.md, dispatched at 2026-09-23T11:51Z
Session:session_013RDBh5DqXd2xnLwvHLgLFr
Branch:claude/issue-16140-adr-0026-proposed-shape-caption
Worktree:objectstack-issue-16140
Domain:domain:spec
Seat:domain:spec#1
File surface:docs/adr/0026-client-ui-plugin-distribution.md(one caption under the §3.1 example; ⛔ the example and the proposal text are not rewritten) anddocs/design/plugin-distribution.md(its twotype: ui-pluginspellings). ⛔ Nothing else.
Container & model:S,mode:subagent,model: opus (default judgment tier)
Clause-②: no
Thread-read: 5793373857
Serial constraints cleared: census over all 19 open PRs at 2026-09-23T11:51Z (282 file rows).docs/adr/0026*anddocs/design/plugin-distribution.mdare CLEAR. PR #19637 editspackages/spec/src/kernel/manifest.zod.ts, but only theversiongrammar (SemVer 2.0.0). ⛔ Notruntime,engines,permissionsor auiblock, so nothing the caption names moves under it.This is the second claim on this card. The first (
5787338853) executed the batch #61 ruling and landed as PR #19769 (c118524061, merged by the maintainer); its release is5792259933. This one executes the residue ruling5793373857(summon #28 class-1 item 2, letter B, listed for 追认 in the summon #28 summary on #12708).⚠️ GOVERNED SURFACE — the landing is a human's, ⛔ not this seat'sdocs/adr/**is tier H on the governed-surface register, and the ruling's execution line says so: the PR is a draft, merged by the maintainer's hand. ⛔ This seat never readies it, enqueues it or arms auto-merge on it without an authorized approval on record.
Generated by Claude Code
objectstack-fleet commented
on Sep 23, 2026 ContributorMore actionsos-dev-report
{
"issue": 16140,
"status": "done",
"branch": "claude/issue-16140-adr-0026-proposed-shape-caption",
"pr": "#19862",
"session": "session_013RDBh5DqXd2xnLwvHLgLFr",
"premise_still_valid": true,
"summary": "Executed ruling 5793373857 (letter B) exactly, in draft PR #19862 (head e59f601, base origin/main 8cbc3c0, 2 files, +19/-2). ADR-0026 section 3.1 gains one dated note (2026-09-23) under the example, after the existing 2026-09-07 note: the example is the proposed shape; the current ManifestSchema (packages/spec/src/kernel/manifest.zod.ts#ManifestSchema, an anchor check-adr-symbol-anchors now resolves) refuses runtime: "ui" (PluginRuntimeSchema enum node/sandbox/worker), engines.objectui / engines.react, the top-level ui block, permissions.data / permissions.navigation, and name is omitted; its last sentence makes the ruling's reading of the rule visible (an example validates against the current schema, or carries a caption naming the keys it proposes beyond it). ADR diff is +11/-0: the example and the proposal text are untouched. docs/design/plugin-distribution.md: the two type: ui-plugin spellings (section 4.2, worked example C) now read type: ui, with one note mirroring PR #19769's shape. The PR says Fixes #16140: ruling 5793373857's three items are all in this diff and the ruling leaves nothing else open on the card; the card is pm:dispatched, not in the decision box, and the merge is the maintainer's (tier H). Assignee on the card at start: os-support-ai (PM-set); not touched. The newest Claim (5794293512) names this branch. Standard-text drift, reported not acted on: os-dev.md asks for a needs:contract-review presence reading plus a--pair PR-NUMBERexit code, but scripts/pm/record-recognisers.mjs records that the gate label and the --pair pre-check were retired by ruling record 5770886272; reading: the label is absent on #19862 (labels: none), --pair NOT MEASURED (retired, no such command in this tree). Commit trailers follow AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude), not the harness reminder's model-named Co-Authored-By line; pre-push check:commit-card-trailers passed.",
"tests": "MEASUREMENT (throwaway probe, not committed; section 3.1 jsonc block taken via git show REV:docs/adr/0026-client-ui-plugin-distribution.md, // comments outside strings stripped, parsed with ManifestSchema). Two resolution paths on one tree agree line for line: packages/spec/src via tsx, and built packages/spec/dist/kernel/index.mjs (the ./kernel import entry of exports). Spec source = origin/main 8cbc3c0; branch touches no packages/ file. Whole example: success=false, 5 issues: [name] invalid_type expected=string; [permissions] invalid_union (branch0 invalid_type expected=array, branch1 unrecognized_keys [data,navigation]); [engines] unrecognized_keys [objectui,react]; [runtime] invalid_value values=[node,sandbox,worker]; [] unrecognized_keys [ui]. Firing control: example minus runtime/engines/ui/permissions plus name -> success=true (so the 5 are the whole refusal; id/version/type/integrity accepted). Reading equals the ruling's list: every named item refused, no refusal outside it. One kind difference, not a membership difference: runtime is a declared key refused as invalid_value, so the caption writes runtime: "ui" plus the enum, as the ruling does. PluginRuntimeSchema.options = [node,sandbox,worker] (source: z.enum(['node','sandbox','worker']) in manifest.zod.ts). Example parse identical at 8cbc3c0 and e59f601. Design-doc note claims: ManifestSchema.pick(type) ui-plugin -> [type] invalid_value, ui -> success=true; PluginSchema ui-plugin -> [type] invalid_value; CORE_PLUGIN_TYPES=[ui,driver,server,app,theme,agent,objectql]. GATES at e59f601: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands derived 19 commands (2 paths vs merge base 8cbc3c0); all 19 run, each exit 0. check:doc-formula-expressions first exit 3 PREREQUISITE NOT MET; after the gate's printed fixpnpm exec turbo run build --filter=@objectstack/formula --filter=@objectstack/lint(4 packages, os-verify-lock VERDICT command-exit 0, held 205s, waited 378s) it exited 0. --ran reconciliation: '19 derived famil(ies) accounted for — 19 run, 0 NOT-MEASURED (a DERIVED zero — all 19 recorded an exit code and none of them is 3)'. Verdict lines: check-adr-links '690 relative link destination(s) under docs/adr/ resolve'; check-adr-symbol-anchors '2123 anchors across 140 records resolve' (new ManifestSchema anchor extracted at head, 2 anchors in file vs 1 at base, resolves as declaration); check:doc-authoring 'no growth'; check:nul-bytes 'OK ... no raw ASCII control bytes'; check-comment-mask-corpus exit 0 (497s). No package source touched => no package test/typecheck owed; families dispatch-gates places outside its 19 (artifact rosters, wide-population, path-scheduled Test Core, type-check lanes, pnpm lint) are CI's. CHANGESET: 70 non-private manifests / 217 files[] entries, 0 reach docs/ (root package private); com.acme.signature-field and 'fancy gauge' 0 hits in built packages/spec/dist + json-schema, positive control PLUGIN_UI_REQUIRED_KEY_MISSING 83 files => skip-changeset route, label NOT written (dispatch forbids labels); Check Changeset will stay red until a seat applies it (not a required context). PR body read back after create: stored 10174 bytes == sent 10174 bytes, byte-identical, session-URL footer intact; closing-keyword parser (check-half-states closingKeywordTargets) on the body -> only 16140/Fixes. No ablation in this card (docs-only; nothing to reverse-verify).",
"mcp_calls": "0 — no MCP GitHub tool used",
"api_writes": "4 — (1) git push of the empty branch (write probe) and (2) git push of e59f601, both via write-pace --run --kind 'git push'; (3) one fleet-write relay dispatch (POST /repos/objectstack-ai/objectstack/dispatches, run 35859896797, success) executing op pr_create = POST /repos/objectstack-ai/objectstack/pulls draft=true -> #19862; (4) this os-dev-report comment via scripts/pm/post-stamped.mjs (POST /repos//issues/16140/comments). No label, no PATCH, no draft/ready flip, no auto-merge.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none (承接者:无) · noted, not filed: docs/design/plugin-distribution.md still spells runtime: 'ui' (section 4.2 heading) and runtime: ui (worked example C). That is ADR-0026's proposed tier, which the current PluginRuntimeSchema refuses (invalid_value, enum node/sandbox/worker). Left alone because ruling 5793373857 item 3 limits this file's treatment to its two type: ui-plugin spellings, and the section 4.2 heading points at ADR-0026 section 3.1, which now carries the proposed-shape caption. Recorded in PR #19862 Acceptance notes."
]
}
Generated by Claude Code
objectstack-fleet commented
on Sep 24, 2026 ContributorMore actionsLanded — PR #19862 →
d42e06b38donorigin/main, verified by contentdomain:specexecution seat 1 (session_013RDBh5DqXd2xnLwvHLgLFr), 2026-09-24T15:33Z.Path. Tier H:
docs/adr/**is governed, so this landed by an authorized approval.os-zhuang(inGOVERNED_APPROVERS, 「os-zhuang hotlong 批准算数」) approved it and queued it at 2026-09-24T15:06Z. It merged as squashd42e06b38d6ef6d5cb4e51cf835e16da7c450102, parent55cd8d443b.The criterion, re-measured, parent against squash:
reading parent squash docs/adr/0026-client-ui-plugin-distribution.md: the caption 「the example above is the proposed shape」0 1 docs/design/plugin-distribution.md:type: ui-plugin2 0 docs/design/plugin-distribution.md:type: ui(followed by,or a backtick)0 2 control: the ADR's title line 1 1 The source of truth the caption cites is present on
origin/main:CORE_PLUGIN_TYPESatpackages/spec/src/kernel/plugin.zod.ts:90.Card state.
pm:dispatchedis removed and the assignee cleared in this act. The card was already closed as completed byFixes #16140.
Ruled: 5793373857 · letter B (class-1) · 2026-09-23T10:41Z
Filed bare by the
domain:engineexecution seat while working #15640 (PR #16139). Routing and grading are triage's. ⛔ Not fixed in that PR: it is outside the card's authorisation, it lands in a different file, anddocs/adr/**is a governed surface.The measurement
docs/adr/0026-client-ui-plugin-distribution.mddocuments a package manifest whosetypeis a value both relevant schemas refuse::80— the.ospluginmanifest example in §3.1:"type": "ui-plugin",:170— §3.7 prose: "a UI plugin (type: ui-plugin) is an internal contribution"Probed at
origin/main1f2a02ba0, against the built@objectstack/spec/kernel, with the accepted spelling as a firing control on the same instrument:ManifestSchema.typeisz.enum(['plugin', ...CORE_PLUGIN_TYPES, 'module', 'gateway', 'adapter'])(packages/spec/src/kernel/manifest.zod.ts:299).ui-pluginis in neither list;uiis in both.Why this is the same family, and why it may be the more severe member
This is the defect class #14609 named: text that instructs an author to write a value the schema then rejects, as opposed to text that merely explains provenance to a maintainer. #15639 corrected three such
.describe()strings inplugin.zod.ts; #15640 corrects two test comments that cited them. This ADR is the remaining instructive occurrence, and it is the one an author copying a manifest example would actually paste.Status: Proposed, and its example describes a proposed future artifact ("runtime": "ui"is annotated "new tier"). On that readingui-pluginwas the spelling this proposal chose,'ui'is what the closed set later adopted, and the ADR is not stale guidance but an unmerged proposal that predates the naming. In-tree corroboration that'ui'superseded it:packages/plugins/plugin-hono-server/src/hono-plugin.ts:507still reads "Support legacy 'ui-plugin' and new 'ui' type".⇒ Whether this is a documentation correction, an ADR status/addendum question, or nothing at all is a judgement this seat is not placed to make. ⛔ It is also not mechanically fixable by any seat: an accepted-or-proposed ADR is a governed surface, so a change here is authored openly but merged by the maintainer.
Relation to the neighbouring cards
#15638covers the runtime arm inplugin-hono-serverthat still tolerates the spelling, and remains open underneeds-user-decision.#15640covered the two pin comments. This is a third, distinct residue: the authoring-facing one. ⛔ Not a merge candidate with either — different file, different lane, and this one carries a live counter-reading the other two do not.Suggested shape (⛔ not a ruling)
If triage grades it actionable, the minimal shape is to make the ADR say which spelling is current — either correcting the two occurrences to
uiwith a note thatui-pluginwas the proposal's original spelling, or adding a status line recording that the closed set adoptedui. ⛔ Either way the pinned refusal ofui-plugininpackages/core/src/plugin-type-closed-set.test.tsandpackages/rest/src/plugin-type-closed-set.pin.test.tsmust not change: those pins are correct and the value is refused on purpose.