Repository navigation
finding(plugin-sharing): recipient_id declares dependsOn: ['recipient_type'] while its widget also reads object_name — the declaration understates what it reads, and a scoped renderer would break the field recipient in silence #19258
Copy link
Copy link
Closed
Labels
Description
Activity
huangyiirene commented
on Sep 21, 2026 CollaboratorMore actionsClaim: session_01AhQASwqJr2Z7XfGWUdvnbF
Branch:claude/issue-19258-recipient-id-dependson-object-name
Session:session_01AhQASwqJr2Z7XfGWUdvnbF
Clause-②: no认领 ——
domain:services席写于 2026-09-21T03:52Z。⛔ 与卡面不一致处以本评论为现值。
为什么现在可派(本卡此前被条款 3 挡着)
维护者裁决,2026-09-21T03:52Z,逐字:「没有卡的时候可以处理 p3」。⇒ 在飞为 0、队列无更高级别可派时,p3 卫生/散文卡解禁。p0 实读仍为 4(
12243,11663,11632,2714)—— 变的是闸门,不是事实;条款 3 的其余适用面不受本裁决影响。条款②:两条肢都测了(⛔ 不再只测一条)
- 接受集肢:
dependsOn只影响表单渲染器把哪些兄弟字段的值传给 widget,⛔ 不改任何解析/准入判定 ⇒ 没有先前被拒的输入变成被接受。 - 公开面肢:改的是一个既有键的值(数组多一个成员),⛔ 不是新导出符号、⛔ 不是已发布载荷上的新键、⛔ 不触
packages/spec。
⇒ 两肢皆否 ⇒
no。(本班我在 #19307 上正因为只测了接受集肢、对整个析取式下结论而报错,已更正5753070284;此处逐肢申明。)交付物两半,第二半有前置条件
- 主交付(无条件):
recipient_id的dependsOn补上object_name—— widget 实际读两个兄弟字段,声明只写了一个。同文件criteria字段声明dependsOn: ['object_name']是活的对照 ⇒ 这是遗漏,⛔ 不是没人用的键。 ⚠️ 条件交付:正文点名的那段 docblock 括号(「the picker has no mapping for that kind and degrades to its text input」)只有在 objectui#10049 落地后才变成假话。⇒ 先核它的状态;核不到就 ⛔ 不要改那段话,在报告里说明。⛔ 不许凭卡面推断它已经落地。
⛔ objectui 不在本会话的仓范围内;若你也读不到,按「核不到」处理,⛔ 不猜。
Generated by Claude Code
- 接受集肢:
huangyiirene commented
on Sep 21, 2026 CollaboratorMore actionsos-dev-report
{ "issue": 19258, "status": "done", "branch": "claude/issue-19258-recipient-id-dependson-object-name", "pr": "https://github.com/objectstack-ai/objectstack/pull/19505", "session": "session_01AhQASwqJr2Z7XfGWUdvnbF", "premise_still_valid": true, "summary": "sys_sharing_rule.recipient_id now declares dependsOn: ['recipient_type', 'object_name'] — both siblings its recipient-picker widget reads. Three readings taken first-hand on today's head: (1) recipient_id.dependsOn was ['recipient_type'] at sys-sharing-rule.object.ts:197; (2) control, same file, criteria_json.dependsOn is ['object_name'] at line 156 for its filter-condition widget, so the key is live and used correctly a few lines up; (3) objectui RecipientPickerField.tsx:150,152 reads dependentValues.recipient_type AND dependentValues.object_name, and does so at this repo's pinned .objectui-sha 87af769e too. The conditional second half was checked rather than assumed and turned out UNBLOCKED: objectui#10049 landed as 23b99585 (2026-09-20) and merge-base --is-ancestor 23b99585 87af769e exits 0, so the pinned console includes it — the docblock parenthesis claiming the picker 'has no mapping for that kind and degrades to its text input' was false for the shipped console and was corrected in the same commit. The issue's assignee was already set by the PM dispatch (huangyiirene, the shared identity); I wrote it never. Three declaration pins added to the existing authoring-seams block of field-recipient.test.ts. Patch changeset on @objectstack/plugin-sharing.", "tests": "pnpm --filter '@objectstack/plugin-sharing^...' build --concurrency=2 :: exit 0 (dependency closure). pnpm --filter @objectstack/plugin-sharing exec vitest run --maxWorkers=2 src/field-recipient.test.ts :: exit 0 — 'Test Files 1 passed (1) / Tests 60 passed (60)'. pnpm --filter @objectstack/plugin-sharing build && typecheck :: exit 0 ('check:test-typecheck: OK — test layer compiles; 2 file(s) / 3 error(s) / 3 pinned signature(s) held'). pnpm lint (repo-wide, eslint . --no-inline-config) :: exit 0 — full run, no narrowing claimed, so no narrowing evidence is owed. dispatch-gates --commands (derived on THIS tree, commit 5e794538b, --repo objectstack-ai/objectstack asserted and held): 62 families derived, all 62 run, 60 exit 0. pnpm check:i18n first exited 3 (PREREQUISITE NOT MET), so its declared 10-package closure was built (exit 0) and it was re-run :: exit 0 — '9 package(s) — all bundles in sync'. NOT MEASURED: pnpm check:dual-build-cjs-loads and pnpm check:type-check-debt, both exit 3 PREREQUISITE NOT MET — each needs a whole-repo dist, which is CI's build; neither is a red and neither is a green. dispatch-gates --ran with exit codes reconciles: 62 derived, 60 run, 2 NOT-MEASURED, 0 UNRUN. ABLATION (fix committed FIRST as 5e794538b, then mutated): scripts/ablation-replace.mjs reverted dependsOn to ['recipient_type'] and proved the mutation landed before running anything — anchor 1 -> 0, blob 3b86f89cc43e -> 158df1894eb5, and in-run grep counts ['recipient_type']=1 / ['recipient_type','object_name']=0. Predicted direction red, observed red and SHARP: 'Tests 1 failed | 2 passed | 57 skipped (60)', the single failure being the new object_name pin, while the recipient_type pin and the criteria_json control stayed green. No dist preflight was owed: the test imports ./objects/sys-sharing-rule.object.js, a same-package relative specifier resolved from src, not through a package exports entry into dist. Restore verified by state, not exit code: blob back to 3b86f89cc43e == HEAD and 'git diff HEAD' empty (ablation-replace's own restore leg, with its EXIT/INT/TERM trap). Changeset measured not assumed: after building the package, dist/index.js (in files[]) carries dependsOn: [\"recipient_type\", \"object_name\"], positive control 'recipient-picker' 1 hit ⇒ publish surface moves ⇒ patch changeset, skip-changeset does not apply.", "mcp_calls": "0 — no MCP GitHub tool was called, read or write. One non-GitHub MCP call: Claude_Code_Remote add_repo (objectstack-ai/objectui, access read), which attached nothing and only reported that anonymous git reads are already served; the objectui readings come from a read-only shallow clone at /home/user/objectstack-ai/objectui.", "api_writes": "2 — POST /repos/objectstack-ai/objectstack/pulls (draft PR 19505, body read back: byte-identical to what was sent apart from a stripped trailing newline, one footer, no sanitizer mutation) and POST /repos/objectstack-ai/objectstack/issues/19258/comments (this report). ZERO label writes: the dispatch named no label scope and skip-changeset does not apply (a changeset is included), so the permitted intersection was empty. The branch push is git, not REST. Reads used: GET issue 19258, GET its comments, GET pull 19505.", "open_questions": [], "out_of_scope_findings": [ "noted, not filed: same-shape sweep across this repo's live `widget` declarations came back NEGATIVE — `object_name`'s `object-ref` widget reads no siblings (objectui ObjectRefField.tsx contains no `dependentValues` at all), `criteria_json`'s `filter-condition` widget reads exactly the `object_name` it already declares, and `sys_permission_set`'s `permission-facet-link` reads no siblings either. So `recipient_id` was the only instance of this defect; nothing to file. Carrier: none needed — the result is that no other file is affected.", "noted, not filed: `packages/spec/liveness/field.json`'s `widget` entry anchors its evidence at objectui @09987b68 while `.objectui-sha` is now 87af769e. That is a correctly anchored historical reading (a count plus the tree it was taken against), not drift, so it is not a finding. Carrier: the next enforce-or-remove audit of that ledger entry." ] }
Generated by Claude Code
Path: none | latent declaration defect (plugin-sharing) | 北极星「优先级」4
Filed by the
domain:ui#2execution seat at objectstack-ai/objectui (PM sessionsession_018HrVaotisyhgmot9o2MLRq) while accepting objectui PR #10049 (objectui#7613). Raised by that PR'sos-devas an out-of-scope finding and re-verified first-hand here before filing — ⛔ not transcribed. ⛔ Not graded, ⛔ nodomain:*applied, ⛔ not routed: that is the triage seat's sole production.The reading
packages/plugins/plugin-sharing/src/objects/sys-sharing-rule.object.ts, read onorigin/mainin this act:The
recipient-pickerwidget reads two siblings, not one:recipient_typeand, for thefieldrecipient kind,object_name— the shared object whose user-typed columns it offers. The declaration names only the first.Control, in the same file: the neighbouring
criteriafield declaresdependsOn: ['object_name']for itsfilter-conditionwidget, so the key is live and correctly used a few lines up. ⇒ the omission is an omission, ⛔ not a key nobody uses.Why it is a trap rather than a bug today
It works only because the form renderer passes
dependentValuesas the WHOLE watched record rather than adependsOn-scoped slice. A renderer that ever scoped it — which is what the declaration asks for — would break thefieldrecipient mode in silence: the picker would lose the object name, fall back to its plain text input, and an admin would be back to typing a column name by hand with no error anywhere.⇒ the class this belongs to: a declaration that understates what the widget reads, on metadata authored by one party and consumed by another.
A second item, in the same file and the same fix
The
recipient_iddocblock currently tells the reader:fieldand offers the shared object's user-valued columns (exactly the set this repo's ownfieldHoldsUsersaccepts —user, orlookup/master_detailwhosereferenceissys_user). Left as is, the comment will assert the opposite of the shipped behaviour.Refs
objectui#7613 · objectui PR #10049 (
fieldHoldsUsersthere is a clause-for-clause copy of this repo's own) · objectstack#15072 · objectstack#14103Dedupe words:
recipient_id dependsOn·recipient-picker object_name·dependentValues scoped slice·sys-sharing-rule widget declaration·field recipient picker mappingGenerated by Claude Code