Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

objectui 配套:#5055 退役 spec 的 WidgetManifest / WidgetSource 后,parity tripwire 按设计打红,packages/types/src/widget.ts 的锚点注释指向不存在的名字 #5213

Closed

Description

@os-support-ai

Moved from objectstack-ai/objectstack#6275 by the repo:objectui PM seat (session session_01RV6yuVCxymHYE16PL9vQkE) under the maintainer's direct-dispatch authorisation, 2026-08-18, verbatim: 「转」.

Reason: file-at-destination. Both halves land in this repo — packages/types/src/__tests__/page-nav-misc-spec-parity.test.ts and packages/types/src/widget.ts. The original body says it plainly: 「framework 仓无法落 objectui 的改动,故立此单」 — it was filed in the platform repo because the fix could not be made there.

pm:on-hold carried over, and its precondition with it: 「framework 侧 PR 合并后才动」. ⚠️ Its restart condition is an upstream merge, so the holder must watch objectstack-ai/objectstack#5055, not a local file.

⚠️ A label did not survive: the original carried target:v17, which does not exist in this repo. ⛔ Not minted. Recorded here in prose — this is a v17 release-board item, and a label-based release-blocker query will no longer find it. Flagging explicitly because that is exactly the kind of silent drop that loses a release blocker.

Original thread has 5 comments; read them there. Bare references rewritten to full cross-repo form.

objectstack-ai/objectstack#5055(ADR-0049 enforce-or-remove)在 framework 侧退役了 @objectstack/spec/ui 的 widget 注册词汇 —— WidgetManifest / WidgetLifecycle / WidgetEvent / WidgetProperty / WidgetSource(含 npm/remote/inline 三分支)。objectui 侧有两处会因此需要跟进,两处都是设计好的 tripwire 在按规格开火,不是附带损伤。

前置:framework 侧 PR 合并后才动;在此之前 objectui 主干是绿的。

1. page-nav-misc-spec-parity.test.ts 会打红(设计如此)

packages/types/src/__tests__/page-nav-misc-spec-parity.test.ts:558-568 断言 spec 仍然拥有这两个名字:

it.each([
  …
  ['WidgetManifest', 'RuntimeWidgetManifest'],
  ['WidgetSource', 'RuntimeWidgetSource'],
])('the spec still owns `%s`, which is why the rename to `%s` happened', (owned) => {
  // The other direction of the tripwire: if the spec RETIRES one of these,
  // the local dialect can take the natural name back. A workaround should not
  // outlive its reason (objectui#3169).
  expect(names, `spec no longer owns '${owned}' — re-run the triage`).toContain(owned);
});

注释本身写明了触发后该做什么:「a workaround should not outlive its reason」—— 重跑三轴分诊。所以这不是「把断言删掉让它绿」,而是要回答改名的理由是否已消失。

两个方向,建议按 objectui#3169 的先例裁:

  • A. 收回自然名:RuntimeWidgetManifest → WidgetManifest、RuntimeWidgetSource → WidgetSource,因为造成改名的碰撞已经不存在了。代价:objectui 侧 breaking(@object-ui/types 的公开导出名),且 RuntimeXxx 前缀在 WidgetRegistry / app-shell / components 的 CHANGELOG 里已经流传开。
  • B. 保留 RuntimeXxx 名,只把这两行从 it.each 移走,并在下面那张 the spec does not own 表里补上说明:名字现在无人拥有,不是「spec 拥有」。这是 objectstack-ai/objectstack#4988 处置 ConflictResolution 裸名时用的形状(「freeing a word is not a reason to spend a second breaking change renaming back」)。

倾向 B,理由与 objectstack-ai/objectstack#4988 一致:释放出来的名字不构成再花一次 breaking 改回去的理由;但两个名字从此无人拥有这一事实必须被断言,否则将来别的域会悄悄捡走它。

⚠️ 无论 A 还是 B,specExportNames() 的反向断言(the spec does not own RuntimeWidgetManifest / RuntimeWidgetSource)都应保留。

2. packages/types/src/widget.ts 的锚点注释指向已删除的名字

两处 JSDoc 把 objectui 自己的运行时类型锚定在 spec 的名字上:

  • :28 —「Renamed off the spec's WidgetManifest name (objectstack#4115): the spec's is the field-widget plugin manifest that sits beside its FieldWidgetProps — { fieldTypes, category, lifecycle: { onMount, onValidate, … }, events, properties, implementation, screenshots, license, aria, performance }」
  • :107 —「Renamed off the spec's WidgetSource name (objectstack#4115)」

那段逐键对照现在描述的是一个不存在的 schema,而它恰恰是 ADR-0033 意义上「AI 作者会当成事实读」的文本。需要改写成历史陈述(「曾经存在,#5055 退役」),并指明今天 objectui 的运行时 manifest 是唯一的 widget 注册契约。

⚠️ 不受影响的一处 —— 不要顺手一起动

packages/fields/src/__tests__/spec-symbol-batch7.test.ts 的 import type { FieldWidgetProps } from '@objectstack/spec/ui' 完好。FieldWidgetPropsSchema 在 objectstack-ai/objectstack#5055 里被刻意保留,正是因为 objectui PR #3289(2026-08-03)给了它一个跨仓编译期消费者:那三条 error 槽位的 pin 是这次保留决定的直接依据。framework 侧新增的 packages/spec/src/ui/widget-i18n-retirement.test.ts 反向钉住了同一个槽位(error 存在、errorMessage 不存在、可选字符串),所以任何会悄悄弄坏 objectui 的改动会先在 framework 打红。

关联:objectstack-ai/objectstack#5055 · objectstack-ai/objectstack#4115 · objectstack-ai/objectstack#4988 · objectui#3161 · objectui#3169 · objectui#3222 · objectui PR #3289

Activity

  1. os-zhuang commented on Aug 19, 2026

    @os-zhuang
    Contributor

    On-hold daily batch (triage seat, round of ~14:47Z fire): the recorded Restart-when (upstream objectstack#5055 merged) is discharged — it closed completed 08-07 via merged PR #6385 (13 retire / 1 keep). But the retirement is not yet in the published spec this repo pins (17.0.0), so the actionable gate is the pin, not the issue. Staying pm:on-hold with the condition updated so the daily batch stops re-firing on the stale line:

    Restart-when: the @objectstack/spec pin resolves a version carrying #5055's WidgetManifest retirements (same pin-bump family as #5233/#5210/#4795/#4676/#4664/#4935 — now seven cards on one bump).


    Generated by Claude Code

  2. added
    domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lane
    on Aug 23, 2026
  3. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    Contributor

    Triage: domain:spec (lane only — pm:on-hold untouched). This is objectui's follow-through on a spec retirement (WidgetManifest / WidgetSource, objectstack#5055) landing in packages/types — contract convergence, so the contract stream.

    Routed via the maintainer direct-dispatch channel, this session, verbatim: 「然后 批 4–5」. PM session session_0124Qg8rLvpXnQDwCmpKUmaJ. objectui three-stream split (maintainer 2026-08-21); not a Routine triage fire — the triage seat may re-grade.


    Generated by Claude Code

  4. self-assigned this
    on Sep 2, 2026
  5. yinlianghui commented on Sep 2, 2026

    @yinlianghui
    Contributor

    Unlock scan → restart hit → dispatched in one pass (spec@objectui seat, session session_01V3hPr7riucnMfhcHY86Msd, 2026-09-02).

    Release double-check, both legs mechanical: ① the newest pm:on-hold transition comment (2026-08-19) conditions on "the @objectstack/spec pin resolves a version carrying #5055's WidgetManifest retirements" — objectui pnpm-lock.yaml on origin/main 67dadd6 resolves @objectstack/spec@17.2.0, whose dist/ui has zero occurrences of WidgetManifestSchema (probe on the published tarball); ② no PR has merged against this card since that comment (closed_by_pull_requests = 0).

    Scope re-verified on the ref, not on the card: half 1 is already done — packages/types/src/__tests__/page-nav-misc-spec-parity.test.ts:652-653 lists WidgetManifest / WidgetSource in the "spec no longer owns" table with the RuntimeXxx names kept (the card's preferred option B, landed with the rc.6 pin bump; reclaim card #4164 closed not-planned 08-17). Half 2 is still open: packages/types/src/widget.ts:30 and :109 still read "Renamed off the spec's WidgetManifest / WidgetSource name (objectstack#4115)" and describe a schema that no longer exists. That JSDoc rewrite is the whole remaining scope.

    State: pm:on-hold → pm:dispatched (skipping the queue stop, the card is claimed in the same pass; label swap and assign done together). Claim follows.


    Generated by Claude Code

  6. yinlianghui commented on Sep 2, 2026

    @yinlianghui
    Contributor

    Claim: PM loop round 1 (spec@objectui, 2026-09-02 shift)
    Session: session_01V3hPr7riucnMfhcHY86Msd
    Branch: claude/issue-5213-widget-ts-spec-anchor-jsdoc
    Worktree: objectui-issue-5213
    Domain: domain:spec
    File surface: packages/types/src/widget.ts (JSDoc only) + one changeset file (stop on breach; explain in the report)
    Container & model: S (text face, not gate-judged ⇒ judgment tier), mode:subagent, model: opus — node scripts/pm/dispatch-gates.mjs --tier packages/types/src/widget.ts (objectstack tree, d63c8a2): "no path-derived mandate … The tier stays the PM's per-card judgment call (floor sonnet · default opus · ceiling fable)"
    Clause-②: no — comment text only; no schema, type member, or accepted document changes
    Serial constraints cleared: in-lane in-flight = none. Cross-lane in-flight PRs touching packages/types: #7240 (crud.ts, disclosure.ts, form.ts + zod mirrors) and #7241 (data-display.ts + zod mirror + tests) — file lists read, neither touches widget.ts; no sibling card's pins assert this file's text. Same-day churn on widget.ts: none.


    Generated by Claude Code

  7. yinlianghui commented on Sep 2, 2026

    @yinlianghui
    Contributor

    Claim (dev seat, os-dev subagent dispatched by the spec@objectui PM seat, round 1)
    Session: session_01V3hPr7riucnMfhcHY86Msd
    Branch: claude/issue-5213-widget-ts-spec-anchor-jsdoc (pushed empty at 67dadd6 before the first edit; work now at 015bec4)
    Worktree: objectui-issue-5213 (from origin/main 67dadd6)
    Assignee field: untouched — the PM owns it; this comment is the identity bit under the shared GitHub identity.

    Scope taken: half 2 only — the two JSDoc anchors in packages/types/src/widget.ts, plus one changeset. Half 1 (the parity test's "spec no longer owns" table) re-verified as already landed on the ref, not re-done.

    Read channel declared: repo-scoped REST is 403 GitHub access is not enabled for this session on this seat, so the card body and all four comments were read through the public-repo embedded-JSON payload route (zero quota); MCP is used for writes only.


    Generated by Claude Code

  8. yinlianghui commented on Sep 2, 2026

    @yinlianghui
    Contributor

    os-dev-report

    {
      "issue": 5213,
      "status": "done",
      "branch": "claude/issue-5213-widget-ts-spec-anchor-jsdoc",
      "pr": "https://github.com/objectstack-ai/objectui/pull/7262",
      "premise_still_valid": true,
      "summary": "Card body integrity OK — it ends with the full 关联 line (objectstack#5055 · #4115 · #4988 · objectui#3161 · #3169 · #3222 · PR #3289), not truncated; 4 comments read, last two are the PM transition note and claim. Zone 2 assumptions 1-4 all confirmed by measurement: parity test already lists WidgetManifest/WidgetSource in the 'spec no longer owns' table at :652-653 with the moved-OUT note at :609 and reverse assertions at :750-751 (half 1 landed, untouched here); widget.ts :30 and :109 still described the retired spec schema in the present tense; installed @objectstack/spec is 17.2.0 with ZERO .d.ts/.js hits for WidgetManifest/WidgetSource; no same-day churn on widget.ts (last touch 03380aa). Deviation from assumption 3, in the harmless direction: the dist grep is not literally empty — WidgetManifestSchema/WidgetSourceSchema survive only inside sourcesContent of dist/ui/index.js.map, which is the retired file's own tombstone comment, and that tombstone plus the D3 SemanticMigration 'ui-widget-i18n-family-retired' and the RETIRED_DEFS_BY_MAJOR 'retired-def:17' entry are quoted in the new JSDoc instead of invented history; the retirement entry's acceptanceCriteria names this exact file as a prescribed response. Half 2 implemented: both blocks rewritten as history, per-key enumeration of the retired schema dropped, inline collision kept in past tense, prefix-by-choice stated with the objectstack#4988 precedent and the objectui#4164 recorded unlock, both pointing at the parity table as the live assertion. No type/member/signature/export/test changed; no new test added (JSDoc-only). File surface held exactly: packages/types/src/widget.ts + one changeset.",
      "tests": "All gates re-run at final commit 015bec4 (tree clean, `git rev-parse --short HEAD` quoted from that run), every heavy step through os-verify-lock.sh slot issue-5213-objectui, each returning `VERDICT command-exit 0`; exit codes captured by redirect-then-capture, never after a pipe. `pnpm --filter @object-ui/types type-check` exit 0 — script is `tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json`, so the test project IS included (not a NOT-MEASURED case). `pnpm exec vitest run packages/types/src/__tests__/page-nav-misc-spec-parity.test.ts --maxWorkers=2` -> 'Test Files 1 passed (1) / Tests 45 passed (45)'. `pnpm exec eslint packages/types/src/widget.ts` exit 0. `pnpm check:control-bytes` -> '✅ check-control-bytes: OK (scanned 5997 tracked text file(s); skipped 85 binary).' `pnpm check:spec-symbols` -> '✅ spec symbol derivation: 1333 files scanned against 4959 spec export names; 16 declared dialects, 0 untriaged collisions in 0 packages.' + '✅ spec alignment claims: 2 declared deliberate copies, 18 unbacked claims in 5 packages.' check-changeset-presence -> '✅ 1 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'; check-changeset-no-major / -overwrite / -fixed all ✅. Emit measurement backing the `patch` (implementation COMMITTED FIRST, absolute-path restore under trap EXIT INT TERM): mutation proved on disk before measuring — old-text hits 2, new-marker hits 0, `git hash-object` == HEAD~1 blob 1db9c9c7; both legs rebuilt from a cleared dist + tsconfig.tsbuildinfo; dist/widget.d.ts bb4f2fd702cac02a… -> db1d5fbd53d305f5… (CHANGED, so the docblock publishes), dist/widget.js a3de34c54213a269… on BOTH sides (byte-identical, nothing runtime moved); restore proved by `git diff HEAD --name-only` empty and working blob hash back to HEAD blob 85dd8a9a. Non-gate note: `pnpm --filter '@object-ui/types^...' build` exits 1 with ERR_PNPM_RECURSIVE_RUN_NO_SCRIPT — that is an EMPTY dependency closure (types is the zero-workspace-dep base package), not a red gate; `pnpm --filter @object-ui/types build` exits 0. Declared narrowing: the repo-wide farm (pnpm lint + the other ~30 check:* scripts) was not run locally; CI owns it. Gate set derived by hand from objectui's own package.json + .github/workflows — objectstack's scripts/pm/dispatch-gates.mjs was deliberately NOT used, it only answers about its own tree.",
      "mcp_calls": "4 — add_issue_comment (claim), create_pull_request, update_pull_request (one cosmetic body fix: escaped backticks in a table cell), add_issue_comment (this report). All card and comment reads went through the zero-quota public-repo embedded-JSON payload route; repo-scoped REST is 403 'GitHub access is not enabled for this session' on this seat (probe run before choosing the channel). No search_issues call was needed — zero out-of-scope findings to dedup.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  9. yinlianghui commented on Sep 2, 2026

    @yinlianghui
    Contributor

    PM verdict: ACCEPT — PR #7262 (spec@objectui seat, session session_01V3hPr7riucnMfhcHY86Msd, reviewed against GitHub, not the report).

    Checklist readings: draft ✓ · base main ✓ · first line Fixes #5213 ✓ · changed files = packages/types/src/widget.ts (comment-only hunks, no member/signature touched) + one @object-ui/types: patch changeset ✓ (emit measured: .d.ts hash changed, .js byte-identical, so patch is the honest declaration) · report comment present with the literal os-dev-report first line ✓ · file surface held exactly as claimed ✓ · Clause-② no, path face not governed ✓ · half 1 verified on the ref and left untouched ✓ · the fenced spec-symbol-batch7.test.ts untouched ✓. Spot-check of the new text: the quoted RETIRED_DEFS_BY_MAJOR / ui-widget-i18n-family-retired provenance comes from the installed 17.2.0 dist (the dev's probe), the objectstack#4988 precedent and objectui#4164 unlock are cited as recorded, and both blocks now defer to the parity table as the live assertion. Deviations: none. Out-of-scope findings: none.

    Landing: farm read by name at 02:07Z — 4 test shards still in_progress, everything else success/skipped. Ready + auto-merge (the merge-queue entry) are armed only after the full farm is green by name, per this seat's rule; next patrol does it.


    Generated by Claude Code

  10. yinlianghui commented on Sep 2, 2026

    @yinlianghui
    Contributor

    Landing (spec@objectui seat): PR #7262 farm read by name at 02:15Z — 30 check runs, all completed, 27 success + 3 skipped, zero red/pending on head 015bec4. Flipped ready and armed auto-merge (the merge-queue entry) at ~02:16Z. Following to MERGED; label sync on the card happens at that reading.


    Generated by Claude Code

  11. yinlianghui commented on Sep 2, 2026

    @yinlianghui
    Contributor

    MERGED — PR #7262 merged: true at 2026-09-02T02:29:28Z; squash commit 64d624d is on origin/main (title carries (#7262)). Both landing readings taken. pm:dispatched removed with the close; domain:spec stays as provenance. Lane hot-file packages/types/src/widget.ts released.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lane

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions