diff --git a/microsoft/skills/review/al-error-handling-review.md b/microsoft/skills/review/al-error-handling-review.md index 56bc0fe4..a3408079 100644 --- a/microsoft/skills/review/al-error-handling-review.md +++ b/microsoft/skills/review/al-error-handling-review.md @@ -22,6 +22,13 @@ An orchestrator invokes this skill with a `pr-diff`, `file-path`, or `folder-pat Use READ's **Bounded retrieval for review skills** workflow with `-Domain error-handling`. Consume every catalog page across enabled layers before applying this leaf's Relevance and Worklist; preserve each exact catalog path and open complete bodies only for exact paths selected by the Worklist. If the helper or prepared index is unavailable or invalid, use READ's explicit path-discovery and bounded native-read fallback. +When the review scope contains outbound `HttpClient.Get` or `HttpClient.Post` calls, including resolved call paths, also retrieve every catalog page with `-Domain web-services`, using the same known task dimensions and enabled layers. Restrict supplementary candidates to these article slugs across enabled layers; the links identify their canonical owners: + +- [`handle-httpclient-platform-failure-before-response-access`](../../knowledge/web-services/handle-httpclient-platform-failure-before-response-access.md) +- [`check-http-status-before-consuming-response-body`](../../knowledge/web-services/check-http-status-before-consuming-response-body.md) + +Retain each selected catalog row's exact `path`; do not invent paths for missing, pruned, or disabled entries. Apply this leaf's Relevance, Worklist, and READ layer precedence to the supplementary candidates before retrieving complete bodies with `Get-KnowledgeArticles.ps1`. Apply each selected article's own scope and exceptions when evaluating code and agent-finding candidates. Use READ's bounded path-discovery fallback over these same sources when needed. This supplements error-handling knowledge, not the scope of the review with unrelated web-services concerns. + ## Relevance Apply the frontmatter matching rules defined in READ (*Frontmatter matching semantics*) against the task context: @@ -40,6 +47,7 @@ Narrow the relevant files to the subset that applies to the changes under review - The changed AL object names and types — especially codeunits that post or validate, tables and table extensions with `OnValidate` triggers, and any procedure that raises errors or orchestrates a batch over records. - The changed procedures and triggers, weighted toward `OnValidate`/`OnInsert`/`OnModify` triggers, posting and validation routines, and procedures attributed with `[ErrorBehavior(...)]` or `[TryFunction]`. - Tokens extracted from the diff that relate to error surfacing and diagnostics (`Error`, `ErrorInfo`, `FieldError`, `TestField`, `Title`, `Message`, `DetailedMessage`, `AddAction`, `AddNavigationAction`, `RecordId`, `PageNo`, `ErrorBehavior`, `Collect`, `HasCollectedErrors`, `GetCollectedErrors`, `ClearCollectedErrors`, `ErrorType`, `Internal`, `Client`, `TryFunction`, `GetLastErrorText`, Boolean assignment). +- For the outbound HTTP call paths identified in Source, include `HttpClient`, `Get`, `Post`, `HttpResponseMessage`, response use, and caller failure handling (including `[TryFunction]` call sites) in keyword and topic matching. - Resolve changed standalone call targets; when the target declaration has `[TryFunction]`, worklist the ignored-return rule even if the declaration itself is unchanged. Only assignment and conditional use activate try semantics. A file enters the candidate worklist when its `keywords` intersect the extracted tokens or its topic (derived from the index entry's `path`, `title`, and `description`) matches a changed object type. Read an article's full file — its `## Best Practice` / `## Anti Pattern` bodies — only after it makes the worklist; candidate selection uses the index alone. diff --git a/tools/Test-KnowledgeRetrieval.ps1 b/tools/Test-KnowledgeRetrieval.ps1 index ef658125..568a4bd7 100644 --- a/tools/Test-KnowledgeRetrieval.ps1 +++ b/tools/Test-KnowledgeRetrieval.ps1 @@ -348,6 +348,60 @@ try { $indexPath = Join-Path $tmp 'knowledge-index.json' & $generator -BCQualityRoot $Root -IndexPath $indexPath | Out-Null $index = Get-Content -LiteralPath $indexPath -Raw -Encoding utf8 | ConvertFrom-Json + + # Check the declared finder route and real tool reachability, not model compliance. + $errorSkill = Get-Content -LiteralPath (Join-Path $Root 'microsoft/skills/review/al-error-handling-review.md') -Raw + $errorSource = [regex]::Match($errorSkill, '(?ms)^## Source\r?\n(.*?)(?=^## )').Groups[1].Value + $sourceDomains = @([regex]::Matches($errorSource, '-Domain ([a-z-]+)') | ForEach-Object { $_.Groups[1].Value }) + Assert-Sequence $sourceDomains @('error-handling', 'web-services') 'error-handling declares its own and supplementary HTTP catalogs' + foreach ($cue in @('HttpClient.Get', 'HttpClient.Post', 'resolved call paths', 'same known task dimensions and enabled layers')) { + Assert-True ($errorSource.Contains($cue)) "supplementary source retains '$cue'" + } + $httpArticleNames = @( + [regex]::Matches($errorSource, '\]\(\.\./\.\./knowledge/web-services/([a-z-]+\.md)\)') | + ForEach-Object { $_.Groups[1].Value } + ) + Assert-Sequence $httpArticleNames @( + 'handle-httpclient-platform-failure-before-response-access.md' + 'check-http-status-before-consuming-response-body.md' + ) 'supplementary source names only the two canonical HTTP articles' + $httpArguments = @{ + BCQualityRoot = $Root + IndexPath = $indexPath + EnabledLayers = @('microsoft', 'community', 'custom') + Technologies = @('al') + BCVersion = 28 + Countries = @('w1') + } + $ownCatalog = Invoke-CatalogPages -Arguments ($httpArguments + @{ Domain = $sourceDomains[0] }) + Assert-True (-not @($ownCatalog.candidates | Where-Object { $_.path -like '*/knowledge/web-services/*' }).Count) 'the primary catalog does not silently expand domains' + $httpCatalog = Invoke-CatalogPages -Arguments ($httpArguments + @{ Domain = $sourceDomains[1] }) + $httpRows = @($httpCatalog.candidates | Where-Object { $httpArticleNames -ccontains ($_.path -split '/')[-1] }) + $expectedHttpPaths = @( + $index.articles | + Where-Object { $_.domain -ceq 'web-services' -and $httpArticleNames -ccontains ($_.path -split '/')[-1] } | + ForEach-Object path | + Sort-Object + ) + foreach ($name in $httpArticleNames) { + Assert-True ($expectedHttpPaths -ccontains "microsoft/knowledge/web-services/$name") "canonical owner exists for $name" + } + Assert-Sequence @($httpRows.path | Sort-Object) $expectedHttpPaths 'supplementary selection preserves exact paths across layers' + Test-BodyRoundTrip -Paths $httpRows.path -IndexPath $indexPath + foreach ($excludedContext in @( + @{ EnabledLayers = @() } + @{ Technologies = @('javascript') } + )) { + $arguments = $httpArguments + @{ Domain = $sourceDomains[1] } + foreach ($key in $excludedContext.Keys) { + $arguments[$key] = $excludedContext[$key] + } + $catalog = Invoke-CatalogPages -Arguments $arguments + $selected = @($catalog.candidates | Where-Object { $httpArticleNames -ccontains ($_.path -split '/')[-1] }) + Assert-Equal $selected.Count 0 'supplementary selection respects disabled layers and nonmatching technology' + } + Write-Host 'HTTP source contract and exact-body reachability passed; model routing was not evaluated.' + $diskArticlePaths = @( foreach ($layer in 'microsoft', 'community', 'custom') { $knowledge = Join-Path $Root "$layer\knowledge"