bcquality/microsoft/skills/review/al-telemetry-review.md
Jesper Schulz-Wedde 5480e891ff Merge main into review knowledge readiness
Resolve orchestration conflicts by preserving human-readable review domains through deduplication while retaining isolated leaf execution and citation-integrity safeguards.

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

Copilot-Session: 9825b012-e653-496a-9310-c1f4b6f8ac27
2026-07-15 10:53:52 +02:00

104 lines
11 KiB
Markdown

---
kind: action-skill
id: al-telemetry-review
version: 1
title: AL telemetry review
description: Performs an AL telemetry review against guidance from BCQuality.
inputs: [pr-diff, file-path]
outputs: [findings-report]
bc-version: [all]
technologies: [al]
countries: [w1]
application-area: [all]
---
# AL telemetry review
Reviews AL source changes against the `telemetry` knowledge domain in BCQuality and emits a findings report. This is a leaf action skill: it invokes no sub-skills. It is one of the skills composed by `al-code-review`.
An orchestrator invokes this skill with either a `pr-diff` (the standard PR-review entry point) or a `file-path` (single-file review). Telemetry findings are narrow by design — they apply when the diff emits, wraps, or changes custom telemetry through `Session.LogMessage`, `Session.LogError`, `FeatureTelemetry`, or related telemetry helpers. The skill returns `not-applicable` when none of those apply.
## Source
Read the BCQuality knowledge index once — the `knowledge-index.json` BCQuality builds at the root of the knowledge checkout (Entry's preparation step regenerates it over the live, already-filtered clone — see `skills/entry.md`). It lists every article that survived layer and allow/deny filtering and carries, per article, its `path`, `layer`, `domain`, frontmatter dimensions, `keywords`, `title`, and a one-line `description` hint — exactly the fields Relevance and Worklist consume. Take the index entries whose `domain` is `telemetry` as this skill's candidate set across every enabled Microsoft, community, and custom layer; do not open the individual article files at this step. Open an article's full body only once it enters the Worklist below, so a review reads the index plus the handful of worklisted articles instead of every file under `*/knowledge/telemetry/**`.
## Relevance
Apply the frontmatter matching rules defined in READ (*Frontmatter matching semantics*) against the task context:
- `bc-version` — the target BC version from the PR branch's `app.json` or the orchestrator-supplied version. If unavailable, the dimension is `unknown`.
- `technologies``[al]`.
- `countries` — the countries declared in the consuming app's `app.json`. Default to the orchestrator's configured context; if absent, `unknown`.
- `application-area` — the union of application areas declared by the changed objects. Pass the actual set; do not substitute `[all]`. If the area cannot be determined from the changes, the dimension is `unknown`.
Discard files that are not applicable. Retain conditionally applicable files (any dimension `unknown`) only when the orchestrator's configuration permits them; findings derived from those files MUST have `confidence` no higher than `medium`, AND the finding's `message` MUST name the dimension or dimensions that were unknown.
## Worklist
Narrow the relevant files to the subset that applies to the changes under review. For each relevant file, compute overlap against:
- The changed AL objects and procedures — especially telemetry wrapper codeunits, feature lifecycle instrumentation, error logging, integration diagnostics, and background/session processing.
- Calls to `Session.LogMessage`, `Session.LogError`, or `FeatureTelemetry` methods, weighted toward the event ID, verbosity, data classification, custom dimensions, and `TelemetryScope` arguments.
- Telemetry infrastructure codeunits that implement `"Telemetry Logger"` or subscribe to `"Telemetry Loggers".OnRegisterTelemetryLogger`.
- Tokens extracted from the diff that relate to telemetry (`Session.LogMessage`, `Session.LogError`, `FeatureTelemetry`, `TelemetryScope`, `ExtensionPublisher`, `All`, `Verbosity`, `Critical`, `Error`, `Warning`, `Normal`, `Verbose`, `DataClassification`, `CustomDimensions`, `Application Insights`, `Telemetry Logger`, `Telemetry Loggers`, `OnRegisterTelemetryLogger`, `LogUsage`, `LogError`, `LogUptake`, `Feature Uptake Status`, `Discovered`, `Set up`, `Used`, `Undiscovered`).
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. When the diff contains no telemetry-related changes by any of the above signals, return `outcome: "not-applicable"` without evaluating files.
The following targeted checks cover every current `telemetry` article. Treat each as a candidate-selection cue:
- A `Session.LogMessage` event ID is empty, generated dynamically, reused for different events, changed on an existing event, or uses a placeholder such as `0000`, `1234`, `TODO`, or `XX0000``telemetry-event-id-stable-unique`.
- `TelemetryScope::All` is used for a clearly publisher-only implementation diagnostic, or `ExtensionPublisher` hides a clearly customer-actionable failure from environment telemetry — `choose-telemetry-scope-by-audience`. Do not infer the audience when the message and surrounding branch are ambiguous.
- An explicit failure branch logs through `Session.LogMessage` with `Verbosity::Normal` or `Verbose`, or a non-error event is inflated to `Error`/`Critical``match-verbosity-to-signal-severity`.
- A new feature's visible uptake calls skip `Discovered` or `Set up`, jump directly to `Used`, or use inconsistent feature-name literals across states — `feature-uptake-transitions-in-order`. Require repository-level lifecycle evidence; one isolated call is not proof.
- `FeatureTelemetry.LogUsage` runs before success is known or on a failure path — `feature-usage-only-after-success`. `LogUptake(...Used)` records an attempt and is not this anti-pattern.
- A complete app or app family uses `FeatureTelemetry` without any registered `"Telemetry Logger"`, or registers more than one implementation for the same publisher — `register-one-telemetry-logger-per-publisher`. Absence requires repository/app-family context.
- A custom-dimension key contains spaces or non-PascalCase naming, or an existing event ID changes/removes a shipped key — `keep-custom-dimension-schema-stable`. Treat naming alone as advisory; the schema change is the compatibility defect.
Once the candidate worklist is known, resolve layer-precedence conflicts per READ. Drop lower-precedence files whose normative guidance (`## Best Practice` or `## Anti Pattern`) directly contradicts a higher-precedence candidate, and record each dropped file in `suppressed` with `reason: "layer-precedence"`. Files that would have been candidates but are hidden because their layer is disabled in consumer configuration are recorded with `reason: "configuration"`. Files that never became candidates are NOT recorded in `suppressed`.
When the post-conflict worklist is empty because no applicable telemetry knowledge exists, or because configuration suppressed every candidate, emit `outcome: "no-knowledge"`. When the worklist is empty because no applicable telemetry knowledge matched the changes, emit `outcome: "completed"` with an empty `findings` array.
## Action
For each worklist entry, evaluate the diff against the file's `## Best Practice` and `## Anti Pattern` sections. Emit findings as follows:
- When the diff contains a clear match for an Anti Pattern, emit a finding with severity `major` or `blocker`, a message summarizing the anti-pattern, `location` pointing to the offending line or range, and a `references` entry pointing to the knowledge file. Use `blocker` only when the knowledge file states the anti-pattern violates a platform-level guarantee; otherwise the ceiling is `major`.
- When the diff contains code that contradicts a Best Practice without being a full anti-pattern, emit `minor` with the same reference shape.
- Applicability alone is not a finding. Emit `info` only for a concrete, non-actionable observation the article explicitly defines; otherwise emit nothing when no violation is present.
Set `confidence` to:
- `high` when the detection is based on an unambiguous API and `TelemetryScope` argument.
- `medium` when determining whether a signal is customer-actionable requires heuristic interpretation or when any frontmatter dimension was `unknown`.
- `low` when the finding is an advisory derived only from applicability.
After evaluating each worklist entry, also consider whether the diff exhibits a telemetry defect the agent recognises from its general AL knowledge that no knowledge file in the worklist covers. Such candidates are agent findings within this skill's domain — emit them with `references: []`, an `id` slug prefixed with `agent:`, `confidence` capped at `medium`, `severity` capped at `minor` (agent findings are advisory and non-gating), and a `message` that is self-contained (describing both the issue and a concrete recommendation, since there is no knowledge-file footer for the consumer to fall back on). Hold every candidate to the precision bar in `skills/do.md` (*Agent findings*): emit only a concrete, material telemetry defect a knowledgeable BC reviewer would agree is wrong — steelman it first and drop anything stylistic, speculative, dependent on code outside the diff, or merely a valid alternative; when in doubt, omit. The scope is strictly telemetry; defects outside this domain belong to other leaves and MUST NOT be emitted here. Before emitting, check the worklist for a knowledge file that matches the candidate — if one exists, upgrade the candidate to a knowledge-backed finding instead. See `skills/do.md` for the full contract.
For every emitted finding, decide whether the fix is mechanical. A fix is mechanical when it is small, local, and unambiguous from the diff context (for example: replace `TelemetryScope::All` with `TelemetryScope::ExtensionPublisher` for a clearly publisher-only diagnostic). For mechanical findings, emit `findings[].suggested-code` with the literal replacement for the source lines indicated by `location`. The payload must be a verbatim replacement — no diff markers, no fences, no commentary — that the consumer can render as a one-click suggestion. When a `.good.al` companion exists and the diff context matches the `.bad.al` shape, adapt the `.good.al` replacement into `suggested-code`.
Omit `suggested-code` only when the appropriate fix depends on context the skill cannot determine, when multiple defensible replacements exist, or when the fix spans non-contiguous code. If a finding is mechanical-looking but you omit `suggested-code`, set `findings[].suggested-code-omission-reason` to a short explanation. See `skills/do.md` for the full contract.
Outcome selection:
- `completed` — the skill evaluated every worklist item.
- `no-knowledge` — no applicable telemetry knowledge survived filtering.
- `not-applicable` — the diff touches no telemetry emission, wrapper, or feature-instrumentation surface.
- `partial` — a budget was hit before the worklist was exhausted.
- `failed` — an unrecoverable error occurred.
## Output
Output conforms to the DO output contract. Every finding this skill emits MUST set `findings[].domain` to `"Telemetry"`. The empty-corpus case produces:
```json
{
"skill": { "id": "al-telemetry-review", "version": 1 },
"outcome": "no-knowledge",
"summary": {
"counts": { "blocker": 0, "major": 0, "minor": 0, "info": 0 },
"coverage": { "worklist-size": 0, "items-evaluated": 0 }
},
"findings": [],
"suppressed": []
}
```