Skip to content

feat(notifications): @mention notifications for channels and tasks - #1298

Merged
2witstudios merged 6 commits into
masterfrom
pu/mention-notifs
May 8, 2026
Merged

2witstudios merged 6 commits into
masterfrom
pu/mention-notifs

Conversation

@2witstudios

@2witstudios 2witstudios commented May 8, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Channel messages (top-level and thread replies) now fire createMentionNotification for each @mentioned user who passes a canUserViewPage check
  • Task creation fires mention notifications for @mentioned users in the description
  • Task updates diff old vs new description mentions — only newly added mentions trigger notifications, preventing re-notification on edits
  • All notification calls use per-call .catch() for best-effort delivery (one failure never blocks others)
  • loggers.api.error() added to all task-route catch blocks for observability
  • Security gate: canUserViewPage always checked before notifying — prevents crafted mentions from leaking channel/page existence to unauthorized users

Test plan

  • Channel top-level POST: createMentionNotification fires for viewable @mentioned non-senders; skipped for sender self-mentions and users who can't view the channel; errors don't fail the 201 response
  • Channel thread reply POST: notification fires for view-checked mentionTargets; suppressed when alsoSendToParent is set (broad fan-out covers everyone); errors don't fail the 201
  • Task create POST: notifications fire for @mentioned users in description; self-mentions and non-viewable users skipped; errors don't fail the 201
  • Task update PATCH: only newly added @mentions notify (diff logic); self-mentions, non-viewable users, and already-mentioned users skipped; errors don't fail the 200
  • All 6 task-update mention tests use explicit mockResolvedValueOnce chains — canUserViewPage gate and error isolation are actually exercised (not vacuous)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added mention notifications for channel messages: users are now notified when mentioned in message posts, respecting visibility permissions.
    • Added mention notifications for task descriptions: users receive notifications when newly mentioned during task creation or updates, excluding self-mentions and respecting page visibility.

2witstudios and others added 2 commits May 8, 2026 15:45
… and tasks

When a user is @mentioned in a channel message (top-level or thread reply)
or in a task description (create or update), createMentionNotification is
called for each mentioned user who passes a canUserViewPage gate. Task
updates diff old vs new mentions so previously-notified users are not
re-notified. All notification calls are wrapped in try/catch so failures
never fail the API response after DB commit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ry, logging, clean tests

- Switch notification Promise.all to per-call .catch() so each mention
  is attempted independently; one failure no longer blocks the rest
- Add loggers.api.error() to task routes (spec required error logging;
  silent catch was non-compliant)
- Remove redundant description type/length guard in tasks/route.ts —
  extractMentionedUserIds already handles empty/null safely
- Remove WHAT-comments on mention blocks; remove explicit :string
  annotation from mentionTargets.map
- Fix 3 vacuous task-update mention tests that passed for wrong reasons
  due to mockResolvedValue override: use explicit mockResolvedValueOnce
  chains so existingTask.description is distinct from the new value
- Fix loggers.api mock in taskId tests to expose .error() directly
- Assert createMentionNotification not called when alsoSendToParent is
  set (broad fan-out path suppresses targeted mention notification)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 8, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Rate limit exceeded

@2witstudios has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 38 minutes and 42 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e36848fa-02c4-4310-b388-7c59ce726cac

📥 Commits

Reviewing files that changed from the base of the PR and between 1436ff5 and b113b55.

📒 Files selected for processing (6)
  • apps/web/src/app/api/channels/[pageId]/messages/__tests__/route.test.ts
  • apps/web/src/app/api/channels/[pageId]/messages/route.ts
  • apps/web/src/app/api/pages/[pageId]/tasks/[taskId]/__tests__/route.test.ts
  • apps/web/src/app/api/pages/[pageId]/tasks/[taskId]/route.ts
  • apps/web/src/app/api/pages/[pageId]/tasks/__tests__/route.test.ts
  • apps/web/src/app/api/pages/[pageId]/tasks/route.ts
📝 Walkthrough

Walkthrough

