From 406d58463955aaf9e906ce1dd3a10b7773633d19 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Thu, 30 Apr 2026 16:06:25 -0300 Subject: [PATCH 1/3] docs: Add Azure DevOps work item markdown formatting instructions - Create ado-work-items-markdown.instructions.md with safe patterns for markdown description updates - Document two-step conversion for changing field format without data loss - Include newline integrity checks and batch verification scripts - Update AGENTS.md to link new instruction guide for discoverability --- .../ado-work-items-markdown.instructions.md | 129 ++++++++++++++++++ AGENTS.md | 10 ++ 2 files changed, 139 insertions(+) create mode 100644 .github/instructions/ado-work-items-markdown.instructions.md diff --git a/.github/instructions/ado-work-items-markdown.instructions.md b/.github/instructions/ado-work-items-markdown.instructions.md new file mode 100644 index 0000000000..419faeff0b --- /dev/null +++ b/.github/instructions/ado-work-items-markdown.instructions.md @@ -0,0 +1,129 @@ +--- +applyTo: "**" +--- +# Azure DevOps Work Items: Markdown Description Rules + +Use this guide whenever creating or updating Azure DevOps work items that include rich text in `System.Description`. + +## Goals + +- Ensure descriptions render as Markdown (not HTML/plain text) +- Preserve newline characters and list structure +- Verify work items after every batch update + +## Required Behavior + +1. Always use `az rest` for description content-type changes. +2. Use `application/json-patch+json` for PATCH requests. +3. Set `multilineFieldsFormat.System.Description` to `markdown`. +4. Preserve exact newlines in the Markdown body. +5. Verify both format and newline integrity after updates. + +## Authentication and Resource + +Use Azure DevOps resource audience when calling `az rest`: + +- Resource: `499b84ac-1321-427f-aa17-267ca6975798` + +Example auth check: + +```bash +az rest \ + --method GET \ + --resource 499b84ac-1321-427f-aa17-267ca6975798 \ + --url "https://dev.azure.com//_apis/projects?api-version=7.1-preview.4" +``` + +## Safe Update Pattern (Prevents Type/Value Errors) + +Some work items reject a direct type switch unless a valid value is provided. Use this two-step process: + +### Step 1: Capture current description + +```bash +desc=$(az boards work-item show --id | jq -r '.fields["System.Description"] // ""') +``` + +### Step 2: Force markdown type with temporary empty value + +```bash +jq -n '[ + {"op":"replace","path":"/fields/System.Description","value":""}, + {"op":"replace","path":"/multilineFieldsFormat/System.Description","value":"markdown"} +]' >/tmp/patch-step1.json + +az rest \ + --method PATCH \ + --resource 499b84ac-1321-427f-aa17-267ca6975798 \ + --url "https://dev.azure.com///_apis/wit/workitems/?api-version=7.1-preview.3" \ + --headers "Content-Type=application/json-patch+json" \ + --body @/tmp/patch-step1.json +``` + +### Step 3: Restore exact Markdown text + +```bash +jq -n --arg d "$desc" '[ + {"op":"replace","path":"/fields/System.Description","value":$d} +]' >/tmp/patch-step2.json + +az rest \ + --method PATCH \ + --resource 499b84ac-1321-427f-aa17-267ca6975798 \ + --url "https://dev.azure.com///_apis/wit/workitems/?api-version=7.1-preview.3" \ + --headers "Content-Type=application/json-patch+json" \ + --body @/tmp/patch-step2.json +``` + +## Newline Integrity Checks + +After updates, confirm newline characters are still present and structure was not flattened. + +### Check format and description sample + +```bash +az boards work-item show --id | jq '.multilineFieldsFormat, .fields["System.Description"][0:200]' +``` + +Expected: + +- `multilineFieldsFormat.System.Description == "markdown"` +- Description text contains `\n` where line breaks are expected + +### Check line count did not collapse + +```bash +az boards work-item show --id \ +| jq -r '.fields["System.Description"]' \ +| awk 'END { print NR }' +``` + +If a multi-line description unexpectedly returns `1`, newline content was likely lost. + +## Batch Verification Script + +Use this after bulk updates: + +```bash +python3 - <<'PY' +import json, subprocess +ids = [44787, 44794] # replace with your target IDs +bad = [] +for i in ids: + out = subprocess.check_output(["az", "boards", "work-item", "show", "--id", str(i)], text=True) + j = json.loads(out) + fmt = (j.get("multilineFieldsFormat") or {}).get("System.Description") + desc = j.get("fields", {}).get("System.Description") or "" + if fmt != "markdown" or "\n" not in desc: + bad.append((i, fmt, "has_newlines" if "\n" in desc else "missing_newlines")) +print("noncompliant:", len(bad)) +for row in bad: + print(row) +PY +``` + +## Common Failure Modes + +- `401` or `TF400813`: wrong token audience or insufficient auth context +- `Content-Type ... not supported`: must use `application/json-patch+json` +- `type changed without a value`: use two-step pattern (empty + markdown type, then restore text) diff --git a/AGENTS.md b/AGENTS.md index 690e9c9c8d..409523b444 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,6 +5,7 @@ This document provides guidance for AI coding agents working with the Microsoft. ## Quick Start ### Essential Context Files + Before making changes, agents should be aware of: | File | Purpose | @@ -15,6 +16,7 @@ Before making changes, agents should be aware of: | [.github/copilot-instructions.md](.github/copilot-instructions.md) | Copilot-specific instructions | ### Detailed Technical Instructions + The `.github/instructions/` directory contains comprehensive guides: | Guide | Coverage | @@ -29,6 +31,7 @@ The `.github/instructions/` directory contains comprehensive guides: | [features.instructions.md](.github/instructions/features.instructions.md) | Feature reference, keywords | | [documentation.instructions.md](.github/instructions/documentation.instructions.md) | Documentation and samples | | [external-resources.instructions.md](.github/instructions/external-resources.instructions.md) | Docs links, version matrix, external references | +| [ado-work-items-markdown.instructions.md](.github/instructions/ado-work-items-markdown.instructions.md) | Ensure Azure DevOps work item descriptions are Markdown and preserve newlines | ## Workflow Prompts @@ -66,6 +69,7 @@ Do **not** create branches directly under `main`, `dev/`, or any other top-level ## Common Tasks ### Bug Fix Workflow + 1. Understand the issue from the bug report 2. Locate relevant code in `src/Microsoft.Data.SqlClient/src/` (do NOT modify legacy `netcore/src/` or `netfx/src/`) 3. Write a failing test that reproduces the issue @@ -74,6 +78,7 @@ Do **not** create branches directly under `main`, `dev/`, or any other top-level 6. Update documentation if behavior changes ### Feature Implementation + 1. Review the feature specification 2. Plan the implementation (see `implement-feature` prompt) 3. Update reference assemblies if adding public APIs @@ -82,6 +87,7 @@ Do **not** create branches directly under `main`, `dev/`, or any other top-level 6. Do not edit `CHANGELOG.md` directly; instead, add a suggested release-note entry (per `.github/copilot-instructions.md`) in the PR description or via the release-notes workflow/prompt. ### Adding Connection String Keywords + 1. Add to `SqlConnectionStringBuilder` 2. Update connection string parser 3. Default to backward-compatible value @@ -89,6 +95,7 @@ Do **not** create branches directly under `main`, `dev/`, or any other top-level 5. Document in feature reference ### Protocol Changes + 1. Reference MS-TDS specification 2. Update `TdsEnums.cs` for new constants 3. Implement in `TdsParser.cs` and related files @@ -96,6 +103,7 @@ Do **not** create branches directly under `main`, `dev/`, or any other top-level 5. Consider backward compatibility ### Performance Optimization + 1. Profile the issue using benchmarks or traces 2. Identify allocation hotspots (see `perf-optimization` prompt) 3. Apply patterns: `ArrayPool`, `Span`, static/cached instances, source generation @@ -105,6 +113,7 @@ Do **not** create branches directly under `main`, `dev/`, or any other top-level ### Key Documentation Links + - [Microsoft.Data.SqlClient on Microsoft Learn](https://learn.microsoft.com/sql/connect/ado-net/introduction-microsoft-data-sqlclient-namespace) - [MS-TDS Protocol Specification](https://learn.microsoft.com/openspecs/windows_protocols/ms-tds) - [SQL Server Documentation](https://learn.microsoft.com/sql/sql-server/) @@ -112,6 +121,7 @@ Do **not** create branches directly under `main`, `dev/`, or any other top-level ## Repository Policies See the `policy/` directory for: + - [coding-best-practices.md](policy/coding-best-practices.md) - Programming standards - [coding-style.md](policy/coding-style.md) - Code formatting guidelines - [review-process.md](policy/review-process.md) - PR review requirements From 9581de89f43c546c037b2a216db0db91cc7662b6 Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Tue, 5 May 2026 16:53:12 -0300 Subject: [PATCH 2/3] docs: address PR 4253 review feedback in ADO markdown guide --- .../ado-work-items-markdown.instructions.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/instructions/ado-work-items-markdown.instructions.md b/.github/instructions/ado-work-items-markdown.instructions.md index 419faeff0b..b9db7a8d7f 100644 --- a/.github/instructions/ado-work-items-markdown.instructions.md +++ b/.github/instructions/ado-work-items-markdown.instructions.md @@ -34,6 +34,8 @@ az rest \ --url "https://dev.azure.com//_apis/projects?api-version=7.1-preview.4" ``` +Note: API versions can differ by endpoint. The examples below use `7.1-preview.3` for work item PATCH calls, while this auth check uses `7.1-preview.4`. + ## Safe Update Pattern (Prevents Type/Value Errors) Some work items reject a direct type switch unless a valid value is provided. Use this two-step process: @@ -47,32 +49,36 @@ desc=$(az boards work-item show --id | jq -r '.fields["System.Description"] ### Step 2: Force markdown type with temporary empty value ```bash +PATCH_STEP1_FILE="${PATCH_STEP1_FILE:-./patch-step1.json}" + jq -n '[ {"op":"replace","path":"/fields/System.Description","value":""}, {"op":"replace","path":"/multilineFieldsFormat/System.Description","value":"markdown"} -]' >/tmp/patch-step1.json +]' >"$PATCH_STEP1_FILE" az rest \ --method PATCH \ --resource 499b84ac-1321-427f-aa17-267ca6975798 \ --url "https://dev.azure.com///_apis/wit/workitems/?api-version=7.1-preview.3" \ --headers "Content-Type=application/json-patch+json" \ - --body @/tmp/patch-step1.json + --body @"$PATCH_STEP1_FILE" ``` ### Step 3: Restore exact Markdown text ```bash +PATCH_STEP2_FILE="${PATCH_STEP2_FILE:-./patch-step2.json}" + jq -n --arg d "$desc" '[ {"op":"replace","path":"/fields/System.Description","value":$d} -]' >/tmp/patch-step2.json +]' >"$PATCH_STEP2_FILE" az rest \ --method PATCH \ --resource 499b84ac-1321-427f-aa17-267ca6975798 \ --url "https://dev.azure.com///_apis/wit/workitems/?api-version=7.1-preview.3" \ --headers "Content-Type=application/json-patch+json" \ - --body @/tmp/patch-step2.json + --body @"$PATCH_STEP2_FILE" ``` ## Newline Integrity Checks @@ -107,7 +113,7 @@ Use this after bulk updates: ```bash python3 - <<'PY' import json, subprocess -ids = [44787, 44794] # replace with your target IDs +ids = [12345, 12346] # replace with your target IDs bad = [] for i in ids: out = subprocess.check_output(["az", "boards", "work-item", "show", "--id", str(i)], text=True) From 5fc9bec79878dccabd4fb57fc49d1777681aa75a Mon Sep 17 00:00:00 2001 From: Paul Medynski <31868385+paulmedynski@users.noreply.github.com> Date: Tue, 5 May 2026 17:00:41 -0300 Subject: [PATCH 3/3] - Added a prompt to help review PR feedback. - Tested it with this PRs comments. --- .github/prompts/review-pr-feedback.prompt.md | 123 +++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 .github/prompts/review-pr-feedback.prompt.md diff --git a/.github/prompts/review-pr-feedback.prompt.md b/.github/prompts/review-pr-feedback.prompt.md new file mode 100644 index 0000000000..c14a7b96cb --- /dev/null +++ b/.github/prompts/review-pr-feedback.prompt.md @@ -0,0 +1,123 @@ +--- +name: review-pr-feedback +description: Uses gh CLI to collect unresolved PR review feedback, optionally includes discussion comments, applies fixes, and reports status. +argument-hint: pr= repo= includeDiscussionComments= authorFilter= testScope= +tools: ['edit/editFiles', 'edit/createFile', 'read/readFile', 'read/problems', 'search/codebase', 'search/textSearch', 'search/fileSearch', 'execute/runInTerminal', 'execute/getTerminalOutput'] +--- +You are an expert software maintenance agent focused on resolving pull request feedback quickly, safely, and with clear traceability. + +## Context +- Workspace root: ${workspaceFolder} +- Target PR: ${input:pr} +- Optional repository override: ${input:repo} +- Include non-review discussion comments: ${input:includeDiscussionComments} +- Optional author filter: ${input:authorFilter} +- Optional focused testing hint: ${input:testScope} +- Optional selected context: ${selection} + +## Skills +#skill:generate-mstest-filter + +Use this skill when building a dotnet test filter: +- [generate-mstest-filter](.github/skills/generate-mstest-filter/SKILL.md) + +Follow the referenced skill instructions before producing any custom filter. + +## Task +1. Validate prerequisites +- Confirm gh CLI is installed and authenticated. +- Resolve repository from ${input:repo}, or infer from git remote. +- Resolve PR number from ${input:pr} (accept number or URL). +- Discover the correct git remote name from the current repository and store it for later commands. +- Use that discovered remote name for push and any other git operations that require a remote; do not assume `origin`. + +2. Gather actionable review feedback +- Query PR review threads with gh api GraphQL. +- Keep only unresolved threads where isResolved is false. +- Extract thread id, file path, line/startLine, comment url, author login, and body. +- If ${input:authorFilter} is provided, apply it case-insensitively. + +3. Optionally gather non-review discussion comments +- If ${input:includeDiscussionComments} is true, fetch PR issue comments. +- Mark these as Informational because they do not have open/resolved state. +- Apply ${input:authorFilter} if provided. + +4. Build an implementation plan +- Group unresolved review feedback by file and risk. +- Determine minimal safe edits needed. +- Identify comments that are non-actionable or ambiguous. +- Ask the user to confirm the plan before proceeding, showing a concise summary of proposed changes and rationale. + +5. Implement and verify +- Apply required code or test updates with smallest safe change set. +- Run targeted checks first. +- If ${input:testScope} is provided, generate and use a focused MSTest filter via the skill. +- Collect diagnostics when tests cannot run. + +6. Classify each item +- Fixed: change implemented and validated. +- Needs Clarification: ambiguous, conflicting, or insufficiently specified. +- Blocked: external dependency, permission, or missing context. +- Informational: non-review discussion comment captured only. + +7. Produce a final report +- Keep review-thread outcomes and discussion outcomes in separate sections. +- Include evidence for each item: file location, change summary, validation result. +- Draft a distinct reply for each comment item that addresses that exact comment's request, context, and outcome. + +8. Commit changes +- If any changes were made, create a commit with a clear message referencing the PR and summarizing the resolution. +- Prompt the user to review and confirm the commit message before finalizing. +- When suggesting or performing a push, use the discovered git remote name. +- Prompt the user to push the commit if they have permissions, or provide instructions if they do not. +- Prompt the user to reply to each original PR comment with a comment-specific response and link to the relevant commit or code location, if appropriate. +- Prompt the user to mark review threads as resolved in GitHub if they have permissions, or provide instructions if they do not. + +## Output Format +1. PR Scope +- Repo +- PR number +- Unresolved review threads found +- Discussion comments found (if enabled) + +2. Unresolved Review Feedback (Actionable) +- Item: +- Location: : +- Author: +- Request summary: +- Action taken: +- Status: Fixed | Needs Clarification | Blocked +- Evidence: +- Suggested reply: + +3. Discussion Comments (Informational, optional) +- Item: +- Author: +- Summary: +- Notes: +- Suggested reply: + +4. Validation +- Commands run +- Filters used +- Pass/fail summary +- Remaining warnings/errors + +5. Final Summary +- Files changed +- Number fixed +- Number needing clarification +- Number blocked +- Number informational +- Recommended next step + +## Rules +- Do not invent comments; only act on data fetched from gh. +- Review-thread resolution tracking is authoritative for unresolved state. +- Keep behavior-compatible edits unless feedback explicitly requires change. +- If no unresolved review threads exist, report that explicitly. +- If auth or permission fails, report exact failure and minimum required user action. +- Do not use `set -e` in bash commands or scripts. +- After each terminal step, verify the bash session is still alive; if it died, report it immediately, start a new session, and continue from the last confirmed checkpoint. +- Use the discovered git remote name consistently anywhere a remote is required. +- Do not post generic batch replies; each reply must be tailored to the specific comment content and its exact resolution status.