Skip to content

fix(plugin-sharing): recipient_id declares object_name, the second sibling its picker reads - #19505

Merged
huangyiirene merged 1 commit into
mainfrom
claude/issue-19258-recipient-id-dependson-object-name
Sep 21, 2026
Merged

huangyiirene merged 1 commit into
mainfrom
claude/issue-19258-recipient-id-dependson-object-name

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes #19258

Clause-②: no

sys_sharing_rule.recipient_id declared dependsOn: ['recipient_type'] while its recipient-picker widget reads two siblings. It now declares both.

The three readings, taken first-hand on today's head (4045781fa, worktree base)

# reading value
1 recipient_id.dependsOn before this PR — packages/plugins/plugin-sharing/src/objects/sys-sharing-rule.object.ts:197 ['recipient_type']
2 control, same file, criteria_json.dependsOn at line 156, for its filter-condition widget ['object_name']
3 the widget's sibling reads — objectui packages/fields/src/widgets/RecipientPickerField.tsx:150,152 dependentValues.recipient_type and dependentValues.object_name

Reading 2 is the judgement: the key is live and used correctly a few lines up, for the very same object_name dependency, by a widget in the same form. So this was an omission, not a key nobody uses.

Reading 3 was taken in objectui at befd40cc and re-taken at this repo's pinned .objectui-sha 87af769e — the picker reads object_name at the pin too, so the dependency is live in the console this repo actually ships.

Why nothing was broken today, and why that is the point

objectui packages/components/src/renderers/form/form.tsx:3004 passes dependentValues: ruleRecord — the whole watched form record, not a dependsOn-scoped slice. That is what masked the under-declaration. A renderer that ever scoped it — which is exactly what this key asks for — would drop the object name and degrade the field recipient mode to a plain text input in silence: no error, no empty state, just an admin typing a column name by hand again. The declaration is the only thing that survives that change, so it is what gets fixed.

The second half of the fix: the docblock parenthesis, now verified unblocked

The recipient_id docblock said the picker "has no mapping for that kind and degrades to its text input". That was conditional on objectui#10049, so it was checked rather than assumed:

  • objectui#10049 landed as commit 23b99585, 2026-09-20, feat(fields): give RecipientPickerField a picker mode for the field sharing recipient (objectui#7613).
  • git merge-base --is-ancestor 23b99585 87af769e exits 0 — this repo's pinned console includes it. (Exit 0 is self-proving on a shallow checkout; the control leg, an older known-ancestor commit, also exits 0.)

So the parenthesis is false for the console this repo ships, and the docblock now says what the picker actually does: it offers the shared object's user-valued columns, using a "holds users" predicate that is a clause-for-clause copy of this plugin's own fieldHoldsUsers.

Tests

packages/plugins/plugin-sharing/src/field-recipient.test.ts gains three pins in the existing authoring-seams block (which already asserts declaration facts about this same field):

  • recipient_id.dependsOn contains recipient_type;
  • recipient_id.dependsOn contains object_name;
  • control: criteria_json.dependsOn still contains object_name.

Reverse verification — predicted direction: red, and sharply. The fix was committed first (5e794538b), then dependsOn was reverted on disk to ['recipient_type'] through scripts/ablation-replace.mjs, which proved the mutation landed by anchor counts and blob hash (3b86f89cc43e to 158df1894eb5) before running anything:

grep count "dependsOn: ['recipient_type']"               -> 1   (mutation on disk)
grep count "dependsOn: ['recipient_type', 'object_name']" -> 0
Tests  1 failed | 2 passed | 57 skipped (60)
FAIL  ... names `object_name` — the sibling the `field` mode reads for its candidate columns

Exactly one pin failed — the object_name one. The recipient_type pin and the criteria_json control stayed green, so the new pin is sharp rather than tautological. Restore verified the way a restore has to be: blob back to 3b86f89cc43e == HEAD, and git diff HEAD empty.

Other readings, exit codes captured before any pipe:

run verdict
pnpm --filter @objectstack/plugin-sharing exec vitest run src/field-recipient.test.ts exit 0 — 60 passed
pnpm --filter @objectstack/plugin-sharing build && ... typecheck exit 0 (test layer compiles; debt ledger held)
pnpm --filter '@objectstack/plugin-sharing^...' build (dependency closure) exit 0
pnpm lint (repo-wide, eslint . --no-inline-config) exit 0 — no narrowing claimed
scripts/pm/dispatch-gates.mjs --commands derived families, all 62 run 60 exit 0
pnpm check:i18n exit 0 after building its declared 10-package prerequisite closure — 9 packages in sync
pnpm check:dual-build-cjs-loads, pnpm check:type-check-debt NOT MEASURED — both exit 3, PREREQUISITE NOT MET (each needs a whole-repo dist, which is CI's build). Not a red and not a green.

dispatch-gates --ran with those exit codes reconciles: 62 derived, 60 run, 2 NOT-MEASURED, 0 UNRUN.

Changeset

patch on @objectstack/plugin-sharing. Measured rather than assumed: after pnpm --filter @objectstack/plugin-sharing build, the changed declaration is present in the published files[] output — dist/index.js carries dependsOn: ["recipient_type", "object_name"], with recipient-picker as the positive control (1 hit). So the publish surface moves and skip-changeset does not apply.

Acceptance notes

  • Same-shape sweep, negative result. widget is live in this repo on the sys_sharing_rule trio plus sys_permission_set's permission-facet-link. Of the others: object_name's object-ref widget reads no siblings (ObjectRefField.tsx contains no dependentValues at all), criteria_json's filter-condition widget reads exactly the object_name it already declares, and permission-facet-link reads no siblings either. So recipient_id was the only instance of this defect — nothing else to file.
  • No gate or test in this repo pinned dependsOn on this object before this PR; the three added pins are the first, and they sit in the file that already owns this field's declaration assertions rather than in a new verification surface.
  • Nothing in packages/spec is touched, no renderer behaviour is changed, and no dependentValues plumbing is changed — this PR moves a declaration and the comment that describes it.

Generated by Claude Code

…bling its picker reads

`sys_sharing_rule.recipient_id` declared `dependsOn: ['recipient_type']`
while its `recipient-picker` widget reads TWO siblings: `recipient_type`
picks the mode, and the `field` recipient kind (#15072) reads
`object_name` to offer that object's user-valued columns.

The neighbouring `criteria_json` field already declares
`dependsOn: ['object_name']` for its `filter-condition` widget, so the
key is live and correctly used a few lines up — the omission was an
omission, not a key nobody uses.

Nothing breaks today only because the form renderer passes
`dependentValues` as the whole watched record instead of a
`dependsOn`-scoped slice. A renderer that ever scoped it — which is what
this declaration asks for — would drop the object name and degrade the
`field` recipient mode to a plain text input in silence.

Also corrects the `recipient_id` docblock: the pinned console
(`.objectui-sha` 87af769e) includes objectui#10049, so the picker DOES
have a mapping for the `field` kind and no longer degrades to its text
input for it.

Claude-Session: https://claude.ai/code/session_01AhQASwqJr2Z7XfGWUdvnbF
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/plugin-sharing, touching 3 documentable anchor(s).

5 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/automation/webhooks.mdx (via object_name (literal, a string literal in SysSharingRule))
  • content/docs/kernel/runtime-services/audit-service.mdx (via object_name (literal, a string literal in SysSharingRule))
  • content/docs/permissions/record-view-auditing.mdx (via object_name (literal, a string literal in SysSharingRule))
  • content/docs/protocol/kernel/http-protocol.mdx (via object_name (literal, a string literal in SysSharingRule))
  • content/docs/protocol/kernel/i18n-standard.mdx (via object_name (literal, a string literal in SysSharingRule))

⛔ 2 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v15.mdx (via recipient_type (literal, a string literal in SysSharingRule))
  • content/docs/releases/v17/17-1.mdx (via recipient_type (literal, a string literal in SysSharingRule))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see

Coarse fallback — 9 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 2cac3636cab1cecef8f7a0453e4963dd1d01fb21 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 151d17fa3d323b9d15cc3181747d7d24fea766a5 — the merge of head 5e794538b29eef74c491f510ad67c9d5c9d52c2d into base 2cac3636cab1cecef8f7a0453e4963dd1d01fb21, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 151d17fa3d323b9d15cc3181747d7d24fea766a5 && git checkout 151d17fa3d323b9d15cc3181747d7d24fea766a5
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2cac3636cab1cecef8f7a0453e4963dd1d01fb21 5e794538b29eef74c491f510ad67c9d5c9d52c2d && git checkout -B drift-repro 2cac3636cab1cecef8f7a0453e4963dd1d01fb21 && git merge --no-ff 5e794538b29eef74c491f510ad67c9d5c9d52c2d

node scripts/docs-audit/affected-docs.mjs --json 2cac3636cab1cecef8f7a0453e4963dd1d01fb21

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 2cac3636cab1cecef8f7a0453e4963dd1d01fb21 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Sep 21, 2026
@huangyiirene
huangyiirene marked this pull request as ready for review September 21, 2026 05:14
@huangyiirene
huangyiirene added this pull request to the merge queue Sep 21, 2026
Merged via the queue into main with commit 4be0868 Sep 21, 2026
36 checks passed
@huangyiirene
huangyiirene deleted the claude/issue-19258-recipient-id-dependson-object-name branch September 21, 2026 05:44
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 tests tooling

Projects

None yet

2 participants