Skip to content

docs(adr-0026): spell the UI plugin package type ui, note the original ui-plugin - #19769

Merged
hotlong merged 1 commit into
mainfrom
claude/issue-16140-adr-0026-ui-plugin-example
Sep 23, 2026
Merged

hotlong merged 1 commit into
mainfrom
claude/issue-16140-adr-0026-ui-plugin-example

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Part of #16140

Clause-②: no

This PR executes ruling 5563454219 on docs/adr/0026-client-ui-plugin-distribution.md and nothing else. The ruling came from the director seat in decision batch #61 (option A); the maintainer's reply, verbatim, was 「同意」.

What changed

  • Section 3.1 manifest example (:80): "type": "ui-plugin" is now "type": "ui".
  • Section 3.7 prose (:170 on base, :176 after the note): type: ui-plugin is now type: ui.
  • One note directly under the example records that ui-plugin was this proposal's original spelling and that the closed set (CORE_PLUGIN_TYPES) adopted ui. The ADR's argument, its Proposed status line and every other line are unchanged.

The diff is 1 file, +8 / -2. Two things are deliberately untouched:

Premise check (base ed4b655e5b)

  • ADR-0026 line 3 reads **Status**: Proposed.
  • ui-plugin occurs exactly twice in the file: at :80, inside the jsonc example, and at :170, in prose.
  • CORE_PLUGIN_TYPES (packages/spec/src/kernel/plugin.zod.ts:90) is ui, driver, server, app, theme, agent, objectql. There is no ui-plugin.

Two of the card's readings have drifted since it was filed. Neither affects the ruling:

  • The ManifestSchema.type enum is now at manifest.zod.ts:430, and ManifestSchema is now a strictObject, which refuses unknown keys.
  • PluginSchema.safeParse({type:'ui'}) is no longer success=true: type: 'ui' now requires staticPath and slug (PLUGIN_UI_REQUIRED_KEY_MISSING). The reading on the type key itself still holds on both schemas.

Proof: the example against the built schema

The instrument is a throwaway probe, not committed. It takes the section 3.1 jsonc block from the committed file at each revision (git show REV:docs/adr/...) and strips the // comments that sit outside strings. It then parses the result with ManifestSchema and PluginSchema from a fresh pnpm --filter @objectstack/spec build of this branch, loaded through the package's exports map (packages/spec/dist/kernel/index.js, not src/). "Before" is base ed4b655e5b and "after" is e968910ad5.

The type key, on both schemas. The before leg is the firing control: the same instrument refuses it.

before  ManifestSchema {type:"ui-plugin"} -> ["type"] invalid_value
        PluginSchema   {type:"ui-plugin"} -> ["type"] invalid_value
after   ManifestSchema {type:"ui"}        -> no issue at ["type"]
        PluginSchema   {type:"ui"}        -> no issue at ["type"]

The example's keys whose values the current schema already accepts (id, version, type, integrity), parsed with ManifestSchema.pick of those keys:

before  success=false | ["type"] invalid_value
after   success=true

The whole example, as pasted, against ManifestSchema:

before  success=false, 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, 5 issues: the same list without ["type"]
removed by the edit: ["type"] invalid_value        introduced by the edit: none

Acceptance notes

  • This edit alone does not meet the ruling's general rule. The rule says any example under docs/adr/** that an author could paste must validate against the current schema. After this edit, ManifestSchema still refuses the section 3.1 example on five counts, and none of them is type:

    • runtime: "ui": PluginRuntimeSchema accepts only node, sandbox or worker. The example itself annotates this value "new tier".
    • engines.objectui and engines.react: PluginEnginesSchema declares only platform and protocol.
    • The top-level ui block is not a ManifestSchema key.
    • permissions.data and permissions.navigation: the structured branch declares only services, hooks, network and fs.
    • name is required by ManifestSchema, and the example never had it.

    The first four are schema extensions the proposal makes and that were never adopted. Correcting them would change what the ADR proposes, which the ruling does not authorise, so this PR leaves them alone and reports them to the seat as an open question.

  • PluginSchema is not the example's schema, because the example is an .osplugin package manifest. PluginSchema is a non-strict z.object and strips the manifest's keys. On the after leg it trades the type refusal for PLUGIN_UI_REQUIRED_KEY_MISSING on staticPath and slug, which are runtime-plugin keys that a package manifest does not carry. This is recorded for completeness and is not a defect in the example.

  • The same spelling survives in prose at docs/design/plugin-distribution.md:127 and :277 (type: ui-plugin). That file is outside this card's one-file write surface, so it is reported to the seat and not changed here.

