Files
dotnet__skills/.github/aw/shared/devops-health.lock.md
Jan Krivanek 7bd6628e91 fix(devops-health): resilient dashboard issue discovery (#737)
The health check located its dashboard issue solely via the devops-health label search. When GitHub silently dropped the pinned dashboard (#288) from its issue search/list index, the workflow could not find it, created a duplicate (#695), and abandoned the pinned issue -- leaving the pinned dashboard stale for days.

Step 4.1 now resolves the dashboard by a cached issue number first (updating it directly by number, which works even when the issue is missing from search), persists that number to cache-memory every run, falls back to label + pinned-issue lookup, and consolidates duplicates. Documents the new health-dashboard-issue cache key.

Lock file unchanged: the prompt body is runtime-imported from these .md files.
2026-06-09 17:47:06 +00:00

251 lines
9.2 KiB
Markdown

<!-- AUTO-GENERATED — DO NOT EDIT -->
<!-- Source: devops-health-check.md knowledge compilation -->
# DevOps Health Check — Compiled Knowledge
This document contains the health check catalog, fingerprinting rules, output templates, and operational guidance for the DevOps Daily Health Check agentic workflow.
---
## 1. Fingerprinting Rules
Every health finding MUST be assigned a deterministic **fingerprint** — a string ID derived from the finding's category and key attributes (but NOT timestamps, run IDs, or other ephemeral data). The same real-world issue MUST produce the same fingerprint on every run.
### 1.1 Pipeline Fingerprints
```
fingerprint = "pipeline:{workflow_name}:{job_name}:{failed_step}:{conclusion}"
```
- Normalize `workflow_name` by lowercasing and replacing spaces with hyphens
- Normalize `job_name` and `failed_step` the same way
- Same workflow + job + step + conclusion = same finding (even across different run IDs)
- A workflow that fails in a _different_ step is a _different_ finding
- For timeouts/cancellations: `pipeline:{workflow_name}:{job_name}:timeout`
- For aggregate failure rate (P5): `pipeline:evaluation:failure-rate:{bucket}` where bucket = "critical" or "warning"
- For scheduled cancellation rate (P6): `pipeline:evaluation:schedule-cancellation:{bucket}` where bucket = "critical" or "warning"
**Examples:**
| Finding | Fingerprint |
|---------|-------------|
| Evaluation workflow, evaluate job, "Run skill-validator" step failed | `pipeline:evaluation:evaluate:run-skill-validator:failure` |
| Evaluation workflow, evaluate job, "Build validator" step failed | `pipeline:evaluation:evaluate:build-validator:failure` |
| validate-skills workflow, validate job timed out | `pipeline:validate-skills:validate:timeout` |
| Evaluation failure rate > 30% across all branches | `pipeline:evaluation:failure-rate:critical` |
| Evaluation failure rate > 15% across all branches | `pipeline:evaluation:failure-rate:warning` |
| Evaluation scheduled cancellation rate > 60% | `pipeline:evaluation:schedule-cancellation:critical` |
| Evaluation scheduled cancellation rate > 30% | `pipeline:evaluation:schedule-cancellation:warning` |
### 1.2 Infrastructure Fingerprints
```
fingerprint = "infra:{config_key}"
where config_key ∈ { "no-codeowners", "no-dependabot", "relaxed-skill-validation",
"verdict-warn-only", "pages-deployment-failed",
"unpinned-action:{action_name}",
"orphan-skill:{component}:{skill_name}",
"orphan-plugin:{directory_basename}" }
```
### 1.3 Resource Fingerprints
```
fingerprint = "resource:{metric}:{threshold_breach}"
```
- `resource:eval-duration:warning` — eval avg > 50 min
- `resource:eval-duration:critical` — eval avg > 55 min
- `resource:cost-increase` — weekly compute hours up >20%
---
## 2. Diff Algorithm
```
previous_fps = cache_memory_load("health-check-fingerprints") ?? {}
current_fps = {}
for each finding in all_collected_findings:
fp = compute_fingerprint(finding)
current_fps[fp] = finding
new_findings = { fp: f for fp, f in current_fps if fp NOT IN previous_fps }
existing_findings = { fp: f for fp, f in current_fps if fp IN previous_fps }
resolved_findings = { fp: f for fp, f in previous_fps if fp NOT IN current_fps }
# Update occurrence tracking
for fp in existing_findings:
existing_findings[fp].occurrences = previous_fps[fp].occurrences + 1
existing_findings[fp].first_seen = previous_fps[fp].first_seen
for fp in new_findings:
new_findings[fp].occurrences = 1
new_findings[fp].first_seen = today
cache_memory_save("health-check-fingerprints", current_fps)
cache_memory_save("health-check-history", append(
load("health-check-history"),
{ date: today, new_count, existing_count, resolved_count, by_severity }
))
```
### 2.1 Sorting Within Diff Categories
Within each category (NEW, EXISTING, RESOLVED):
1. **Primary**: Severity descending — 🔴 Critical → 🟡 Warning → 🔵 Info
2. **Secondary**: Category — pipeline → infra → resource
3. **Tertiary**: Alphabetical by title
---
## 3. Severity Rules Reference
### Pipeline
| Check | Condition | Severity |
|-------|-----------|----------|
| P1 | `evaluation` workflow failed on `main` | 🔴 Critical |
| P1 | Other workflow failed on `main` | 🟡 Warning |
| P1 | Matches `known-noise` pattern | 🔵 Info (demoted) |
| P2 | Any cancelled/timed-out run on `main` | 🟡 Warning |
| P3 | Eval avg duration > 55 min | 🔴 Critical |
| P3 | Eval avg duration > 50 min | 🟡 Warning |
| P5 | Eval failure rate > 30% (all branches, 24h) | 🔴 Critical |
| P5 | Eval failure rate > 15% (all branches, 24h) | 🟡 Warning |
| P6 | Eval scheduled cancellation rate > 60% (24h) | 🔴 Critical |
| P6 | Eval scheduled cancellation rate > 30% (24h) | 🟡 Warning |
### Infrastructure
| Check | Condition | Severity |
|-------|-----------|----------|
| I1 | No CODEOWNERS file | 🟡 Warning |
| I2 | No Dependabot config | 🟡 Warning |
| I3 | `fail-on-warning: false` in validate-skills | 🟡 Warning |
| I4 | `--verdict-warn-only` in evaluation | 🔵 Info |
| I5 | Pages deployment failed | 🔴 Critical |
| I6 | Unpinned third-party action | 🔵 Info |
| I7 | Orphan skill (not registered in any plugin) | 🟡 Warning |
| I8 | Orphan plugin (not listed in marketplace.json) | 🟡 Warning |
### Resource
| Check | Condition | Severity |
|-------|-----------|----------|
| U3 | Weekly compute up >20% | 🟡 Warning |
---
## 4. Known Noise Patterns
The `cache-memory` key `known-noise` stores a list of fingerprint prefixes or patterns that should be demoted to 🔵 Info severity. Example patterns:
- `pipeline:copilot-code-review` — org-level workflow with known chronic failures
- `infra:verdict-warn-only` — intentional configuration, always Info
When a finding's fingerprint matches any known-noise pattern (prefix match), demote its severity to 🔵 Info. The finding is still reported in the output (in the EXISTING section if recurring) — it is NOT hidden.
New patterns can be added by manually editing the `known-noise` list in `cache-memory`.
---
## 5. Investigation Dispatch Rules
Only 🆕 NEW findings that meet these criteria qualify for investigation dispatch:
| Condition | Action |
|-----------|--------|
| 🆕 + 🔴 Critical | **Always dispatch** |
| 🆕 + 🟡 Warning + `pipeline` category | **Dispatch** |
| 🆕 + 🟡 Warning + `infra` or `resource` category | **Skip** |
| 🆕 + 🔵 Info | **Never dispatch** |
| 📌 EXISTING or ✅ RESOLVED | **Never dispatch** |
**Budget cap:** Maximum 2 dispatches per run.
**Priority order when cap is hit:**
1. 🔴 Critical findings first
2. Pipeline findings before infrastructure
3. Other categories last
## 6. Output Templates
### 6.1 Issue Title
```
🏥 Repository Health Dashboard
```
### 6.2 Issue Label
```
devops-health
```
- Color: `#0E8A16`
- Description: `Daily automated health check report`
### 6.3 First Run Notice
If no previous fingerprints exist in `cache-memory`:
```markdown
> ⚠️ This is the first health check run. All findings appear as new.
> Starting from the next run, only changes will be highlighted.
```
### 6.4 Trends Arrow Legend
| Condition | Arrow | Meaning |
|-----------|-------|---------|
| Δ positive and good (e.g., success rate up) | ✅ | Improving |
| Δ positive and bad (e.g., compute hours up) | ↗️ | Increasing (watch) |
| Δ negative and good (e.g., open PRs down) | ✅ | Improving |
| Δ negative and bad (e.g., success rate down) | ⚠️ | Degrading |
| Δ ≈ 0 | ➡️ | Stable |
### 6.5 Investigation Island Template
```markdown
<!-- investigation:{fingerprint} -->
⏳ Investigation dispatched — results arriving shortly...
<!-- /investigation:{fingerprint} -->
```
---
## 7. Operational Guardrails
### 7.1 API Rate Limits
- Use targeted, date-filtered queries to minimize API calls
- The `github` MCP toolset handles pagination automatically
- Space dispatches 5 seconds apart
### 7.2 Issue Body Size
- GitHub issues have a ~65,535 character limit
- If body exceeds 60k: truncate EXISTING section (keep top 20 by severity)
- Footer: `> … N additional existing findings omitted`
- The daily comment always includes complete summary counts
### 7.3 Cache Memory Keys
| Key | Contents | Updated |
|-----|----------|---------|
| `health-check-fingerprints` | Map of fingerprint → finding (with occurrences, first_seen) | Every run |
| `health-check-history` | Array of daily summaries (date, counts by diff type and severity) | Appended each run |
| `health-dashboard-issue` | Issue number of the canonical health dashboard issue. Used to update the dashboard **by number** so it stays stable even when GitHub's label search/list index drops the issue (which otherwise causes a duplicate dashboard to be created). | Every run |
| `known-noise` | Array of fingerprint patterns to demote to Info | Manual edit |
### 7.4 Graceful Degradation
If any data source is unavailable:
- Skip that check category entirely
- Note the skip in the output: `> ⚠️ Skipped {category} checks: {reason}`
- Do NOT fail the entire workflow
- Continue with available data
### 7.5 Cache Memory Loss
If `cache-memory` returns no previous state:
- Treat all findings as 🆕 NEW
- Display the first-run notice (§6.3)
- The diff will resume automatically on the next run