This PR adds mention-notification side effects to four API endpoints: channel message posts (top-level and thread replies), task creation, and task description updates. Each endpoint extracts @ mentions from content, filters by viewability permissions and sender identity, and dispatches mention notifications asynchronously with error handling.

Changes

Mention Notifications across Channel Messages and Tasks APIs

Layer / File(s) Summary
Imports and Dependencies
apps/web/src/app/api/channels/[pageId]/messages/route.ts, apps/web/src/app/api/pages/[pageId]/tasks/route.ts, apps/web/src/app/api/pages/[pageId]/tasks/[taskId]/route.ts
Adds imports for createMentionNotification, extractMentionedUserIds, canUserViewPage, and loggers to enable mention-notification dispatch across channel messages and task routes.
Channel Messages Implementation
apps/web/src/app/api/channels/[pageId]/messages/route.ts
Top-level POST extracts mentioned user IDs from message content, filters for sender exclusion and page-view permission, then sends mention notifications. Thread-reply POST sends mention notifications to viewable mention targets after broadcasting inbox events. Notification failures are caught and logged per-recipient without failing the request.
Task Creation Implementation
apps/web/src/app/api/pages/[pageId]/tasks/route.ts
POST endpoint extracts mentioned user IDs from the description field, filters out the author, checks view permission per candidate, and sends mention notifications with error handling wrapped in try/catch and per-notification .catch blocks.
Task Update Implementation
apps/web/src/app/api/pages/[pageId]/tasks/[taskId]/route.ts
PATCH endpoint computes newly added mentions by comparing old vs. new description mention sets, excludes the acting user, verifies each mentioned user can view the target page, and dispatches mention notifications with try/catch error handling and logging.
Channel Messages Tests Setup
apps/web/src/app/api/channels/[pageId]/messages/__tests__/route.test.ts
Adds mockCreateMentionNotification and wires it into the notifications module mock. Sets default resolve behavior in top-level and thread-reply test setups. Extends existing alsoSendToParent assertion to verify mention notifications remain uncalled.
Channel Messages Tests Coverage
apps/web/src/app/api/channels/[pageId]/messages/__tests__/route.test.ts
Introduces comprehensive test suites for top-level and thread-reply mention notifications, validating fanout to viewable users, sender and self-mention exclusion, skipped non-viewable users, and HTTP 201 resilience on notification failure.
Task Creation Tests
apps/web/src/app/api/pages/[pageId]/tasks/__tests__/route.test.ts
Adds mockCreateMentionNotification and test coverage asserting notification on description mentions, self-mention exclusion, viewability filtering, and HTTP 201 returned even when notification creation rejects.
Task Update Tests
apps/web/src/app/api/pages/[pageId]/tasks/[taskId]/__tests__/route.test.ts
Updates permission and logger mocks, adds createMentionNotification to notifications mock. Introduces comprehensive PATCH test coverage validating newly-added mention detection, mention reuse skipping, description absence handling, self-mention suppression, permission-based suppression, and HTTP 200 resilience on notification failure.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • 2witstudios/PageSpace#217: Introduces the core createMentionNotification function and mention-notification infrastructure that this PR depends on for dispatching mention notifications across endpoints.
  • 2witstudios/PageSpace#531: Modifies the channel message POST handler—concurrent changes to the same route related to agent-mention responder and message content handling.

Poem

🐰 A hop through mentions, a notify leap,
Users see tags as promises to keep,
Channels and tasks now gently chime,
When someone mentions a friend in time,
Resilient errors make the dance complete!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(notifications): @mention notifications for channels and tasks' directly and clearly summarizes the main change: adding @mention notification functionality to both channels and tasks.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pu/mention-notifs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

https://github.com/2witstudios/PageSpace/blob/1436ff547a7cbcfa5933b41347bbd50c099ea0c1/apps/web/src/app/api/channels/[pageId]/messages/route.ts#L451-L452
P2 Badge Notify mentioned thread followers too

The mention-notification path for thread replies reuses candidateTargets that explicitly excludes followerSet, so any user who already follows the thread is filtered out before createMentionNotification runs. In practice, @-mentioning a thread follower only emits a thread_updated inbox event and never creates a durable MENTION notification (no notification center entry/email/push), which is inconsistent with top-level channel and task mention behavior.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

TypeScript infers transactionTaskResult as { id: string; title: string }[]
from the default value; our new mockNewTask objects were missing title.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/app/api/pages/[pageId]/tasks/__tests__/route.test.ts (1)

158-195: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

vi.resetAllMocks() clears mockCreateMentionNotification's implementation, causing the happy-path notification test to silently exercise the error path.

vi.resetAllMocks() (line 159) resets all vi.fn() implementations, including the module-scope mockCreateMentionNotification. After this call, mockCreateMentionNotification() returns undefined instead of Promise.resolve(undefined). In the route, the code calls:

createMentionNotification(e.id, pageId, userId).catch(...)

…which becomes undefined.catch(...) → TypeError, caught by the outer try/catch, logged, and silently discarded. The assertion in the test "fires createMentionNotification for @mentioned users…" (line 752) still passes because the mock was called before the TypeError, but the actual notification send path is never verified.

The channel tests correctly guard against this by calling mockCreateMentionNotification.mockResolvedValue(undefined) in each beforeEach after vi.clearAllMocks().

🛠 Proposed fix
  beforeEach(() => {
    vi.resetAllMocks();
+   mockCreateMentionNotification.mockResolvedValue(undefined);
    // Reset default mock for taskStatusConfigs.findMany
    vi.mocked(db.query.taskStatusConfigs.findMany).mockResolvedValue([] as never);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/app/api/pages/`[pageId]/tasks/__tests__/route.test.ts around
lines 158 - 195, The test's vi.resetAllMocks() clears the module-scoped
mockCreateMentionNotification implementation causing
createMentionNotification(...) to become undefined and throw; after the reset,
re-establish the mock's resolved-value behavior (e.g. call
mockCreateMentionNotification.mockResolvedValue(undefined) or equivalent) in the
beforeEach so createMentionNotification remains a Promise-returning mock during
tests; locate and update the beforeEach block that currently calls
vi.resetAllMocks() to add a restoring call for mockCreateMentionNotification
(and any similar module-scoped mocks) so the happy-path notification test
exercises the success path rather than hitting a TypeError.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/src/app/api/pages/`[pageId]/tasks/route.ts:
- Around line 509-530: The mention notification is using the task list's pageId
instead of the individual task page id; update the POST route to pass
result.page.id to createMentionNotification (replace
createMentionNotification(e.id, pageId, userId) with
createMentionNotification(e.id, result.page.id, userId)) and do the same in the
PATCH route (use the task-specific page id variable analogous to
result.page.id), and also update the permission checks that call canUserViewPage
to validate against the task's page id rather than the task list pageId; keep
existing error handling with loggers.api.error and preserve use of
extractMentionedUserIds and the candidates filtering by userId.

---

Outside diff comments:
In `@apps/web/src/app/api/pages/`[pageId]/tasks/__tests__/route.test.ts:
- Around line 158-195: The test's vi.resetAllMocks() clears the module-scoped
mockCreateMentionNotification implementation causing
createMentionNotification(...) to become undefined and throw; after the reset,
re-establish the mock's resolved-value behavior (e.g. call
mockCreateMentionNotification.mockResolvedValue(undefined) or equivalent) in the
beforeEach so createMentionNotification remains a Promise-returning mock during
tests; locate and update the beforeEach block that currently calls
vi.resetAllMocks() to add a restoring call for mockCreateMentionNotification
(and any similar module-scoped mocks) so the happy-path notification test
exercises the success path rather than hitting a TypeError.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5606feff-6e19-4c4e-8511-e2077ac43a12

📥 Commits

Reviewing files that changed from the base of the PR and between e94f42a and 1436ff5.

📒 Files selected for processing (6)
  • apps/web/src/app/api/channels/[pageId]/messages/__tests__/route.test.ts
  • apps/web/src/app/api/channels/[pageId]/messages/route.ts
  • apps/web/src/app/api/pages/[pageId]/tasks/[taskId]/__tests__/route.test.ts
  • apps/web/src/app/api/pages/[pageId]/tasks/[taskId]/route.ts
  • apps/web/src/app/api/pages/[pageId]/tasks/__tests__/route.test.ts
  • apps/web/src/app/api/pages/[pageId]/tasks/route.ts

Comment on lines +509 to +530
if (description) {
try {
const mentionedIds = extractMentionedUserIds(description);
const candidates = mentionedIds.filter((id) => id !== userId);
if (candidates.length > 0) {
const viewChecks = await Promise.all(
candidates.map(async (id) => ({ id, canView: await canUserViewPage(id, pageId) }))
);
await Promise.all(
viewChecks
.filter((e) => e.canView)
.map((e) =>
createMentionNotification(e.id, pageId, userId).catch((err) =>
loggers.api.error('Failed to send mention notification', err as Error)
)
)
);
}
} catch (err) {
loggers.api.error('Failed to resolve mention targets', err as Error);
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find the createMentionNotification implementation to check what the second param (pageId) represents
rg -nP --type=ts -C 10 'export.*(function|const|async function)\s+createMentionNotification'

# Also check call sites for usage context
rg -nP --type=ts 'createMentionNotification\(' -A2

Repository: 2witstudios/PageSpace

Length of output: 5560


🏁 Script executed:

#!/bin/bash
# Read the full createMentionNotification implementation
sed -n '436,500p' packages/lib/src/notifications/notifications.ts

Repository: 2witstudios/PageSpace

Length of output: 1666


🏁 Script executed:

#!/bin/bash
# Read lines around 509-530 in the tasks route file to see context
sed -n '490,540p' apps/web/src/app/api/pages/[pageId]/tasks/route.ts

Repository: 2witstudios/PageSpace

Length of output: 1542


🏁 Script executed:

#!/bin/bash
# Find the PATCH route for tasks and look for mention notification code
sed -n '390,410p' apps/web/src/app/api/pages/[pageId]/tasks/[taskId]/route.ts

Repository: 2witstudios/PageSpace

Length of output: 955


Pass the individual task's page ID to mention notifications, not the task list page.

In both the POST and PATCH routes, createMentionNotification(e.id, pageId, userId) uses pageId (the task list page) instead of the individual task's page ID. This causes the notification message to display the task list title instead of the task title, and users will be navigated to the task list rather than the specific task they were mentioned in.

Use result.page.id in the POST route (line 521) and the equivalent task page ID in the PATCH route (line 402). Also verify that permission checks validate access to the actual task page being mentioned in, not just the task list.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/app/api/pages/`[pageId]/tasks/route.ts around lines 509 - 530,
The mention notification is using the task list's pageId instead of the
individual task page id; update the POST route to pass result.page.id to
createMentionNotification (replace createMentionNotification(e.id, pageId,
userId) with createMentionNotification(e.id, result.page.id, userId)) and do the
same in the PATCH route (use the task-specific page id variable analogous to
result.page.id), and also update the permission checks that call canUserViewPage
to validate against the task's page id rather than the task list pageId; keep
existing error handling with loggers.api.error and preserve use of
extractMentionedUserIds and the candidates filtering by userId.

2witstudios and others added 3 commits May 8, 2026 16:26
Followers were excluded from `mentionTargets` (correct — to avoid
double-counting `channel_updated` unread), but this also suppressed
the durable MENTION notification for them. Split the logic: only
non-followers get `channel_updated`; all @mentioned non-sender users
(followers + non-followers who pass view check) get
`createMentionNotification`.

Adds a regression test for the follower-mention case.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
vi.resetAllMocks() clears the implementation, making .catch() call on
undefined throw a TypeError that is silently caught. Re-establish the
resolved-value implementation in beforeEach so the notification success
path is actually exercised.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
createMentionNotification uses the pageId to look up the page title and
build navigation links. Passing the task list pageId caused notifications
to display the list title and navigate to the list instead of the task.

- POST tasks: use result.page.id (the created task's own page)
- PATCH task: use existingTask.pageId (the task's own page)
- Permission gate: canUserViewPage now checks the task page, not the list

Update test assertions and descriptions to reflect the corrected page IDs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@2witstudios

Copy link
Copy Markdown
Owner Author

Addressed all review findings — summary of fixes pushed in three commits after the initial implementation:

Codex (follower @mentions missing MENTION notification): Fixed in fix(notifications): fire MENTION for @mentioned thread followers. The root cause: thread-reply candidateTargets excluded followerSet to avoid double-counting channel_updated unread, but this also suppressed the durable MENTION notification. Now split into nonFollowerMentioned (gets both channel_updated + MENTION) and followerMentioned (gets MENTION only — they already receive thread_updated). Added a regression test.

CodeRabbit (vi.resetAllMocks() clearing mockCreateMentionNotification): Fixed in test(tasks): restore mockCreateMentionNotification after resetAllMocks. Added mockCreateMentionNotification.mockResolvedValue(undefined) after vi.resetAllMocks() in the POST tasks beforeEach so the happy-path notification test actually exercises the success path.

CodeRabbit (task mention notifications used task list pageId instead of task page ID): Fixed in fix(notifications): use task page ID in mention notifications. createMentionNotification uses the pageId to build the notification title and navigation link — pointing at the task list caused wrong title and wrong nav destination. POST now uses result.page.id, PATCH uses existingTask.pageId. canUserViewPage gate also updated to check the task page. Test assertions updated accordingly.

@2witstudios
2witstudios merged commit 140d2d2 into master May 8, 2026
10 checks passed
@2witstudios
2witstudios deleted the pu/mention-notifs branch May 9, 2026 03:19
2witstudios added a commit that referenced this pull request May 15, 2026
…1298)

* feat(notifications): fire @mention notifications for channel messages and tasks

When a user is @mentioned in a channel message (top-level or thread reply)
or in a task description (create or update), createMentionNotification is
called for each mentioned user who passes a canUserViewPage gate. Task
updates diff old vs new mentions so previously-notified users are not
re-notified. All notification calls are wrapped in try/catch so failures
never fail the API response after DB commit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(notifications): address review findings — best-effort delivery, logging, clean tests

- Switch notification Promise.all to per-call .catch() so each mention
  is attempted independently; one failure no longer blocks the rest
- Add loggers.api.error() to task routes (spec required error logging;
  silent catch was non-compliant)
- Remove redundant description type/length guard in tasks/route.ts —
  extractMentionedUserIds already handles empty/null safely
- Remove WHAT-comments on mention blocks; remove explicit :string
  annotation from mentionTargets.map
- Fix 3 vacuous task-update mention tests that passed for wrong reasons
  due to mockResolvedValue override: use explicit mockResolvedValueOnce
  chains so existingTask.description is distinct from the new value
- Fix loggers.api mock in taskId tests to expose .error() directly
- Assert createMentionNotification not called when alsoSendToParent is
  set (broad fan-out path suppresses targeted mention notification)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(test): add missing title field in mockNewTask

TypeScript infers transactionTaskResult as { id: string; title: string }[]
from the default value; our new mockNewTask objects were missing title.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(notifications): fire MENTION for @mentioned thread followers

Followers were excluded from `mentionTargets` (correct — to avoid
double-counting `channel_updated` unread), but this also suppressed
the durable MENTION notification for them. Split the logic: only
non-followers get `channel_updated`; all @mentioned non-sender users
(followers + non-followers who pass view check) get
`createMentionNotification`.

Adds a regression test for the follower-mention case.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(tasks): restore mockCreateMentionNotification after resetAllMocks

vi.resetAllMocks() clears the implementation, making .catch() call on
undefined throw a TypeError that is silently caught. Re-establish the
resolved-value implementation in beforeEach so the notification success
path is actually exercised.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(notifications): use task page ID in mention notifications

createMentionNotification uses the pageId to look up the page title and
build navigation links. Passing the task list pageId caused notifications
to display the list title and navigate to the list instead of the task.

- POST tasks: use result.page.id (the created task's own page)
- PATCH task: use existingTask.pageId (the task's own page)
- Permission gate: canUserViewPage now checks the task page, not the list

Update test assertions and descriptions to reflect the corrected page IDs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant