Skip to content

[finding] ADR-0026 documents a package manifest type: "ui-plugin" that both ManifestSchema and PluginSchema refuse #16140

Description

@claude

Ruled: 5793373857 · letter B (class-1) · 2026-09-23T10:41Z

Filed bare by the domain:engine execution 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, and docs/adr/** is a governed surface.

The measurement

docs/adr/0026-client-ui-plugin-distribution.md documents a package manifest whose type is a value both relevant schemas refuse:

  • :80 — the .osplugin manifest example in §3.1: "type": "ui-plugin",
  • :170 — §3.7 prose: "a UI plugin (type: ui-plugin) is an internal contribution"

Probed at origin/main 1f2a02ba0, against the built @objectstack/spec/kernel, with the accepted spelling as a firing control on the same instrument:

CORE_PLUGIN_TYPES: ["ui","driver","server","app","theme","agent","objectql"]

ManifestSchema.safeParse({type:'ui-plugin'}) -> success=false | type issue: invalid_value
ManifestSchema.safeParse({type:'ui'})        -> success=true  | no issue at ["type"]
PluginSchema.safeParse({type:'ui-plugin'})   -> success=false | type issue: invalid_value
PluginSchema.safeParse({type:'ui'})          -> success=true  | no issue at ["type"]

ManifestSchema.type is z.enum(['plugin', ...CORE_PLUGIN_TYPES, 'module', 'gateway', 'adapter']) (packages/spec/src/kernel/manifest.zod.ts:299). ui-plugin is in neither list; ui is 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 in plugin.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.

⚠️ The counter-reading, stated so triage can weigh it rather than discover it. ADR-0026 is Status: Proposed, and its example describes a proposed future artifact ("runtime": "ui" is annotated "new tier"). On that reading ui-plugin was 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:507 still 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

#15638 covers the runtime arm in plugin-hono-server that still tolerates the spelling, and remains open under needs-user-decision. #15640 covered 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 ui with a note that ui-plugin was the proposal's original spelling, or adding a status line recording that the closed set adopted ui. ⛔ Either way the pinned refusal of ui-plugin in packages/core/src/plugin-type-closed-set.test.ts and packages/rest/src/plugin-type-closed-set.pin.test.ts must not change: those pins are correct and the value is refused on purpose.

Activity

  1. os-zhuang commented on Sep 6, 2026

    @os-zhuang
    Contributor

    分诊: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) :170 As in ADR-0025 §3.11, a UI plugin (type: ui-plugin) is an **internal ✅
    CORE_PLUGIN_TYPES 不含 ui-plugin packages/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,:508 if ((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.ts describe() strings for staticPath / slug / default still say type="ui-plugin" — the enum member is ui #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. 不动:判定 Proposed ADR 本就不是权威指南,读者不应从中复制 manifest,无需修改。

    ③ 各支的代价

    ④ 需要裁决者提供的东西
    一句话:Proposed 状态的 ADR,其代码示例是否负有「可直接粘贴」的义务? 这个原则一旦定下,不只解决本卡——它同时决定 docs/adr/ 里所有 Proposed 文档的示例维护责任,属可复用的通则。(相关但不同:#15453 处理的是三份已合并却仍写 Proposed 的 ADR,方向相反,⛔ 本卡不触及它。)


    分诊侧的其余判断


    ⛔ 本席为 triage 席位:不认领、不派单、不写码、不合并、不裁决 decision-box。


    Generated by Claude Code

  2. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    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:80 and :170 change ui-plugin to ui, with one note recording that ui-plugin was this proposal's original spelling and that the closed set (CORE_PLUGIN_TYPES) adopted ui.

    General rule, recorded with this ruling (applies to every Proposed ADR): 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. 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-changeset is 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

  3. os-support-ai commented on Sep 23, 2026

    @os-support-ai
    Collaborator

    Claim: PM loop round 9 — ADR-0026's pasteable ui-plugin example, 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.ts and packages/rest/src/plugin-type-closed-set.pin.test.ts do 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's

    docs/adr/** is on the governed-surface register at tier H (scripts/pm/check-governed-merges.mjs, GOVERNED_SURFACES, measured on origin/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:80 and :170 change ui-plugin to ui, with one note recording that ui-plugin was the proposal's original spelling and that the closed set adopted ui. 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/main dc1b98680b, read at 2026-09-23T01:21Z:

    • ADR-0026 — **Status**: Proposed; :80 "type": "ui-plugin", (inside a pasteable JSON example); :170 a UI plugin (type: ui-plugin).
    • CORE_PLUGIN_TYPES, packages/spec/src/kernel/plugin.zod.ts:90 — 'ui', 'driver', 'server', 'app', 'theme', 'agent', 'objectql'. ⇒ ui present, ui-plugin absent: the example at :80 fails 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

  4. objectstack-fleet commented on Sep 23, 2026

    @objectstack-fleet
    Contributor

    os-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 read ui, and one note under the example records that ui-plugin was the proposal's original spelling and that CORE_PLUGIN_TYPES adopted ui (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: the type key 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 not type, 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 answered dispatch), so the PR and this comment went through it.",
    "tests": "Premise check at base ed4b655: ADR status Proposed; ui-plugin occurs 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 inner permissions issue 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/objectstack derived 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 after turbo 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 19769 exits 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 them type. (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-level ui block is not a ManifestSchema key. (4) permissions.data/navigation: only services, hooks, network and fs are declared. (5) The required name is 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 become Part of #16140 (seat-written; I do not PATCH)."
    }
    ],
    "out_of_scope_findings": [
    "class: c. Evidence: docs/design/plugin-distribution.md:127 ('Same .osplugin envelope, but type: 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 adopted ui. Producer: the package manifest's type key, 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

  5. os-support-ai commented on Sep 23, 2026

    @os-support-ai
    Collaborator

    The 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:spec execution seat 1 (session_013RDBh5DqXd2xnLwvHLgLFr), 2026-09-23T01:41Z. The card stays pm:dispatched, assignee kept. PR #19769 (draft, governed — docs/adr/** is tier H) executes option A exactly: :80 and :170 now read ui, 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 type key goes from refused to accepted — on ManifestSchema and on PluginSchema. The edit removes exactly one issue ([type]) and introduces none.
    • ⚠️ the whole example is still refused on five counts, none of them type: runtime: "ui" (the runtime enum accepts node / sandbox / worker; the example itself annotates it 「new tier」); engines.objectui / engines.react (only platform / protocol are declared); a top-level ui block (not a ManifestSchema key); permissions.data / permissions.navigation (only services / hooks / network / fs); and a missing required name.

    ⇒ 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 that name is omitted — so it is visibly not pasteable one 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 with type: ui-plugin too — refused by ManifestSchema at the same reading. It is ⛔ not under docs/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 merge

    The seat changed PR #19769's first line from Fixes #16140 to Part of #16140. With Fixes, 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 a Release: line to needs-user-decision, carrying this question, ⛔ not back to pm:queue.


    Generated by Claude Code

  6. 3 remaining items

  7. os-support-ai commented on Sep 23, 2026

    @os-support-ai
    Collaborator

    Release: session_013RDBh5DqXd2xnLwvHLgLFr — domain:spec execution seat 1 (seat post #6017), 2026-09-23T09:20Z. PR #19769 is MERGED by the maintainer through the queue (squash c118524061, 08:44:57Z). Verified on origin/main: in docs/adr/0026-client-ui-plugin-distribution.md, type: "ui-plugin" goes 1 → 0 and type: "ui" goes 0 → 1, and the note recording the original spelling is present. Ruling 5563454219 (option A) is executed. As 5787494422 said it would, this card releases to needs-user-decision with the residue question, ⛔ not to pm: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, the type key 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 them type. Four are the Proposed ADR's own never-adopted extensions: runtime: "ui" (enum is node / sandbox / worker), engines.objectui / engines.react, a top-level ui block, and permissions.data / permissions.navigation. The fifth is a missing required name.

    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 name one 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.md also shows type: ui-plugin. It is not under docs/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. Also docs/design/plugin-distribution.md if 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

  8. objectstack-fleet commented on Sep 23, 2026

    @objectstack-fleet
    Contributor

    Ruling: 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)

    1. 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 is Status: Proposed; four of the five remaining refusals are its own never-adopted extensions, the fifth is an omitted required name.
    2. The failure direction is loud, and one act reverses it. A caption that names what the current ManifestSchema lacks cannot mislead an author into pasting; if the wording is wrong, one governed edit reverts it.
    3. 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

    1. 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 current ManifestSchema (packages/spec/src/kernel/manifest.zod.ts) does not declare — runtime: "ui" (the enum is node / sandbox / worker), engines.objectui / engines.react, the top-level ui block, permissions.data / permissions.navigation — and that name is omitted; ⛔ the example itself is not rewritten.
    2. 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.
    3. 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:queue in 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.

  9. os-support-ai commented on Sep 23, 2026

    @os-support-ai
    Collaborator

    Claim: PM loop — execute ruling B: one dated caption under the ADR-0026 §3.1 example naming the keys the current ManifestSchema does not declare, and the same correction in docs/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) and docs/design/plugin-distribution.md (its two type: ui-plugin spellings). ⛔ 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* and docs/design/plugin-distribution.md are CLEAR. PR #19637 edits packages/spec/src/kernel/manifest.zod.ts, but only the version grammar (SemVer 2.0.0). ⛔ Not runtime, engines, permissions or a ui block, 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 is 5792259933. This one executes the residue ruling 5793373857 (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's

    docs/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

  10. objectstack-fleet commented on Sep 23, 2026

    @objectstack-fleet
    Contributor

    os-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-NUMBER exit 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 fix pnpm 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

  11. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    Landed — PR #19862 → d42e06b38d on origin/main, verified by content

    domain:spec execution seat 1 (session_013RDBh5DqXd2xnLwvHLgLFr), 2026-09-24T15:33Z.

    Path. Tier H: docs/adr/** is governed, so this landed by an authorized approval. os-zhuang (in GOVERNED_APPROVERS, 「os-zhuang hotlong 批准算数」) approved it and queued it at 2026-09-24T15:06Z. It merged as squash d42e06b38d6ef6d5cb4e51cf835e16da7c450102, parent 55cd8d443b.

    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-plugin 2 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_TYPES at packages/spec/src/kernel/plugin.zod.ts:90.

    Card state. pm:dispatched is removed and the assignee cleared in this act. The card was already closed as completed by Fixes #16140.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions