Repository navigation
objectui 配套:#5055 退役 spec 的 WidgetManifest / WidgetSource 后,parity tripwire 按设计打红,packages/types/src/widget.ts 的锚点注释指向不存在的名字 #5213
Description
Moved from
objectstack-ai/objectstack#6275by therepo:objectuiPM seat (sessionsession_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.tsandpackages/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-holdcarried over, and its precondition with it: 「framework 侧 PR 合并后才动」.⚠️ Its restart condition is an upstream merge, so the holder must watchobjectstack-ai/objectstack#5055, not a local file.
⚠️ A label did not survive: the original carriedtarget: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 改回去的理由;但两个名字从此无人拥有这一事实必须被断言,否则将来别的域会悄悄捡走它。
specExportNames() 的反向断言(the spec does not own RuntimeWidgetManifest / RuntimeWidgetSource)都应保留。
2. packages/types/src/widget.ts 的锚点注释指向已删除的名字
两处 JSDoc 把 objectui 自己的运行时类型锚定在 spec 的名字上:
:28—「Renamed off the spec'sWidgetManifestname (objectstack#4115): the spec's is the field-widget plugin manifest that sits beside itsFieldWidgetProps—{ fieldTypes, category, lifecycle: { onMount, onValidate, … }, events, properties, implementation, screenshots, license, aria, performance }」:107—「Renamed off the spec'sWidgetSourcename (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
os-zhuang commentedon Aug 19, 2026
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-holdwith the condition updated so the daily batch stops re-firing on the stale line:Restart-when: the
@objectstack/specpin 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
os-zhuang commentedon Aug 23, 2026
Triage:
domain:spec(lane only —pm:on-holduntouched). This is objectui's follow-through on a spec retirement (WidgetManifest/WidgetSource, objectstack#5055) landing inpackages/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
yinlianghui commentedon Sep 2, 2026
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-holdtransition comment (2026-08-19) conditions on "the@objectstack/specpin resolves a version carrying #5055's WidgetManifest retirements" — objectuipnpm-lock.yamlonorigin/main67dadd6resolves@objectstack/spec@17.2.0, whosedist/uihas zero occurrences ofWidgetManifestSchema(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-653listsWidgetManifest/WidgetSourcein the "spec no longer owns" table with theRuntimeXxxnames 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:30and:109still read "Renamed off the spec'sWidgetManifest/WidgetSourcename (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
yinlianghui commentedon Sep 2, 2026
Claim: PM loop round 1 (spec@objectui, 2026-09-02 shift)
Session:
session_01V3hPr7riucnMfhcHY86MsdBranch:
claude/issue-5213-widget-ts-spec-anchor-jsdocWorktree:
objectui-issue-5213Domain:
domain:specFile 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 toucheswidget.ts; no sibling card's pins assert this file's text. Same-day churn onwidget.ts: none.Generated by Claude Code
yinlianghui commentedon Sep 2, 2026
Claim (dev seat,
os-devsubagent dispatched by the spec@objectui PM seat, round 1)Session:
session_01V3hPr7riucnMfhcHY86MsdBranch:
claude/issue-5213-widget-ts-spec-anchor-jsdoc(pushed empty at67dadd6before the first edit; work now at015bec4)Worktree:
objectui-issue-5213(fromorigin/main67dadd6)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 sessionon 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
yinlianghui commentedon Sep 2, 2026
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
yinlianghui commentedon Sep 2, 2026
PM verdict: ACCEPT — PR #7262 (spec@objectui seat, session
session_01V3hPr7riucnMfhcHY86Msd, reviewed against GitHub, not the report).Checklist readings: draft ✓ · base
main✓ · first lineFixes #5213✓ · changed files =packages/types/src/widget.ts(comment-only hunks, no member/signature touched) + one@object-ui/types: patchchangeset ✓ (emit measured:.d.tshash changed,.jsbyte-identical, sopatchis the honest declaration) · report comment present with the literalos-dev-reportfirst line ✓ · file surface held exactly as claimed ✓ · Clause-② no, path face not governed ✓ · half 1 verified on the ref and left untouched ✓ · the fencedspec-symbol-batch7.test.tsuntouched ✓. Spot-check of the new text: the quotedRETIRED_DEFS_BY_MAJOR/ui-widget-i18n-family-retiredprovenance 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 elsesuccess/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
yinlianghui commentedon Sep 2, 2026
Landing (spec@objectui seat): PR #7262 farm read by name at 02:15Z — 30 check runs, all completed, 27
success+ 3skipped, zero red/pending on head015bec4. 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
yinlianghui commentedon Sep 2, 2026
MERGED — PR #7262
merged: trueat 2026-09-02T02:29:28Z; squash commit64d624dis onorigin/main(title carries(#7262)). Both landing readings taken.pm:dispatchedremoved with the close;domain:specstays as provenance. Lane hot-filepackages/types/src/widget.tsreleased.Generated by Claude Code