Skip to content

Refine self-improvement review guidance - #132

Merged
Wenjie Fan (gggdttt) merged 4 commits into
mainfrom
gggdttt-refine-self-improvement-guidance
Sep 3, 2026
Merged

Refine self-improvement review guidance#132
Wenjie Fan (gggdttt) merged 4 commits into
mainfrom
gggdttt-refine-self-improvement-guidance

Conversation

@gggdttt

@gggdttt Wenjie Fan (gggdttt) commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Summary

Refine the second self-improvement batch into evidence-backed BCQuality guidance rather than copying reaction-generated changes verbatim.

  • narrow IsHandled reset findings to values that can actually carry true, including loop-carried state
  • retire local Label scope as a correctness/localization rule
  • allow semantic capture/reset/assert UI-handler tests and reserve queues for interaction contracts
  • require restart-safe persisted checkpoints without weakening bounded retrieval
  • align ModifyAll/DeleteAll fallback guidance with documented platform conditions

False-positive boundaries

  • A fresh local Boolean is already false for one non-looping raise. A local declared outside a loop initializes once and can carry true across iterations. A later raise reached only after a semantically valid if IsHandled then exit; remains proven false.
  • Independent event seams use independent handled state so one handled event does not suppress a downstream publisher.
  • Procedure-local Labels are supported and included in the extension translation pipeline; object scope is only a possible maintainability convention.
  • [HandlerFunctions] proves listed handlers execute. Missing semantic verification is minor; queue storage is not mandatory for every handler. Fixtures cover omitted handlers, listed-but-unreached handlers, and meaningful capture/assert verification.
  • Persisted retry progress and bounded next-N retrieval are separate requirements. A full-tail FindSet remains unbounded, and the checkpoint sample initializes its persisted watermark on cold start.
  • Progress UX permits an explicit row loop only when the equivalent bulk API already falls back to individual operations and semantics are preserved. DeleteAll guidance includes trigger code, related subscribers, security filtering, Media/MediaSet, and companion-field fallback conditions.

Validation

  • python .github/scripts/validate_frontmatter.py --root .
  • tools/Test-ReviewFixtures.ps1 -Root . -PrepareDirectory <temp>
  • .github/scripts/Test-KnowledgeIndex.ps1 -Root .
  • git diff --check

Deliberately unchanged

  • internal-access-is-not-a-security-boundary
  • ErrorInfo boundary guidance
  • the PR #7938 unreachable-case candidate
  • no swallowed-handler-assertion warning
  • existing article slugs and paths

Narrow IsHandled, label-scope, UI-handler, checkpoint, and bulk-operation guidance to evidence-backed false-positive boundaries.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Preserve independent event seams, cover loop-carried handled state, strengthen checkpoint and UI-handler fixtures, and align DeleteAll fallback guidance.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 10646e50-2d8b-4cca-b02b-dfa78629e6a1
@gggdttt

Copy link
Copy Markdown
Collaborator Author

Gentle ping — this has been open since 18 August with all checks green and no review yet.

Context on why it is shaped the way it is, in case the size is what is holding it up. The substance is five knowledge articles, corrected after adjudicating false positives from the PR-review self-improvement runs on BCApps 9067, 7938 and 8553:

  • events/initialize-ishandled-to-false-before-publishing — tighten the reset requirement to the case that actually needs it. A fresh local Boolean is initialised once per procedure invocation, so a non-looping single raise does not need an explicit reset; a raise inside a loop does, because the value is carried across iterations. Also stops the .good.al sample from using one broad exit that suppresses independent downstream event seams.
  • style/labels-declared-at-object-scope — drop the blanket rule and the two samples. A procedure-local Label is legitimate, so the previous wording produced false positives.
  • testing/ui-handlers-in-tests — allow a handler to capture meaningful state and assert on it after the run, instead of requiring it to be empty.
  • performance/avoid-commit-inside-loops and the two modifyall articles — separate restart-safe checkpointing from bounded retrieval, and limit the bulk-operation progress-loop exemption.

