Skip to content

UI knowledge: notification recall needs a known Id; open mixed-type documents through Page Management - #214

Merged
Jesper Schulz-Wedde (JesperSchulz) merged 4 commits into
microsoft:mainfrom
Curabis:community-contribution/r4-ui-notifications-and-page-routing
Oct 6, 2026
Merged

Jesper Schulz-Wedde (JesperSchulz) merged 4 commits into
microsoft:mainfrom
Curabis:community-contribution/r4-ui-notifications-and-page-routing

Conversation

@MichaelDieringer

Copy link
Copy Markdown
Contributor

Summary

Two ui articles. Both mistakes compile cleanly and look reasonable at a glance.

  • ui/notification-recall-needs-known-id.md
    • A notification sent without an Id gets one at Send() (Learn, Notification.Id). A later Recall() from a new variable can't target it, so the warning stays until the user dismisses it or the page closes (Learn, nonintrusive notifications).
    • One at a time, even across records: use a fixed GUID and Recall() before re-sending.
      • AnalysisView.ShowResetNeededNotification (lines 1039-1051) does this with a plain Send().
      • SalesLine.SendBlockedItemNotification (10126-10135) and Over-Receipt Mgt. (212-228) pass the fixed Id to "Notification Lifecycle Mgt.".SendNotification.
      • Learn doesn't document what Send() does with an Id that is already on screen, so the article doesn't rely on replacement. It quotes Learn's "can be recalled successfully even if it hasn't been sent" and lists the documented cases where Recall() returns false.
    • Notifications for several records visible at the same time: use codeunit 1511.
      • SendNotification calls CreateGuid() only when the Id is null, and tracks Id↔RecordId in the temporary "Notification Context" table (17-36).
      • RecallNotificationsForRecord recalls every tracked notification for the record (38-44).
      • The ...WithAdditionalContext pair takes a fixed GUID per reason, as Item-Check Avail. does (89-90, 636-646).
    • HandleDelayedInsert is documented from GetUsableRecordId (177-191). The Notification Lifecycle Handler delete subscribers pass false (27-52). Tables outside Base App need their own SetRecordID/UpdateRecordID/recall calls.
    • Explicitly not flagged: notifications that are never recalled (Learn's Sales Order example), Id-less sends through the lifecycle codeunit, and a fixed Id shared across records for a one-at-a-time warning.
  • ui/list-page-document-routing-uses-page-management.md
    • Sales List has no CardPageID. Its ShowDocument action calls PageManagement.PageRun(Rec) (188-202), as do Purchase List, Sales Lines and Navigate.
    • Resolution order (121-133): conditional card, then default card (existing record only), then conditional list, then lookup page. PageRun returns false without GuiAllowed.
    • A hand-written case "Document Type" / Page.Run on a routed table, directly or after Get, duplicates the mapping. It misses mappings Microsoft later adds to Page Management and routing that extensions add through its events.
    • New tables: register through OnConditionalCardPageIDNotFound, which is raised only for unrouted tables (line 258), as the Sustainability app does. Quality Management uses the IsHandled variant instead.
    • Base App still hand-rolls this in several places (Sales/Purchase Line Archive List, Copy Document Mgt. ShowSalesDoc/ShowPurchDoc, Office Document Handler), so severity is minor. Codeunit helpers are outside the UI page scope.
    • Not flagged: opening one known type (Opportunity → Sales Quote), lists with a fixed CardPageID (Sales Order List), and tables Page Management doesn't route (Assembly List).

Verification

  • Samples checked with alc 30.0 against Base App 28.2: no diagnostics.
  • BCApps links are pinned to 837ef802485ee457e52310d2ecaa08b93d0122fd, and every cited range was re-opened.
  • Learn pages checked: Notification.Id, Send and Recall, and Using nonintrusive notifications.

Wiring

  • al-ui-review.md: the entry gate also admits AL code that sends or recalls notifications, since Base App sends most of them from tables and codeunits. Such non-page files are checked only against notification knowledge.
  • Tokens are matched case-insensitively. The two high-signal mappings carry their exclusions in the cue.
  • Both pairs are registered in evaluation/review-fixtures.json.

Test plan

  • validate_frontmatter.py: 0 errors (2 warnings, both in files this PR doesn't touch)
  • Test-ReviewFixtures.ps1: 232 cases / 116 paired articles
  • Test-ReviewContract.ps1, Test-SkillIndex.ps1, Test-KnowledgeIndex.ps1, Test-KnowledgeRetrieval.ps1: pass

🤖 Generated with Claude Code

… routing

Two ui articles with compiled good/bad samples:
- notification-recall-needs-known-id: a notification that the code also
  recalls needs a fixed Id (single instance; recall before re-send) or
  per-record tracking through codeunit "Notification Lifecycle Mgt."
  (SendNotification[WithAdditionalContext] / RecallNotificationsForRecord,
  HandleDelayedInsert semantics). Never-recalled notifications are exempt.
- list-page-document-routing-uses-page-management: open documents from a
  mixed-type list with PageManagement.PageRun(Rec) instead of a hand-written
  case "Document Type" / Page.Run; register new tables through
  OnConditionalCardPageIDNotFound. Single-type opens and tables Page
  Management does not route are exempt.

Wired into al-ui-review (entry gate now covers notification send/recall
outside pages, tokens, high-signal mappings) and registered both pairs in
the ui review-fixtures override.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n, pinned links

- notification-recall-needs-known-id: a fixed Id shared across records is
  valid for one-at-a-time warnings (Sales Line blocked-item, Over-Receipt
  Mgt. pass a fixed Id to SendNotification after Recall); the per-record
  anti-pattern now requires several records' notifications to be visible
  at once. Recall wording follows Learn (including its false-return
  reasons) and cites Base App's recall-before-send practice.
- list-page-document-routing-uses-page-management: definition covers
  opening a routed table directly or after Get; cite archive line lists,
  Copy Document Mgt. ShowSalesDoc/ShowPurchDoc and Office handler; no
  "document types added later" overclaim (GetSalesHeaderPageID has no
  else for the extensible enum); full GetPageID resolution order; drop
  the IRS single-page subscriber.
- al-ui-review: non-page files admitted by the notification clause are
  checked only against notification knowledge; description updated;
  drop the "Document Type" token; case-insensitive token matching; cues
  aligned with both articles.
- Pin BCApps links to 837ef802485ee457e52310d2ecaa08b93d0122fd.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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.

Reviewed 5c15b08eebc3695940e129ed17df5b3270665d64. The Page Management mapping and notification lifecycle facts are generally sound, and local contract/retrieval checks pass. One notification false-positive boundary blocks merge.

notification-recall-needs-known-id.md:23,29 and al-ui-review.md:55 treat direct Send/Recall with no explicit Id or with CreateGuid as inherently unrecoverable. That is not true if the same Notification instance or its generated Id is retained. For example, a page can keep a global Notification, assign CreateGuid once in OnOpenPage, send it, and recall that same instance on a later action/OnClosePage. Likewise, Send assigns an initially unassigned Id; retaining the instance or saving that Id permits a later recall. The defect in the bad fixture is losing/replacing the sent Id across fresh local variables, not whether the Id is literal or runtime-generated. Notification Lifecycle Mgt. itself calls Send and then reads NotificationToSend.Id to retain the generated identity, confirming the relevant mechanism.

Please require evidence that the recalled identity differs from or cannot recover the sent identity, explicitly allow retained instances/saved generated IDs (including correctly tracked per-record IDs), and add those as clean controls. Recommend the lifecycle helper without making it mandatory for every otherwise-correct direct tracking implementation. No change to the Page Management rule is required.

… unassigned or generated Id

- notification-recall-needs-known-id: the defect is a Recall() whose Id
  cannot be the sent one (fresh local Notification, new CreateGuid at
  recall time) while neither the sent instance nor its Id is kept. A
  retained global instance (CreateGuid once in OnOpenPage, or Id left for
  Send to assign), a generated Id saved after Send and reassigned before
  Recall, and correctly tracked per-record Ids are explicitly not findings.
  Findings require evidence that the recalled identity differs from or
  cannot recover the sent identity. Notification Lifecycle Mgt. is
  recommended for per-record tracking, not mandatory. Cites VAT Bus. Post.
  Grp. Part, Certificate, and Data Search Lines, and the lifecycle
  helper's Send-then-read-Id sequence.
- good sample: adds a page with a retained global Notification (CreateGuid
  in OnOpenPage, Send in an action, Recall in a later action and
  OnClosePage) and a pageextension that saves the Send-assigned Id and
  recalls it from a later action. Bad sample comments name the lost
  identity.
- al-ui-review: notification cue requires that evidence and lists the
  retained-instance, saved-Id, and direct per-record tracking controls as
  exclusions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MichaelDieringer

Copy link
Copy Markdown
Contributor Author

Thanks, fixed in cff8917, plus a merge of current main in a37f45a.

  1. Evidence boundary. The article and the al-ui-review cue now define the defect as a Recall() whose Id cannot be the one that was sent. That means a fresh local Notification, or a new CreateGuid() at recall time, with neither the sent instance nor its Id kept anywhere. Before flagging, the reviewer must trace the recalled variable back to where its Id is assigned, and the sent variable forward to where its instance or Id is kept.

  2. Allowed cases and clean controls. Both files now list these explicitly as not this pattern:

    • a retained global or page instance (Id from CreateGuid() once in OnOpenPage, or left for Send() to assign)
    • a generated Id saved after Send() and reassigned before Recall()
    • per-record Ids tracked correctly without the helper

    The good sample adds a page with a retained global Notification (CreateGuid() in OnOpenPage, Send() in an action, Recall() in a later action and in OnClosePage). It also adds a pageextension that saves the Id Send() assigned and recalls it later. Both compile. Precedents cited:

    • VAT Bus. Post. Grp. Part: retained CreateGuid() instance
    • Certificate: retained instance, Id assigned by Send()
    • Data Search Lines: Id assigned by Send(), saved and reused for Recall()
    • Notification Lifecycle Mgt.: reads .Id after Send() to keep the identity
  3. Lifecycle helper. It is now recommended for per-record tracking, not required. The cue says not to flag correct direct tracking for not using it.

The Page Management article is unchanged. All validators pass, including Test-ReviewFixtures with -PrepareDirectory.

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.

Reviewed cff8917ecb2849f2406cdd8380cbb38228901770 against the previously reviewed head. The notification blocker is resolved: article and routing now require evidence that Recall cannot recover the sent identity, explicitly allowing retained Notification instances, saved Send-assigned/generated IDs and correct direct per-record tracking. The new clean controls exercise a global instance with CreateGuid once and a local Send whose ID is saved for a later Recall; these mechanisms match the cited VAT posting-group, Certificate and Data Search examples. Lifecycle management is recommended, not mandatory. The Page Management rule and its fixtures are unchanged, and main registrations are preserved. Exact-head local frontmatter, changed-path fixture preparation (248 cases), review contract, skill/schema and index/retrieval checks pass. No merge-critical issue remains. GitHub's substantive workflows are awaiting approval and should run before merge.

@JesperSchulz
Jesper Schulz-Wedde (JesperSchulz) merged commit 86d809b into microsoft:main Oct 6, 2026
7 checks passed
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.

2 participants