Repository navigation
feat(platform-objects)!: Setup's organization, team, business-unit and user records carry no Discussion feed (enable.feeds: false) - #23869
Conversation
…le.feeds: false sys_organization, sys_team, sys_business_unit and sys_user took the enable.feeds default (true), so the console drew a Discussion feed with a comment composer on every identity record in Setup. Declaring the flag false hides the feed and makes plugin-audit's existing enable.feeds gate refuse a comment create on these objects with 403 FEEDS_DISABLED; rows stored before the flag stay readable and body-editable. The pins boot a real ObjectQL with the real identity definitions and the real installAuditWriters hooks (plugin-audit), one refusal case per object, the grandfathered-row case on sys_user, and a business-object CONTROL. Claude-Session: https://claude.ai/code/session_01TQLy3Yq6vF4SDpTXdr3Uwi Co-authored-by: Claude <noreply@anthropic.com>
…s live on that thread Claude-Session: https://claude.ai/code/session_01TQLy3Yq6vF4SDpTXdr3Uwi Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 2 package(s): 4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 6 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 11 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin be076954b9d126671f9873159a2eb4f807d5f837 && git checkout be076954b9d126671f9873159a2eb4f807d5f837
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 6422da58e83ac5032030c7daa4787fddf5eeb165 01f606f4b8101cd53d2e93c95d8de97cd549167e && git checkout -B drift-repro 6422da58e83ac5032030c7daa4787fddf5eeb165 && git merge --no-ff 01f606f4b8101cd53d2e93c95d8de97cd549167e
node scripts/docs-audit/affected-docs.mjs --json 6422da58e83ac5032030c7daa4787fddf5eeb165
|
…bject thread The thread_id description and the docblock illustrated the thread format with `sys_user:abc123`. sys_user now declares enable.feeds: false, so a comment created by following that example answers 403 FEEDS_DISABLED. The example becomes `account:9001`, already the docblock's second one. The zh-CN, ja-JP and es-ES leaves swap only the example; the en bundle is regenerated from the source in the next commit. Claude-Session: https://claude.ai/code/session_01TQLy3Yq6vF4SDpTXdr3Uwi Co-authored-by: Claude <noreply@anthropic.com>
Written by `node scripts/check-i18n-bundles.mjs --write`; the only leaf that moved is sys_comment.fields.thread_id.help. Claude-Session: https://claude.ai/code/session_01TQLy3Yq6vF4SDpTXdr3Uwi Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: ① Derived judgmentsDiff read as
Gate verdicts on ② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS |
席位核对 · ✅ ACCEPT: PR #23869 at
|
Fixes #23838
Clause-②: no (narrowing: the comment create door refuses on four platform objects that accept it today)
What changes
sys_organization,sys_team,sys_business_unitandsys_user(packages/platform-objects/src/identity/) declared noenable.feeds, so they took the spec default (true) and the console drew "Discussion (0)" with a comment composer on every identity record in Setup (objectui#12614 item 1). Eachenable:block now declaresfeeds: false, with a two-line comment naming the reason. No other line in those files moves.Both consumers of the flag already exist, so nothing else changes:
objectDef?.enable?.feeds !== false(objectuipackages/app-shell/src/views/RecordDetailView.tsx:1754at objectui63d00da) and strips the Discussion nodes when it is false;enforceFeedsCapability(packages/plugins/plugin-audit/src/audit-writers.ts,beforeInsertandbeforeUpdateonsys_comment) refuses a comment whosethread_idnames an object withenable.feeds: false, with the existing403 FEEDS_DISABLED. No new error code.The changeset (
.changeset/23838-identity-feeds-off.md) is aminorbreaking entry under the launch-window convention, with the same Clause-② line and an ADR-0087not-required (no-migration-prescription)disposition: no spec key, export or stored shape moves, and stored comment rows are kept.Measured through the public door
CRM app booted
--freshon a random port from this branch (platform-objects and plugin-audit closure rebuilt at4e5399c4b), signed in as the seeded admin:POST /api/v1/data/sys_commentwiththread_idsys_user:USER_ID403{"code":"FEEDS_DISABLED","object":"sys_user"}sys_organization:ORG_ID403{"code":"FEEDS_DISABLED","object":"sys_organization"}crm_account:ACCOUNT_ID201, row createdGET /api/v1/meta/object/NAME, the four identity objectsenable.feeds=falseon all four (what the console reads)GET /api/v1/meta/object/crm_accountenable.feedsabsent (the console reads absent as on)The server was stopped after the probe (its PID only); its tempdir is gone.
Producer search (dispatch assumption 2): no platform code writes a comment into these threads
Searched at the branch base
66d456d01:sys_commentin non-test code: the only writers are plugin-audit's own hooks (the feeds gate,comment-access-hooks.ts, the mention hook, which writes notifications, not comments) and the CLI's comment-reactions migration (packages/cli/src/utils/comment-reactions-conversion.ts), which insertssys_comment_reactionrows only;'sys_user:,'sys_organization:,'sys_team:,'sys_business_unit:): hits only in thesys_comment.thread_iddescription example and its four translation bundles, oneparseCommentThreadIdunit test and one driver-test code comment, none a writer;thread_idassignment and everyOBJECT:IDtemplate near comment code in non-test sources: reads and keys only (the access hooks' visibility filter, a mention dedup key, a cache key);examples/**and every seed or fixture path: nosys_commentrows; the dogfood comment fixtures use their own fourcmt_*objects;63d00da: the record page createssys_commentonly from the Discussion composer, which is behind the samefeedsEnabledread.Not searched: the
cloudrepository, which is not in this container.Pins
One file,
packages/plugins/plugin-audit/src/identity-objects-feeds-off.test.ts. It boots a realObjectQLover a stub driver with the REAL four definitions imported from@objectstack/platform-objects/identity(aliased to source in this package'svitest.config.ts, so the verdict is about the checkout, notdist/) and the realinstallAuditWritershooks:it.each): a new comment on one of its records rejects withcode: 'FEEDS_DISABLED',status: 403and the object named, and no row lands;sys_user: the gate is first shown live on that exact thread, then a row written below every hook (what a row stored before this change is) stays readable throughfind, and a body edit withoutthread_idstill saves;enable.feedsstill accepts a comment.The pins live in plugin-audit because
@objectstack/platform-objectshas no runtime dependency onobjectqlorplugin-audit(plugin-audit depends on platform-objects; the reverse would be a cycle), so the real gate cannot be exercised there. This file isdomain:servicesterritory, as the claim anticipated. The generic gate stays pinned where it was:audit-writers.test.ts(insert) andcapability-gate-update-verb.test.ts(update verb and the grandfathered edit).Ablation (one-time proof, not kept)
Each leg ran after the fix was committed, through
node scripts/ablation-replace.mjsin WRAP mode (literal anchor, on-disk counts, blob hash before and after, restore proven by blob equal to HEAD and an emptygit diff HEAD), runningpnpm --filter @objectstack/plugin-audit exec vitest run --maxWorkers=2 src/identity-objects-feeds-off.test.ts. No build ordist/leg is owed: the identity definitions resolve tosrc/through the alias, and the gate mutation is in the package under test.feeds: false,insys-user.object.tsdf41d5b3c3f3,84847d0be0b7sys_usercase and the grandfathered-row casesys-organization.object.tscfcbe12495aa,33e67fccd9ddsys_organizationcasesys-team.object.ts3a0954909643,df521d289587sys_teamcasesys-business-unit.object.ts0db7f124c9d4,e5f6d7a3d360sys_business_unitcaseaudit-writers.ts(feeds === falseread asfeeds !== true)f556c52ac945,4a3379a3fc5fEvery leg restored to its HEAD blob, and the tree was clean after the run.
Tests and gates, on head
4e5399c4b(after mergingorigin/maina31ff2eb5, which carries #23845)pnpm --filter @objectstack/platform-objects test: 71 files, 1103 tests passed.pnpm --filter @objectstack/plugin-audit test: 52 files, 839 tests passed.pnpm --filter @objectstack/platform-objects --filter @objectstack/plugin-audit typecheck: exit 0; the new file is in plugin-audit'stsconfig.test.jsonprogram (--listFiles).node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 65 commands, each run with its exit code captured before any pipe, all exit 0;--ranreconciliation: 65 accounted for, 0 NOT-MEASURED, 0 UNRUN.check-changeset-fixed,check:authz-resolver,check:error-code-casing,check:filter-alias-parity, all exit 0.Acceptance notes
sys_comment.thread_idexample fromsys_user:abc123toaccount:9001: the description and docblock inpackages/plugins/plugin-audit/src/objects/sys-comment.object.ts, theenbundle regenerated bynode scripts/check-i18n-bundles.mjs --write, and the zh-CN, ja-JP and es-ES leaves swapped by hand. After this change, a comment created by following the old example answers403 FEEDS_DISABLED. (Written by thedomain:engineseat 2 from the dev's patch-round report; the claim's file-surface amendment is 6213345119 on platform-objects: the four identity objects declare noenable.feeds, so Setup's organization, team, business-unit and user records draw a Discussion feed; declareenable.feeds: false(item 1 of objectui#12614) #23838.)CONTRACT_REVIEW_TIERbefore the queue.Generated by Claude Code