The eight microsoft/skills/review/*.md edits are one-line cue updates that follow from those articles, and the single skills/do.md line just removes "moving a local Label to object scope" from the mechanical-fix examples, since that is no longer a finding after the labels-declared-at-object-scope change.

If the skills/do.md line is the blocker because that file needs both maintainers, I am happy to split it out so the knowledge and skill-cue changes can land first. This PR is currently blocking one further candidate from a later run, so an unblock in either direction is useful.

…arrowed scope

The article was rewritten to say a reset is required only when the value can
carry over, and its H1 was updated to match, but three artefacts still carried
the old "always initialize to false" premise:

- The slug still read `initialize-ishandled-to-false-before-publishing`, which
  contradicts the body. The slug is not cosmetic: Build-KnowledgeIndex.ps1
  ranks candidates on keywords, frontmatter dimensions, domain, path and title,
  so a stale path pushes selection back toward the behaviour this change
  narrows. Renamed to `reset-ishandled-only-when-the-value-can-carry-over`,
  following the existing precedent for conditional slugs such as
  `unreleased-symbol-change-is-not-a-breaking-change`.
- Keywords still listed `initialization` and `deterministic` and omitted
  `false-positive`, the tag this repository uses for suppression articles.
  Replaced with `carry-over` and `loop-iteration` and added `false-positive`.
- The good sample demonstrated only the "prefer separate fresh locals" clause
  and contained no reset at all, so the article's headline case had no positive
  example. It was also asymmetric with the bad sample, which gained a loop
  procedure showing a local that carries `true` into the next iteration.

Added the matching loop procedure to the good sample: a local declared outside
the loop is reset at the top of each iteration. That case cannot be solved by
introducing another local, because AL has no block scope, so it is the only
shape that demonstrates the reset the article still requires. It also gives the
engine the correct `suggested-code` shape for the loop finding; without it the
one-click fix adapted from the good sample would propose splitting the variable
rather than adding one line.

Also renamed the sample codeunits from "IsHandled Init ..." to
"IsHandled Carry Over ...", and updated the two references to the old slug:
the events leaf skill cue and the events pin in evaluation/review-fixtures.json.

validate_frontmatter.py reports 0 errors; Test-ReviewFixtures.ps1 passes with
32 cases across 16 leaf domains and resolves the events fixture to the renamed
article.

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.

One blocking false-positive boundary remains in the UI-handler guidance.

microsoft/knowledge/testing/ui-handlers-in-tests.md now says every listed handler must execute, and microsoft/skills/review/al-testing-review.md requires [HandlerFunctions] to exactly match invoked handlers. The linked Microsoft documentation is narrower: every nonoptional handler must execute, and it explicitly permits send-notification and recall-notification handlers to be optional. As written, agents can flag or remove a deliberately unused optional notification handler.

Please qualify the article's two-sided-contract wording and the review cue to exempt optional SendNotificationHandler/RecallNotificationHandler entries (and ideally encode that boundary in the fixture). The rest of the event-state, Label-scope, checkpoint, bulk-operation, and semantic UI-verification changes look sound.

…tion rule

The narrowed UI-handler guidance still stated the execution rule without the
qualifier the linked Microsoft reference uses. The article said every listed
handler must execute at least once, and the testing leaf skill asked for
`[HandlerFunctions(...)]` to match the invoked handlers exactly. The reference
says every *nonoptional* listed handler must execute, and that send-notification
and recall-notification handlers can be optional. As written, an agent could
flag a deliberately unused optional notification handler.

The discriminator is narrower than the handler type. Both
`[SendNotificationHandler([HandlerIsOptional: Boolean])]` and
`[RecallNotificationHandler([HandlerIsOptional: Boolean])]` take an explicit
optionality argument, so `[SendNotificationHandler(true)]` is exempt while the
same attribute written without the argument stays nonoptional like every other
handler type. Keying the exemption on the argument rather than the type keeps it
checkable from the diff and avoids the opposite false positive, where an agent
stops flagging genuinely nonoptional notification handlers.

Changes:

- The article now states the nonoptional qualifier, explains that optionality is
  declared rather than inferred, and adds an explicit do-not-flag clause. That
  clause also forbids proposing removal, because the listed entry is what keeps
  the test passing on the runs where the notification does fire.
- The testing leaf skill carries the same boundary in its `ui-handlers-in-tests`
  cue, and its mechanical-fix list no longer allows removing a listed optional
  notification handler as a one-click suggestion.
- `SendNotificationHandler` and `RecallNotificationHandler` were missing from the
  skill's testing token list, so notification handlers were not reliably
  surfaced to the relevance step at all. Both are now listed.
- The good sample gains a test that lists an unreached
  `[SendNotificationHandler(true)]`; the bad sample gains the mirror image, an
  unreached `[SendNotificationHandler]` with no optionality argument. The pair
  differs only by that argument, which is the point.
- `evaluation/review-fixtures.json` pins the testing domain to
  `ui-handlers-in-tests` so the boundary is exercised: the good sample is the
  clean control at `minimumCleanRate` 1.0 and the bad sample is the expected
  finding. Keywords were retagged with `notification` and `optional-handler`.

validate_frontmatter.py reports 0 errors; Test-ReviewFixtures.ps1 passes with
32 cases across 16 leaf domains and resolves the testing fixture to this article.
@gggdttt

Copy link
Copy Markdown
Collaborator Author

Thanks, you caught a real bug. Fixed in c213f14.

You were right that the article was too strict, but the rule turned out to be a bit narrower than "notification handlers are exempt", so I want to explain what I did.

Optional is something you declare, not something the handler type gives you. The attribute takes a boolean: [SendNotificationHandler([HandlerIsOptional: Boolean])], same for RecallNotificationHandler. So [SendNotificationHandler(true)] is optional, but [SendNotificationHandler] written plain is nonoptional like any other handler. If I had exempted all notification handlers, I would have traded a false positive for a false negative.

The docs never say what the default is when you leave the argument out, so I counted the real usage in microsoft/BCApps on origin/main:

form count
[SendNotificationHandler(true)] 10
[SendNotificationHandler(false)] 0
[SendNotificationHandler] 359
[RecallNotificationHandler(true)] / (false) 0 / 0
[RecallNotificationHandler] 103

Ten people wrote (true) on purpose and nobody ever wrote (false). That only makes sense if the plain form is nonoptional, otherwise those ten annotations do nothing. So the .bad.al case is now the same test as .good.al with only that one argument removed.

The article had a second way to produce this false positive. I built a small synthetic PR with a [SendNotificationHandler(true)] that the test path never triggers, then ran the engine twice per side and changed nothing but the BCQuality tree:

round BCQuality findings testing leaf
1 origin/main 1 blocker worklist=2, 1 finding
2 origin/main 1 blocker worklist=2, 1 finding
1 this PR 0 worklist=2, 0 findings
2 this PR 0 worklist=2, 0 findings

Both baseline runs flagged the handler, but not for the reason you expected. Neither one complained that it never executed. They complained it had no enqueue/dequeue and no LibraryVariableStorage.AssertEmpty, because the old Best Practice made those mandatory for every handler. Asking a test to assert an empty queue for a notification that may never fire does not make sense. The article now asks for queue storage only when order, count, text, replies, or a scripted sequence is actually part of the contract, and the Anti Pattern says not to flag its absence on its own.

Worth noting: in both candidate runs the testing leaf still loaded and evaluated the article (worklist=2, evaluated=2) and returned nothing. So it is suppressed on purpose, not just missed during retrieval.

The part that worried me more was in the skill, not the article. al-testing-review.md had "remove a handler name in HandlerFunctions" in its mechanical-fix list, and under the do.md contract that renders as a one-click suggestion. So the agent would not just flag a deliberately optional notification handler, it would hand the developer a button to delete it. One click, and the test breaks on every run where the notification does fire. That entry is now excluded for optional notification handlers. On top of that, the token list used for relevance had no SendNotificationHandler or RecallNotificationHandler in it at all, so the skill could not even see them. Both are added.

Fixture. evaluation/review-fixtures.json now pins the testing domain to ui-handlers-in-tests, so this pair is the domain's control. .good.al has a listed but never raised [SendNotificationHandler(true)] and has to stay clean. .bad.al has the plain nonoptional form on a path that is never reached and has to be flagged. Neither sample has explanatory comments, so the clean control stays honest.

One thing I should flag: [RecallNotificationHandler(true)] has zero precedent in BCApps. The docs give it the same signature as SendNotificationHandler, so I covered it the same way, but that half is based on the documentation rather than on code anyone has actually written.

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.

The update resolves the optional-handler false positive precisely.

  • Optionality is keyed to the explicit HandlerIsOptional argument, so [SendNotificationHandler(true)] and [RecallNotificationHandler(true)] may remain listed without executing, while the plain nonoptional forms still must execute.
  • The reviewer no longer proposes deleting optional notification handlers.
  • Relevance tokens and the paired good/bad fixture now exercise the exact boundary.

The rest of the previously reviewed guidance remains sound.

@gggdttt
Wenjie Fan (gggdttt) merged commit 1a5afdc into main Sep 3, 2026
6 checks passed
@gggdttt
Wenjie Fan (gggdttt) deleted the gggdttt-refine-self-improvement-guidance branch September 3, 2026 14:12
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.

3 participants