Changeset

There is no changeset. skip-changeset is the right label, as the ruling says. Measured:

  • 70 non-private package.json manifests scanned; 0 of their files[] entries reach docs/adr/.
  • A string unique to this ADR's example (com.acme.signature-field) has 0 hits across the built @objectstack/spec dist/ and json-schema/. The positive control, PLUGIN_UI_REQUIRED_KEY_MISSING, has 16.

This PR does not write the label.

Gates (at e968910ad5)

node scripts/pm/dispatch-gates.mjs --commands derived 19 commands for this change set. All 19 were run, and each exited 0. check:doc-formula-expressions first stopped at PREREQUISITE NOT MET (exit 3, nothing measured); after building @objectstack/formula and @objectstack/lint it exited 0.

The dispatch-gates --ran reconciliation reads: "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)". Selected verdict lines:

  • check-adr-links: 690 relative link destination(s) under docs/adr/ resolve
  • check-adr-symbol-anchors: 2122 anchors across 140 records resolve
  • check-adr-anchors: OK
  • check:doc-authoring: no growth
  • check-nul-bytes: OK, no raw ASCII control bytes

No package source is touched, so no package build, test or typecheck is owed. The @objectstack/spec build served the proof only. Repo-wide scans such as pnpm lint run in CI.

Governed surface

docs/adr/** is tier H on the governed-surface register. This PR stays draft. It lands only by a human merge through GOVERNED_APPROVERS.

维护者速读(草稿)

改了什么:ADR-0026 §3.1 manifest 示例和 §3.7 正文里的包类型 ui-plugin 改成了 ui;示例下方加了一条注记,说明 ui-plugin 是本提案最初的拼写,闭集 CORE_PLUGIN_TYPES 后来采用的是 ui。只改这一个文件,+8/-2。

为什么改:执行第 61 批裁决的选项 A(您回复「同意」)。原来作者照抄示例时,type: "ui-plugin" 会同时被 ManifestSchema 和 PluginSchema 拒收。

风险与代价(含回滚):纯文档,不发布任何包,运行时零影响;回滚就是 revert 本 PR。有一点需要您知道:改完后 type 已经能通过,但整个示例仍会被 ManifestSchema 拒收 5 处,即 runtime: "ui"、engines.objectui/react、顶层 ui 块、permissions.data/navigation,以及缺少必填的 name。前四处是提案自己提出、至今未被采纳的 schema 扩展。因此光靠本 PR 还满足不了裁决附带的通则「可照抄的示例必须能通过当前 schema」,这一点已作为待决问题交给席位。

席位意见:

你要做的:审阅后合并(这是治理面,需要您本人或 GOVERNED_APPROVERS 批准)。另外请就上面剩下的 5 处拒收定一个方向。


Generated by Claude Code


Generated by Claude Code

…nal `ui-plugin`

The section 3.1 manifest example and the section 3.7 prose spelled the
package type `ui-plugin`, a value both ManifestSchema and PluginSchema
refuse. The closed set (CORE_PLUGIN_TYPES) adopted `ui`. Both occurrences
now read `ui`, and one note under the example records the proposal's
original spelling.

Claude-Session: https://claude.ai/code/session_013RDBh5DqXd2xnLwvHLgLFr
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation labels Sep 23, 2026
@os-support-ai os-support-ai added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 23, 2026 — with Claude

Copy link
Copy Markdown
Collaborator

Contract review

VERDICT: PASS — nothing blocking. Head reviewed: e968910ad5c6e8112d3e6714aadd947e040416ec. Base main (ed4b655e5b).

Reading moment: this record was written at 2026-09-23T01:51Z. A contract-review record binds ONE head and one reading moment.

⚠️ This is the lane's contract-review record for a GOVERNED surface (docs/adr/**, tier H) — ⛔ not a landing authorization. The PR stays draft and lands only by a human merge through GOVERNED_APPROVERS; this seat will ⛔ not ready it, enqueue it or arm auto-merge on it.

Reviewed-by: isolated at-tier subagent dispatched by domain:spec execution seat 1 (session_013RDBh5DqXd2xnLwvHLgLFr), seat post #6017
Implemented-by: claude/issue-16140-adr-0026-ui-plugin-example

Tier — measured by the SEAT from the reviewer's transcript

CONTRACT_REVIEW_TIER on origin/main is claude-fable-5-1. Governing stamps 74 / 74 claude-fable-5-1; dark control empty; the fallback/overload sweep read in context is tool-schema text and repo prose — ⛔ none a notice. ⇒ AT TIER.

What was proven

  • The ruling was executed exactly. One file, +8 / −2: :80 and the §3.7 prose now read ui; one six-line note records the original spelling. ui-plugin still appears twice at head — both inside the note, which is the ruling's own design. **Status**: Proposed and every other line unchanged; both pins byte-identical base → head; [finding] plugin-hono-server still accepts the legacy ui-plugin type that PluginSchema refuses — an unreachable arm under ADR-0049 #15638 untouched, and ⛔ no closing keyword anywhere (the first line reads Part of #16140).
  • Every clause of the note is true — the ADR's first commit already carried ui-plugin ×2 (「originally spelled」), CORE_PLUGIN_TYPES is ui, driver, server, app, theme, agent, objectql (「adopted ui」), and the note's shape matches existing ADR notes.
  • The type key now validates, with the before leg as the firing control: ManifestSchema and PluginSchema both refuse ui-plugin at base and accept ui at head; the { id, version, type, integrity } pick goes success=false → success=true.
  • No changeset is owed: 70 non-private package.json, 0 files[] entries reach docs/adr; the ADR-unique string reads 0 in the built spec against a live positive control.
  • Scope: one file.

The residue — a fact check, reproduced, and ⛔ not a verdict on the ruling

The reviewer reproduced the round's residue exactly: against the built ManifestSchema the whole §3.1 example goes from 6 issues to 5 — removed exactly [type] invalid_value, introduced none — and the five survivors are runtime: "ui", engines.objectui / react, the top-level ui block (ManifestSchema is a strictObject), permissions.data / navigation, and a missing required name, each located in manifest.zod.ts on origin/main. Whether option A is enough under the ruling's general rule is the maintainer's question, put on #16140 at 5787494422.

CI at this head

38 check runs, all completed. The seven required: Lint & Repo Gates, TypeScript Type Check, Test Core (and shards 1–6), Dogfood Regression Gate, Governed Surface Queue Guard success; Build Core and Temporal Conformance skipped by path filter (recorded as skipped, ⛔ not as pass). ⚠️ Check Changeset was red — the gate's own message: 「This PR adds no changeset … apply the 'skip-changeset' label」. Both route-2 discriminators hold (0 .changeset rows in the diff; no files[] reaches the path) and the ruling names skip-changeset as appropriate ⇒ the seat applied skip-changeset in this act; the job re-fires on the labeled event.


Generated by Claude Code

@hotlong
hotlong marked this pull request as ready for review September 23, 2026 08:27
@hotlong
hotlong added this pull request to the merge queue Sep 23, 2026
Merged via the queue into main with commit c118524 Sep 23, 2026
42 of 44 checks passed
@hotlong
hotlong deleted the claude/issue-16140-adr-0026-ui-plugin-example branch September 23, 2026 08:44
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 28, 2026
…, and spell the design doc's UI plugin type `ui` (objectstack-ai#19862)

Fixes objectstack-ai#16140

Clause-②: no

This PR executes ruling `5793373857` (summon 28, class-1 item 2, letter
B, director seat, 2026-09-23T10:41Z) and nothing else. It touches two
files: `docs/adr/0026-client-ui-plugin-distribution.md` and
`docs/design/plugin-distribution.md`.

## What changed

- **ADR-0026, section 3.1.** One dated note sits under the example,
after the existing 2026-09-07 note. It says the example is the
**proposed** shape. It names what the current `ManifestSchema`
(`packages/spec/src/kernel/manifest.zod.ts#ManifestSchema`) refuses in
it: `runtime: "ui"` (the `PluginRuntimeSchema` enum is `node` /
`sandbox` / `worker`), `engines.objectui` and `engines.react`, the
top-level `ui` block, and `permissions.data` and
`permissions.navigation`. It also says `name` is omitted.
- The caption's last sentence makes the ruling's reading of the general
rule visible: an example validates against the current schema, or
carries a caption that names the keys it proposes beyond it. The rule's
recorded text lives in ruling `5563454219`. It is not restated or
rewritten here.
- The example, the 2026-09-07 note and all of the proposal text are
unchanged. The ADR diff is +11 / -0.
- **`docs/design/plugin-distribution.md`.** Its two `type: ui-plugin`
spellings, in section 4.2 and in worked example C of section 10, now
read `type: ui`. One note under section 4.2 records the original
spelling. It copies the shape PR objectstack-ai#19769 (`c118524061`) used on the ADR.
The rest of the prose is unchanged. This file's diff is +8 / -2.

## Measurement: every claim in the caption, taken before it was written

The instrument is a throwaway probe and is not committed. It takes the
section 3.1 jsonc block from the committed file (`git show
REV:docs/adr/0026-client-ui-plugin-distribution.md`) and strips the `//`
comments that sit outside strings. It then parses the result with
`ManifestSchema`. It ran on one tree through two resolution paths, and
they agree line for line:

- `packages/spec/src`, through `tsx`;
- the built `packages/spec/dist/kernel/index.mjs`, which is the
`./kernel` import entry in the package's `exports`.

The spec source is `origin/main` `8cbc3c0084`. This branch changes no
file under `packages/`.

The whole example as written fails against `ManifestSchema`
(`success=false`) with five issues:

```text
path=["name"]         code=invalid_type       expected=string
path=["permissions"]  code=invalid_union
    union-branch[0]   code=invalid_type       expected=array      (the legacy string[] form)
    union-branch[1]   code=unrecognized_keys  keys=["data","navigation"]
path=["engines"]      code=unrecognized_keys  keys=["objectui","react"]
path=["runtime"]      code=invalid_value      values=["node","sandbox","worker"]
path=[]               code=unrecognized_keys  keys=["ui"]
```

**Firing control, on the same instrument.** Remove `runtime`, `engines`,
`ui` and `permissions` from the example and add a `name`, and it parses
with `success=true`. So those five issues are the whole refusal. No
other part of the example (`id`, `version`, `type`, `integrity`) is
refused, and no refusal hides behind another.

**Reading against the ruling's list.** The two sets are the same. Every
item the ruling names is refused, and no refusal falls outside the
ruling's list. One detail differs in kind. `runtime` is a declared key,
and it is refused with `invalid_value` because the value `"ui"` is
outside the enum, not with `unrecognized_keys`. So the caption writes
`runtime: "ui"` and names the enum, as the ruling does. It does not call
`runtime` an undeclared key.

**`runtime`'s enum at source.** `PluginRuntimeSchema = z.enum(['node',
'sandbox', 'worker'])` in `packages/spec/src/kernel/manifest.zod.ts`.
The probe reads `PluginRuntimeSchema.options` as
`["node","sandbox","worker"]`.

The example parses the same way at `8cbc3c0084` and at this branch's
head `e59f601c56`. None of the example's bytes changed.

The design doc's note, measured with the same instrument:

```text
ManifestSchema.pick({type}) {type:"ui-plugin"}  -> ["type"] invalid_value
ManifestSchema.pick({type}) {type:"ui"}         -> success=true
PluginSchema {name:"x", type:"ui-plugin"}       -> ["type"] invalid_value
CORE_PLUGIN_TYPES = ["ui","driver","server","app","theme","agent","objectql"]
```

## Why this closes the card rather than saying `Part of`

The card carries two rulings:

- `5563454219` (batch 61, option A) was executed by PR objectstack-ai#19769, which the
maintainer merged as `c118524061`.
- `5793373857` (letter B) answers the one residue that round released
with (`5787494422` / `5792259933`). All three of its items are in this
diff: the caption, the reading of the rule, and the design doc.

After this lands, the ruling leaves nothing else open on the card.
objectstack-ai#15638, the runtime tolerance arm in `plugin-hono-server`, is a separate
card. It remains open and is not addressed here. The card is
`pm:dispatched`, not `needs-user-decision`, so a merge cannot close a
card that is still waiting for a decision. The merge is also a human act
(tier H), so the card closes only when the maintainer lands the caption.

## Changeset

This PR has no changeset. Measured:

- 70 non-private `package.json` manifests carry 217 `files[]` entries,
and none of them reaches `docs/`. The repo-root `package.json` is
private.
- Strings unique to the two examples, `com.acme.signature-field` and
`fancy gauge`, have 0 hits across the built `packages/spec/dist` and
`packages/spec/json-schema`. The positive control
`PLUGIN_UI_REQUIRED_KEY_MISSING` hits 83 files there.

So the repo's route is the `skip-changeset` label. AGENTS.md (Post-Task
Checklist, step 3) reserves that label for a diff that publishes nothing
from any released package, and ruling `5563454219` named the same route
for the first round. This PR neither adds nor edits a `.changeset/*.md`,
so the route-0 exclusion does not apply. The dispatch forbids this seat
any label write, so the label is **not** applied here. `Check Changeset`
stays red until a seat applies it. It is not a required context.

## Gates (at `e59f601c56`)

`node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--commands` derived 19 commands for this change set: 2 paths against
merge base `8cbc3c008`. All 19 ran, and each exited 0.

`pnpm --filter @objectstack/lint run check:doc-formula-expressions`
first stopped at `PREREQUISITE NOT MET` (exit 3, nothing measured). The
gate printed its fix, `pnpm exec turbo run build
--filter=@objectstack/formula --filter=@objectstack/lint`. That is 4
packages, and it ran under the shared verify lock. After it, the gate
exited 0.

The `--ran` reconciliation reads: "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)".

Selected verdict lines:

- `check-adr-links`: 690 relative link destination(s) under docs/adr/
resolve.
- `check-adr-symbol-anchors`: 2123 anchors across 140 records resolve.
The caption's new anchor
`packages/spec/src/kernel/manifest.zod.ts#ManifestSchema` is one of
them. It is extracted from the ADR at head (2 anchors in the file,
against 1 at base) and resolves as a `declaration`.
- `check:doc-authoring`: no growth.
- `check:nul-bytes`: OK, no raw ASCII control bytes.

This PR touches no package source, so it owes no package test or
typecheck. The spec, formula, sdui-parser and lint builds served two
things only: the doc-formula gate and the dist leg of the probe.
`dispatch-gates` names some families as outside its 19 commands: the
artifact rosters, the wide-population families, the path-scheduled `Test
Core` job and the type-check lanes. CI runs those, and it runs repo-wide
scans such as `pnpm lint`.

## Acceptance notes

- **Placement.** The ruling says "under the section 3.1 example", and
the example already carries one dated note (2026-09-07). The caption
goes directly after that note. Both dated notes now sit under the
example in date order, with no prose between them.
- **The design doc still spells `runtime: 'ui'` / `runtime: ui`**, in
its section 4.2 heading and in worked example C. That is ADR-0026's
proposed tier, and the current `PluginRuntimeSchema` refuses it. It is
left alone for two reasons. The ruling limited 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 caption. Noted, not
filed.
- The two closed-set pins are untouched:
`packages/core/src/plugin-type-closed-set.test.ts` and
`packages/rest/src/plugin-type-closed-set.pin.test.ts`.

## Governed surface

`docs/adr/**` is tier H on the governed-surface register. This PR stays
**draft**. It lands only by the maintainer's hand, or by an authorized
approval from `GOVERNED_APPROVERS`. This seat does not flip it to ready,
queue it or arm auto-merge.

## 维护者速读(草稿)

**改了什么**:ADR-0026 §3.1 的 UI 插件清单示例下面加了一条带日期的说明,写明这是「提议中的形状」。说明点名了当前
`ManifestSchema` 不接受的部分:`runtime: "ui"`(当前只有 `node` / `sandbox` /
`worker`)、`engines.objectui/react`、顶层 `ui`
块、`permissions.data/navigation`,还说明示例缺少必填的
`name`。示例本身和提议正文一字未改。另外,`docs/design/plugin-distribution.md` 里的两处 `type:
ui-plugin` 改成了 `type: ui`,并加了一条注记说明原来的拼写,做法和上一轮改 ADR 时相同。

**为什么改**:执行裁决 `5793373857`(字母 B)。上一轮把 `type` 改对以后,整个示例仍会被 schema 拒收 5
处。裁决的选择是加一行说明,而不是改写示例。

**风险与代价(含回滚)**:纯文档改动,不发布任何包,对运行时零影响。说明里的每一条都先用 schema
实测过,结果与裁决列出的完全一致。回滚方法就是 revert 本 PR。

**席位意见**:

**你要做的**:审阅后合并。ADR 属于治理面,需要您本人合并。另外,`Check Changeset` 要等有人挂上
`skip-changeset` 标签才会变绿;它不是必需检查,不会挡住合并。

---
_Generated by [Claude
Code](https://claude.ai/code/session_013RDBh5DqXd2xnLwvHLgLFr)_

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

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants