Repository navigation
finding(sdui-parser): this copy declares a binding: 'field' arm with zero writers on both sides of the port — objectui is retiring its producer-face half, and nothing propagates that here #16583
Description
Activity
分诊 ·
domain:devx/priority:p3/pm:queue/type: Task—— 并补上卡自己点名未做的那次测量分诊席,session
session_01SwJQDFKe8tVit3BXQ9EfR5。本卡此前零标签 ⇒ 无车道无状态,不在任何队列。归位。车道
domain:devx:车道表该行逐字列了packages/sdui-parser。查表所得。⭐ 补测:本仓的 writer 轴 = 0,带起火控制项
卡明确声明它只测了本仓的声明,没测本仓的 writer,并要求接手者先在这边跑一遍。我跑了(
origin/main@77971021):binding: 'field' 于 packages/ apps/ examples/ → 0 控制项 binding: 'object' 同一形状同一范围 → 2(compile.test.ts、type-attribute-collision.test.ts) 卡点名的三处声明仍在:index.ts 1、types.ts 2⇒ 判别式有效,零是读数。 本仓这一侧的前提与 objectui 侧一致:
'field'臂在本仓也零 writer。⚠️ 但第二根轴我没能测到,如实说明我试着用
=== 'field'找本仓的消费者,拿到 11 个文件的命中——那个查询是错的:它匹配任何地方的'field'字符串比较(cel-to-filter、sharing-rule-service、autonumber-format、approvals…),与 sdui-parser 的 binding kind 无关。⇒ ⛔ 我不把那个数写成消费者计数。消费者轴仍然是未测量的。 一个用错查询产出的数字,比没有数字更坏。
📌 承接者要答的就是这一问,而且要带控制项:本仓有没有任何东西读 sdui-parser 的binding/kind并对'field'分支做事。⚠️ #12858 记过「zero in-repo pull today」,但卡自己说 re-measure rather than inherit —— 照办。定级与方向
p3:observation-class,零 writer,消费者轴未测,今天没有任何东西损坏。
方向:objectui#6950 是维护者采纳的裁定(director 决裁批 #69,「其他同意」),按 ADR-0049 以零 writer 退役该臂。本仓同臂、同理由 ⇒ 跟随退役。⛔ 但两条前置:
- 先答消费者轴。若本仓有
'field'的读取分支 ⇒ 停下来在卡上报,前提两侧不同,答案可能也不同。 - ⛔ 不要断言哪一份是上游。 卡有意不主张方向,我也不主张。已知的只有:两仓都有
packages/sdui-parser,且 objectui 跑check:upstream-port-parity⇒ 某个机制让两份保持同步,而那个机制的主人才决定退役要不要传播。⚠️ 认领时先弄清那条闸的方向,再决定本仓这一改是跟随还是领先——领先会让 parity 门在对面变红。
边界
- ⛔ 不要与 [finding] the two sdui-parser copies also diverge on the manifest-generation guard (assertFullyLoaded / RegistryConfigLike.lazy) — unrecorded on #12810, zero in-repo pull today #12858 合并(
pm:on-hold,同族不同键:manifest 生成守卫的assertFullyLoaded/RegistryConfigLike.lazy)。 - 📎 Port the union-arm
type-mismatchcheck into the hoistedsdui-parser— the half of the lockstep debt that CHANGES what this copy accepts and rejects #12814 / The hoisted@objectstack/sdui-parserneeds theinert-expressiondiagnostic in lockstep with objectui, or the save gate and the renderer speak different dialects #12719 已关,是先例:本副本 accept/reject 行为的变更各自单独立卡处理 ⇒ 本卡照此,⛔ 不搭车。 - 📎 objectui 侧的 reader-face 残余由 objectui#8315 承接;本卡只管本仓。
⛔ 分诊席边界照旧:不认领、不派发、不写码、不合并。
Generated by Claude Code
- 先答消费者轴。若本仓有
os-try-charles commented
on Sep 16, 2026 CollaboratorMore actionsPM loop round 13 —
domain:devx执行席认领本卡。Claim: PM loop round 13 Session: `session_017ef78bLdybu3AffehKkhfk` Branch: `claude/issue-16583-sdui-field-arm-consumer-axis` Worktree: `objectstack-issue-16583` Domain: `domain:devx` File surface: `packages/sdui-parser/` (stop on breach; explain in the report) Container & model: `M`, `mode:subagent`, `model: opus` Clause-②: no Thread-read: 5576301530 Serial constraints cleared: 14 个 open PR 的 files 逐个读过,⛔ 无一碰 `packages/sdui-parser/**`(发火对照:同一命令在 #18319 上读出 92 个文件 ⇒ 读法有效)派发前的读数 —— ⭐ 三条腿:打印那一行、给它一个必中的对照、写明哪棵树哪个 revision
树与 revision:
objectstack-ai/objectstackorigin/main=1e496f9796126b0398c026c96fb8d240f1982e91,读数时刻 2026-09-16T21:16Z。git show origin/main:packages/sdui-parser/src/index.ts | grep -n "binding?:" 81: binding?: 'object' | 'field'; git show origin/main:packages/sdui-parser/src/types.ts | grep -n "binding?:|kind: 'object' | 'field'" 84: binding?: 'object' | 'field'; 107: bindings: Array<{ tag: string; input: string; kind: 'object' | 'field'; value: unknown }>;⇒ 卡面点名的三处声明当刻仍在(卡面写的是
:81/:84/:107,与今天一致)。⚠️ 这条"写明树与 revision"的纪律是本轮花代价学来的,记在这里给承接者:本席上一轮用一棵树的 grep 判定一句引文"不存在于文件",并据此指控同事编造引用 —— 而那句话在共享检出的b48abc48a上逐字为真,只是被8c657f7dd重写了。共享检出实测落后origin/main155 个提交(本席此前整班都在说 119,那也是记忆里的数)。⇒ 一棵陈旧的树会返回真实、逐字、带行号、且能通过字符串对照,却对现行条款为假的引文。(这三个提交号与那个 155 都是本席在 2026-09-16T21:16Z 同一次git show/git rev-list --count里读到的。)派发口径(分诊
5576301530的两条前置,原样带走)- ⭐ 第一交付物是回答"消费者轴",⛔ 不是退役那个臂。 本仓有没有任何东西读
sdui-parser的binding/kind并对'field'分支做事?必须带控制项。
⚠️ 分诊自己在这条上翻过车并如实记了:它用=== 'field'查到 11 个文件,那个查询是错的 —— 它匹配任何地方的'field'字符串比较(cel-to-filter、sharing-rule-service、autonumber-format、approvals…),与 sdui-parser 的 binding kind 无关。⇒ 它没有把那个数写成消费者计数,原话:「一个用错查询产出的数字,比没有数字更坏」。⛔ 别重蹈。 - 若本仓存在
'field'的读取分支 ⇒ 停下来在卡上报,⛔ 不要继续退役 —— 两侧前提不同,答案可能也不同。 - ⛔ 不要断言哪一份是上游。 已知的只有:两仓都有
packages/sdui-parser,且 objectui 跑check:upstream-port-parity⇒ 某个机制让两份同步。⚠️ 先弄清那条闸的方向,再决定本仓这一改是跟随还是领先 —— 领先会让 parity 门在对面变红。 - writer 轴:分诊 2026-09-07 在
77971021上测得本仓'field'writer = 0(控制项binding: 'object'= 2)。⚠️ 卡面自己说 re-measure rather than inherit ⇒ 在今天的树上重测,⛔ 不继承那个数。 - ⛔ 不与 [finding] the two sdui-parser copies also diverge on the manifest-generation guard (assertFullyLoaded / RegistryConfigLike.lazy) — unrecorded on #12810, zero in-repo pull today #12858 合并(
pm:on-hold,同族不同键);📎 Port the union-armtype-mismatchcheck into the hoistedsdui-parser— the half of the lockstep debt that CHANGES what this copy accepts and rejects #12814 / The hoisted@objectstack/sdui-parserneeds theinert-expressiondiagnostic in lockstep with objectui, or the save gate and the renderer speak different dialects #12719 是先例:本副本的 accept/reject 行为变更各自单独立卡,⛔ 不搭车;📎 objectui 侧的 reader-face 残余由 objectui#8315 承接,本卡只管本仓。
⛔ 本席不写代码、不裁上下游方向、不裁那个臂该不该退役。
Generated by Claude Code
- ⭐ 第一交付物是回答"消费者轴",⛔ 不是退役那个臂。 本仓有没有任何东西读
os-try-charles commented
on Sep 16, 2026 CollaboratorMore actionsos-dev-report
Reported by the os-dev seat, session
session_017ef78bLdybu3AffehKkhfk, on branchclaude/issue-16583-sdui-field-arm-consumer-axis(PR #18537).{ "issue": 16583, "status": "done", "branch": "claude/issue-16583-sdui-field-arm-consumer-axis", "pr": "https://github.com/objectstack-ai/objectstack/pull/18537", "premise_still_valid": true, "summary": "DELIVERABLE 1 (the consumer axis) is the headline and is answered with controls: NOTHING in this repository reads sdui-parser's `binding` / `bindings[].kind`, so the count of things doing something on the `'field'` branch is ZERO. Deliverable 2 (writer axis) re-measured on today's tree, not inherited: 0, control 2. Deliverable 3 (gate direction) is ANSWERED rather than left unmeasured, and the card's premise about WHICH gate was wrong: objectui's `check:upstream-port-parity` pins objectstack TOOLING SCRIPTS ported into objectui and its roster contains zero sdui-parser entries, so nothing here can red it. The parser copies are kept in step by THIS repo's `check:sdui-lockstep`, which vendors a one-sided record of objectui and compares only the parse.ts grammar-region blob, the diagnostic-code set and the pin -- the `binding` declarations are on none of the three. And objectui has ALREADY landed both halves of the retirement, so this change is provably FOLLOWING, never leading. All three gating conditions of the dispatch therefore cleared, and the arm is retired on all three declarations with a both-direction pin. The card's three declarations were all present at the branch point exactly as filed.", "consumer_axis": { "answer": "0 consumers. Nothing outside packages/sdui-parser reads `binding` or `bindings[].kind`, and nothing anywhere branches on either arm.", "reading_tree": "objectstack-ai/objectstack @ 1e496f9796126b0398c026c96fb8d240f1982e91 (the branch point; origin/main at dispatch time)", "query_shape_naive_reproduced": "git grep -lF \"=== 'field'\" -- '*.ts' '*.tsx' '*.mts' '*.mjs' -> 11 files (reproduces triage's number exactly; triage was right to refuse to report it)", "query_shape_stage_1": "git grep -lE \"@objectstack/sdui-parser|packages/sdui-parser/(dist|src)\" -- '*.ts' '*.tsx' '*.mts' '*.mjs' '*.js' '*.cjs' -> 14 files. Bounded structurally: the package publishes exactly one entry point (`exports` has only \".\"), so an importer is the ONLY way to reach its binding vocabulary.", "query_shape_stage_2": "git grep -nE \"\\\\.bindings\\\\b|\\\\.binding\\\\b|\\\\bbinding\\\\??:|\\\\bkind\\\\b *[:=]{1,3} *'(object|field)'\" -- $(the 14 stage-1 files) packages/sdui-parser/src -> 12 lines, every one inside packages/sdui-parser/src", "proof_it_separates": "NEGATIVE CONTROL: comm -12 of the naive 11-file set and the stage-1 14-file set is EMPTY (intersection size 0). Not one of cel-to-filter, sharing-rule-service, autonumber-format, plugin-approvals, team-graph, protocol.ts, unique-scope-install-gate, check-i18n-bundles.mjs or the three test files can reach this parser at all. A second, independent leg: the file set of `git grep -lE \"\\\\.bindings\\\\b\" -- ... ':!packages/sdui-parser'` (knex SQL bindings, logger bindings, module bindings) also intersects stage-1 in 0 files. POSITIVE CONTROL: the stage-2 query DOES match the genuine reads it must -- packages/sdui-parser/src/codegen.ts:151 (`i.binding`), src/validate.ts:82-83 (`kind: input.binding`), src/index.ts:108. So it separates 'reads sdui-parser's binding kind' from 'any 'field' string comparison' in both directions.", "the_one_real_importer": "packages/lint/src/validate-jsx-pages.ts:62 -- `const { diagnostics } = opts.manifest ? compile(source, opts.manifest) : parseJsx(source);`. It destructures `{ diagnostics }` only and never touches `bindings`. The other 11 stage-1 members are the package itself or PROSE: a `.describe()` string in packages/spec/src/ui/page.zod.ts:901, a file PATH string in packages/runtime/src/dispatcher-error-vocabulary.ts:1312, and gate/self-test rosters in scripts/.", "branch_count_either_arm": "0. `git grep -nE \"(binding|kind)[^a-zA-Z0-9_]*(===|!==|==|!=)[^a-zA-Z0-9_]*'(field|object)'\"` returns 24 lines repo-wide and NONE of their files is in the stage-1 set." }, "writer_axis_remeasured_today": { "reading_tree": "objectstack-ai/objectstack @ 1e496f9796126b0398c026c96fb8d240f1982e91 -- re-measured, NOT inherited from the 2026-09-07 reading on 77971021", "binding_field_writers": 0, "control_binding_object_writers": 2, "control_sites": [ "git show 1e496f9796:packages/sdui-parser/src/__tests__/compile.test.ts line 15", "git show 1e496f9796:packages/sdui-parser/src/__tests__/type-attribute-collision.test.ts line 23" ], "query": "git grep -nE \"binding: *'field'|binding: *\\\"field\\\"|\\\"binding\\\": *\\\"field\\\"\" -- . (and the same with 'object' as the control)", "third_reading_new_this_round": "The tracked repo-root sdui.manifest.json -- the ONLY manifest this repository produces, serialized from objectui's live ComponentRegistry at the pinned sha -- carries ZERO `binding` keys of ANY spelling: 0 across 339 inputs / 57 components (input key histogram: name 339, type 339, required 38, description 160, enum 54). So not even the surviving 'object' arm has a production writer here; the 2 controls are both test fixtures. This confirms the card's 'dead on both axes' hypothesis and strengthens it." }, "gate_direction_answered": { "verdict": "ANSWERED, not unmeasured -- and the card's premise about WHICH gate was wrong.", "objectui_upstream_port_parity": "git show cfcc17d9dd04ebb80c092cacb4f4034425f51b29:scripts/check-upstream-port-parity.mjs (objectstack-ai/objectui, branch main, committed 2026-09-14T11:40:39+00:00) -- its header states it pins 'the ported objectstack tooling in this tree'. Its roster, git show cfcc17d9dd:scripts/upstream-port-pin.json, lists scripts/pm/check-half-states.mjs et al. and contains ZERO occurrences of 'sdui-parser' (grep -c = 0). Its direction is objectstack-as-upstream, objectui-as-ported-copy -- the OPPOSITE relationship to the parser. Nothing in this change can red it.", "the_gate_that_actually_covers_the_parser": "THIS repo's check:sdui-lockstep. git show 1e496f9796:scripts/check-sdui-lockstep.mjs -- it vendors a ONE-SIDED record of objectui's copy (packages/sdui-parser/objectui-lockstep.json) and checks this tree against it, so this repo is the FOLLOWER for what it covers. But its judge() compares exactly three things: record.recordedAgainstPin vs the live .objectui-sha; ours.region.blob vs record.grammarRegion.blob (the ported grammar region of parse.ts only); and the diagnostic-code SETS. The binding declarations live in types.ts and index.ts and are on NONE of the three -- outside its field of view in both directions. CONFIRMED EMPIRICALLY, not just read: the gate runs GREEN on my diff ('OK -- this copy is byte-identical to objectui@53ded82bf7a4 over 214 grammar line(s) [blob 0131f27cf86d] and agrees on all 24 diagnostic code(s)').", "objectui_is_already_ahead": "git show cfcc17d9dd04ebb80c092cacb4f4034425f51b29:packages/sdui-parser/src/index.ts line 120 reads `binding?: 'object';`; types.ts line 143 reads `binding?: 'object';`; types.ts line 192 reads `kind: 'object';`. Both objectui PR #8297 (the ruling's named coordinate) and objectui#8315 (the two-face residue) have LANDED. So this change is categorically FOLLOWING, and cannot be leading.", "objectui_measured_this_repo_itself": "git show cfcc17d9dd:packages/sdui-parser/src/types.ts, in the docblock on ManifestInput.binding: \"`binding: 'field'` has zero writers here and zero in the objectstack copy of this package (measured 2026-09-09 on both heads, each with a firing `binding: 'object'` control)\". My independent re-measure on 1e496f9796 agrees with their objectstack-side number.", "caveat": "The objectui reading is taken at cfcc17d9dd on branch main of a read-only clone at /home/user/objectstack-ai/objectui that this session did not create and did not fetch. cfcc17d9dd is dated 2026-09-14, two days before today, so it is NOT necessarily objectui's live tip. Every objectui claim above is scoped to that rev." }, "tests": "ALL AT HEAD 3a3a42c72 (working tree clean, `git status --porcelain` empty at the time of each run).\n\n[1] Package suite + typecheck, under the shared lock:\n OS_VERIFY_LOCK_SLOT=issue-16583 bash scripts/pm/os-verify-lock.sh -c '... pnpm --filter @objectstack/sdui-parser test && pnpm --filter @objectstack/sdui-parser typecheck'\n -> Test Files 8 passed (8) / Tests 142 passed (142); typecheck clean.\n -> os-verify-lock: VERDICT command-exit 0 (held 5s, waited 0s).\n\n[2] The pin is in the tsc program, PROVEN, not assumed (AGENTS.md phantom-check clause):\n pnpm --filter @objectstack/sdui-parser exec tsc --noEmit --listFiles -> EXIT=0, and\n grep -c 'binding-field-retired.test.ts' over the --listFiles output = 1 (8 __tests__ entries total).\n packages/sdui-parser/tsconfig.json has include ['src/**/*'] and no test exclusion, so the\n @ts-expect-error directives are real checks. They are also NEEDED at HEAD -- an unneeded one\n would be ts(2578) and the run would not be EXIT=0.\n\n[3] REVERSE VERIFICATION -- run from the COMMITTED state, both legs, all three faces.\n Method for each leg: mutate on disk; prove the mutation landed by anchor grep -c counts AND by\n git hash-object differing from the HEAD blob (an empty hash is read as FAILURE, not as nothing\n to compare); run tsc; restore with `git checkout HEAD -- PATH` (never the bare two-argument form with no ref);\n prove restoration by blob-hash equality AND an empty `git diff HEAD`, never by a cleanup exit code.\n Both scripts carry trap RESTORE EXIT INT TERM with absolute paths seeded from\n REPO_ROOT=$(git rev-parse --show-toplevel). No build or dist is involved: the pin imports\n '../types.js' and '../index.js' as RELATIVE sources inside the same package, so nothing resolves\n through dist and ablation-dist-preflight does not apply. Expected direction was declared before\n running: TURNS RED. Observed: turns red.\n\n Leg A -- widen types.ts (faces 2 and 3):\n HEAD blob = 3a7fc45dac0de5fda3cdca300b60e4c1b0f9c290\n post-mutation anchors: wide binding = 1, wide kind = 1, narrow binding = 0\n mutated blob = 26288c715e292bb2b474a80e91344fba1c0bd21c (differs -> not a no-op)\n MUTATED tsc EXIT=1:\n src/__tests__/binding-field-retired.test.ts(56,5): error TS2578: Unused '@ts-expect-error' directive.\n src/__tests__/binding-field-retired.test.ts(68,7): error TS2578: Unused '@ts-expect-error' directive.\n restored blob = 3a7fc45dac0de5fda3cdca300b60e4c1b0f9c290 (equal to HEAD); git diff HEAD empty\n RESTORED tsc EXIT=0\n\n Leg B -- widen index.ts (face 1). Run because leg A fired only 2 of 3 directives, correctly:\n face 1 lives in index.ts, which leg A does not touch, so its pin stayed needed.\n HEAD blob = 97b94de7642345393189fb75614b73cfc20e3207\n post-mutation anchors: narrow = 0, wide = 1\n mutated blob = 2716c592aa4aa85dc90b9533dfa3ddd945b303c4 (differs -> not a no-op)\n MUTATED tsc EXIT=1:\n src/__tests__/binding-field-retired.test.ts(45,7): error TS2578: Unused '@ts-expect-error' directive.\n restored blob = 97b94de7642345393189fb75614b73cfc20e3207 (equal to HEAD); git diff HEAD empty\n RESTORED tsc EXIT=0\n\n Three faces, three directives, each firing ONLY when its own declaration is widened. The pin is\n not one blanket assertion that would survive two of the three being reverted.\n\n[4] The narrowing reaches the PUBLISHED d.ts (the package publishes dist/):\n pnpm --filter @objectstack/sdui-parser build -> DTS Build success, and the package's own\n check-dts-emitted.mjs post-step passed. In dist/index.d.ts: `binding?: 'object';` at 112 and 456,\n `kind: 'object';` at 145, and ZERO occurrences of the wide spelling.\n\n[5] Repo-wide lint, run in full rather than narrowed:\n pnpm lint (= eslint . --no-inline-config) -> EXIT=0. No narrowing was declared because none\n was needed. A targeted eslint --format json over the 3 changed .ts files also read 0 errors /\n 0 warnings across 3 files.\n\n[6] GATE FAMILIES -- derived from the diff, not from the dispatch word:\n node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack\n (no paths passed; the script took the change set itself: 4 paths vs merge base 1e496f979,\n three-dot semantics). It derived 61 commands. Reconciled afterwards with\n --ran FILE, each line recorded as 'COMMAND :: exit CODE':\n 61 derived, 56 RUN GREEN (exit 0), 5 NOT MEASURED (exit 3), 0 UNRUN.\n Named greens that matter here:\n pnpm check:sdui-lockstep exit 0 -- 'OK -- this copy is byte-identical to\n objectui@53ded82bf7a4 over 214 grammar line(s) [blob\n 0131f27cf86d] and agrees on all 24 diagnostic code(s)'\n check-adr-0087-registration exit 0 -- accepted the disposition:\n '1 declared-breaking changeset(s), each carrying an\n ADR-0087 disposition ... not-required (no-migration-prescription)'\n check-empty-changeset exit 0 -- '1 declaring changeset(s) added'\n check-changeset-no-major exit 0\n pnpm check:nul-bytes exit 0 -- 8745 text files, no raw ASCII control bytes\n pnpm check:published-files exit 0 -- incl. 'none narrows its resolvable surface\n against the merge base without a minor changeset'\n pnpm check:type-check-coverage exit 0\n pnpm check:test-source-alias exit 0\n pnpm check:undeclared-dep-imports exit 0\n NOT MEASURED (exit 3 = the gate refusing its own prerequisite; read as neither pass nor fail):\n pnpm check:dts-closure reason: PREREQUISITE NOT MET -- reads built output,\n pnpm check:dual-build-cjs-loads 96+ workspace packages have no dist/.\n pnpm check:lean-entry-closure Each needs the WHOLE-workspace closure build\n pnpm check:sourcemap-no-sources-content (turbo run build --filter='./packages/*' ...),\n pnpm check:type-check-debt which is CI's run, not this card's: my diff is\n type-only inside one package whose workspace\n dependency closure is EMPTY (sdui-parser declares\n no workspace deps), so scope clause (1) is vacuous\n here. I DID build sdui-parser itself -- see [4].\n check:pm-dispatch-gates was NOT derived for this card (0 hits in the derived command list), so\n its ~1730-case battery was not owed and was not run.\n\n[7] NOT run and not owed: scope clause (5) (a gate/tooling script's own suite) -- this diff edits no\n gate or tooling script. Integration/spawn tiers -- not applicable, this is not packages/cli.", "mcp_calls": "0 - zero MCP GitHub tool calls of any kind, read or write. Every GitHub read and write went through the REST proxy with curl and $GITHUB_TOKEN. (One non-GitHub MCP call was made: Claude_Code_Remote add_repo, read access, to learn how objectui could be read; it attached nothing and wrote nothing.)", "api_writes": "3 - (1) git push -u origin claude/issue-16583-sdui-field-arm-consumer-axis (the empty-branch write-route probe), then one more push carrying the commit; counted as the one push budget line. (2) POST /repos/objectstack-ai/objectstack/pulls (draft). (3) POST /repos/objectstack-ai/objectstack/issues/16583/comments (this report). NO label write was spent: no conditional label is owed (Clause-②: no, so no needs:contract-review; a changeset is present, so no skip-changeset) and the repo's own additive automation had already written documentation, size/m, tests, tooling -- read back and recorded, nothing stripped.", "open_questions": [ { "question": "The dispatch scoped this card's file face to packages/sdui-parser/. The changeset at .changeset/16583-sdui-parser-binding-field-arm-retired.md is outside that face. Declaring the crossing rather than landing it silently.", "options": [ "A - keep it: a published package ('files': ['dist','README.md','CHANGELOG.md']) moves a declared TypeScript surface, so the standard clause makes a changeset mandatory and check:empty-changeset / check:adr-0087-registration both read it", "B - drop it and label skip-changeset: refused, because something published DID move -- the narrowed types are in dist/index.d.ts at lines 112, 145 and 456" ], "recommendation": "A, because the standard clause outranks the dispatch word on conflict and the changeset is a mandatory companion rather than scope creep. Flagged here per the same clause." }, { "question": "The retirement's governing ADR number is deliberately NOT cited in the code comments, and that is a judgement worth a reviewer's eye. objectui cites 'ADR-0049 enforce-or-remove'. This repo's docs/adr/0049-no-unenforced-security-properties.md is scoped to SECURITY/access-control properties in packages/spec; `binding` is neither a security property nor a spec key. Its 2026-09-04 amendment does record that 'the repo cites this ADR as the enforce-or-remove policy for spec-property retirement generally', but it also says 'No new scope is claimed for this ADR by this amendment'.", "options": [ "A - cite no bare ADR number here; report objectui's citation as theirs, and ground the change in the ruling plus the measurements (what I did)", "B - cite ADR-0049 directly in the objectstack comments, which Prime Directive #13 resolves against THIS repo's registry -- i.e. against the security ADR" ], "recommendation": "A, because a bare number resolves against this repo's registry and would attach a security-property ADR to a non-security, non-spec TypeScript interface member. If a maintainer prefers the citation, it is a one-line comment edit; I did not want to make that call silently." } ], "out_of_scope_findings": [ "noted, not filed: packages/sdui-parser/objectui-lockstep.json records objectui at 53ded82bf7a4 (2026-09-05), which PREDATES both halves of the objectui retirement (landed by cfcc17d9dd, 2026-09-14). This is not drift a gate can see -- check:sdui-lockstep is green and the record is refreshed by `pnpm gen:sdui-lockstep` at pin-bump time, which this change does not do. Carrier: whoever next bumps .objectui-sha. Recorded in the PR's Acceptance notes.", "noted, not filed: docs/adr/0080-ai-authored-ui-jsx-source.md's status line still says the save-time authoritative compile-to-compiledTree pipeline and registry-manifest prop/binding validation are NOT wired, and that the parser is consumed only by @objectstack/lint. Both readings are still ACCURATE at 1e496f9796 (I re-measured the second: one real importer). Not a defect, not a contract violation, not a metadata-authoring trap -- it is the true reason the binding vocabulary has no production writer on EITHER arm. Recorded because it is the standing explanation, not because anything is wrong. Carrier: none today.", "noted, not filed: the repo-root sdui.manifest.json carries zero `binding` keys across all 339 inputs, so even the surviving 'object' arm has no production writer in this repository -- its only two writers are test fixtures. Not filed as a card: it is an observation about objectui's registry contents at the pinned sha, not a defect here, and ADR-0080's own status line above already explains it. Carrier: whoever wires the save-time binding validation ADR-0080 still lists as unwired." ] }
Generated by Claude Code
os-try-charles commented
on Sep 16, 2026 CollaboratorMore actions落地记录 —— PR #18537 已合并;卡由
Fixes自动关闭,残留状态同笔清掉domain:devx执行席(座位贴 #6023,sessionsession_017ef78bLdybu3AffehKkhfk,round 13)。两读:⛔ 不看
merged布尔,⛔ 不看 head-sha 祖先性读 读到什么 读数一 队列分支 gh-readonly-queue/main/pr-18537-…已消失(1 → 0);时间线merged+removed_from_merge_queue读数二 重新 fetch 的 origin/main内容六条腿全部翻转,见下 落地提交 2e0401a8fe5f26acae852cc728ef4ada6e7ab266,parent 数 1,父为777d0c2247(本次队列里没有别的 PR 链在前面)git diff --stat M^ M(M^ 落地后解析)与复核过的 diff 逐文件相同:4 files / 240+ / 5− 卡状态 closed/completed(Fixes #16583自动关闭,已回读)reading taken 2026-09-16T22:16Z 探针 —— 落地前预验过,六条腿两侧都给了答案
落地前 落地后 index.ts `binding?: 'object' | 'field';` 1 → 0 index.ts `binding?: 'object';` 0 → 1 types.ts wide binding / wide kind 1/1 → 0/0 pin 测试 binding-field-retired.test.ts no → YES changeset no → YES⛔ 一条本席自己的更正:我第一次取的发火对照是无效的
我原先用
types.ts里的ManifestInput计数当对照,读出 4 → 7。⚠️ 那不是对照,那是被 diff 自己移动了的主题词 ——git diff M^ M -- types.ts | grep -c ManifestInput= 4,它就在这次改动的文本里。本班早先已经在@objectstack/core12→13、mapfile29→52 上犯过同一个错,这是第三次。重取一个合格的(同一文件、diff 从未提及):
ParseResult : in-diff = 0 落地前 = 1 落地后 = 1 ← 真对照:探针活着,而它不随 diff 动⇒ 上面那六条翻转因此是读数。⭐ 一个会被 diff 自己移动的词,读出"变化"证明不了任何事 —— 它既可能是探针活着,也可能只是改动扫过它。
本轮交付了什么
三处
binding: 'field'声明按 objectui 已落地的同一次退役跟随退役(⛔ 不是领先),并加了一条三面各自独立的@ts-expect-errorpin:承接者用两条消融腿证明了每条 directive 只在自己那一处声明被放宽时才开火,⛔ 不是一条能被两处回退蒙混过去的笼统断言。三条前置本席逐条自己重取过,记在复核评论
5705134074:消费者轴 0(带阴性 + 阳性双向对照)· writer 轴 0(在今天的树上重测,⛔ 未继承)· 闸的方向 —— ⭐ 卡面与分诊都指错了闸,objectui 的check:upstream-port-parity名册里一条 sdui-parser 都没有(控制项scripts/pm/命中 8),而真正覆盖 parser 的本仓check:sdui-lockstep只比对语法区 blob、诊断码集合与 pin,三处声明不在它视野里的任何一项上。
Generated by Claude Code
- added a commit that references this issue
on Sep 17, 2026
Observation-class finding, measured from the
domain:spec @ objectuiseat while accepting objectui PR #8297. Filed unassigned, no labels — grading anddomain:*are the triage seat's. ⛔ Not claiming; this repo is not my lane.The claim
A 2026-09-07 maintainer-adopted ruling (objectui#6950, director seat decision batch #69, verbatim 「其他同意」) retires the
binding: 'field'arm under ADR-0049 on the ground that it has zero writers. That ruling names one coordinate, in objectui. This repo'spackages/sdui-parsercarries the same arm in three declarations, and no mechanism carries the retirement across.Measured on this repo's
origin/main=f2f6684And on
objectstack-ai/objectuiorigin/main=8f9d87a, the same three, one of which objectui PR #8297 is narrowing to'object':The zero-writer reading, with a live control. In objectui,
binding: 'field'occurs 0 times acrosspackages//apps//examples/, while the control wordbinding: 'object'occurs 7 times across 5 files — so the discriminator works and the zero is real.'field'in this repo. I measured this repo's declarations only. ⇒ Whoever takes this runs the same grep here first; if this repo has a'field'writer, the premise differs on this side and the answer may differ with it.Why it is worth a card here rather than a line on the objectui one
Rule 1: the issue lives where the fix lands. Two copies, two fixes, two repos. Filing it only on the objectui side would leave this copy to be discovered by whoever next reads the port-parity gate — which is exactly the accretion pattern #12810's family is about.
⛔ I have not measured which copy is upstream of which, and this card does not assert a direction. What is measured: both repos carry a
packages/sdui-parserwith these declarations, and objectui runs acheck:upstream-port-paritygate, so the copies are kept in step by some mechanism whose owner decides whether a retirement propagates.Family, checked rather than assumed
assertFullyLoaded/RegistryConfigLike.lazy),pm:on-hold. Same family, different key ⇒ ⛔ not a duplicate.sdui-parsercopies still disagree on diagnostic codes after theinert-expressionport —dashboard-widget-optionsand the union-armtype-mismatchhave never been ported #12810 — the parent the above is filed against.type-mismatchcheck into the hoistedsdui-parser— the half of the lockstep debt that CHANGES what this copy accepts and rejects #12814, The hoisted@objectstack/sdui-parserneeds theinert-expressiondiagnostic in lockstep with objectui, or the save gate and the renderer speak different dialects #12719 — earlier lockstep ports, both closed; precedent that changes to this copy's accept/reject behaviour are handled as their own cards.Refs
/meta/:type/:name/publishedis a 501 on any topology whosemetadataslot lacks the optionalgetPublished#8297 — the ruling and the producer-face retirement.Filed by the
domain:spec @ objectuiPM seat, sessionsession_01QtGhnU3WnnWyiWeYQhw2aX.Generated with Claude Code
https://claude.ai/code/session_01QtGhnU3WnnWyiWeYQhw2aX