Repository navigation
fix(plugin-audit): match an @mention email case-insensitively - #27751
Conversation
An email-shaped mention was looked up with an exact match on sys_user.email, so a differently-cased address resolved nobody and the colleague was silently never notified. Normalise it with the shared email normalisation (trim, then lowercase) before the lookup, the same spelling identity stores and sign-in queries. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4czuTWNgKR22fKv7jia
📓 Docs Drift Check1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 10 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 9794c41ec66785b13d061cdcf1a6ea8a4052a5c1 && git checkout 9794c41ec66785b13d061cdcf1a6ea8a4052a5c1
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 34dc09b68df7d37ff8f70ed0dae19fbb1700dd65 e711910983d66be94059b99aa485bff340c4a016 && git checkout -B drift-repro 34dc09b68df7d37ff8f70ed0dae19fbb1700dd65 && git merge --no-ff e711910983d66be94059b99aa485bff340c4a016
node scripts/docs-audit/affected-docs.mjs --json 34dc09b68df7d37ff8f70ed0dae19fbb1700dd65 |
|
domain:server#3 · os-elon-musk · session_016WV4czuTWNgKR22fKv7jia Seat ACCEPT · PR #27751 · head
|
Requested by Elon · project thread
Fixes #27503
Clause-②: no
Metadata-protocol: none
维护者速读
Carol@Example.com)评论照样 201 成功,但被提及的人永远收不到通知,作者也看不到任何报错。packages/plugins/plugin-audit/src/mention-recipient-gate.ts里resolveMentionedUser的where那一行;然后看mention-recipient-gate.integration.test.ts新增的两个用例。pnpm --filter @objectstack/plugin-audit exec vitest run src/mention-recipient-gate.integration.test.ts,预期 Tests 17 passed (17)。What changes
resolveMentionedUser(plugin-audit's @mention recipient gate) looked an email-shaped mention up withwhere: { email: value }, an exact match onsys_user.email. Identity stores that column lowercased, soG4B.MEMBER@EXAMPLE.COMresolved nobody. The comment was still accepted with 201, and the gate loggedmention notification withheldwith reasonunknown_email.The lookup now passes the address through
normalizePlatformAdminEmailfrom@objectstack/core. That is the one exported email normalisation in core (trim, then lowercase), and it is already the comparison the platform-admin derivation and the Layer 0 wall use. For an address that has already been trimmed, it gives exactly the spelling sign-in queries:findSignInAccount(plugin-auth) querieswhere: { email: email.toLowerCase() };/sign-in/emailcallsinternalAdapter.findUserByEmail(email.toLowerCase()), andcreateUser/updateUserwriteemail.toLowerCase(), so stored addresses are already normalised.No second matcher is added. Who may be notified does not change: the record read and the comment read in the mentioned user's own envelope still decide.
Tests
packages/plugins/plugin-audit/src/mention-recipient-gate.integration.test.ts(real kernel, ObjectQL, SQLite driver, AuditPlugin) gets two new cases:Carol@A.Test, and one mentioningCAROL@A.TESTwith spaces around it, each notify the user stored ascarol@a.test. Both go through the realafterInsertmention writer.admitMentionRecipientswithCAROL@A.TESTadmits CAROL and logs nothing, so there is nounknown_email.Acceptance notes
normalizePlatformAdminEmailcarries a platform-admin name, but its docblock calls it the one email normalisation, and it is the only exported one in@objectstack/core. Renaming it is a naming question only, so no card was filed.sys_userrow written with a mixed-case email outside the identity write paths (for example a raw system-context insert) cannot be found by sign-in. After this change it cannot be found by a mention either, so a mention now reaches exactly the users sign-in reaches.mentions: ["nosuchuser123"]) is logged ascannot_read_thread. It is unchanged here: it affects only the log text, and nobody is notified who should not be. This is an observation, not filed.origin/main.origin/mainmoved after the single merge (to34dc09b68). The only family file that changed in that range isscripts/check-route-envelope.mjs, and it is not one this diff derives. CI runs on the merged head.Verification
All readings are on head
e7119109(fix commit5febd38eplus one merge oforigin/mainef359b95).Red before the fix (built closure, test only)
Green after the fix
Ablation (fix committed first; scripts/ablation-replace.mjs; suite resolves core and this package from src, so no dist leg)
Package test, typecheck, lint (head e711910)
Derived gate families (dispatch-gates --commands, 61 commands, head e711910)
On the first pass three commands exited 3 (PREREQUISITE NOT MET, nothing was measured). Each was re-run after its prerequisite was met:
check-plugin-teardown-shape --self-test: fetched the pinned fixture commit, then exit 0 (48 cases).check:i18n: built its stated closure, then exit 0 (10 packages in sync).check:dual-build-cjs-loads: fullpnpm build(114 tasks), then exit 0 (112 entries across 69 packages).The PR's check-runs cover all other CI families.
🤖 Generated with Claude Code
https://claude.ai/code/session_016WV4czuTWNgKR22fKv7jia