From 3ef2e95af6fd0c4b462da3fcff918537392eb0d7 Mon Sep 17 00:00:00 2001 From: Michael Dieringer <65093775+MichaelDieringer@users.noreply.github.com> Date: Thu, 2 Jul 2026 00:02:44 +0200 Subject: [PATCH] Hardening: stable-branch som udrulningskanal - merge til main er ikke laengere deploy Alle forbrugere laeser nu fra stable i stedet for main: - curabis-standard.agent.md v10: BASE/AGENTS_BASE + self-heal-URL -> stable - sync-bcquality-knowledge.ps1: $branch = stable - machine/CLAUDE.md: auto-update gater paa stable-SHA og fetcher setup fra stable - templates/bcquality.agent.md + al-triage.agent.md: knowledge-URLer -> stable (+ fix af doed reference: branch-merge-to-main-workflow.md var omdoebt til feature-branch-must-merge-to-track-branch.md - templaten shippede et 404) - francis.agent.md + Invoke-CurabisEvidence.ps1: raw-base -> stable - CONSUMPTION.md: Release channel-sektion med promote-procedure og rationale Deploy sker herefter kun ved bevidst fast-forward af stable (kun Michael). Kanal oprettet: stable @ 57b8292, tag v1.0.0. Co-Authored-By: Claude Fable 5 --- CONSUMPTION.md | 25 +++ custom/agents/francis.agent.md | 2 +- custom/scripts/Invoke-CurabisEvidence.ps1 | 2 +- custom/setup/curabis-standard.agent.md | 8 +- custom/setup/machine/CLAUDE.md | 6 +- custom/setup/sync-bcquality-knowledge.ps1 | 256 +++++++++++----------- custom/setup/templates/al-triage.agent.md | 220 +++++++++---------- custom/setup/templates/bcquality.agent.md | 44 ++-- 8 files changed, 294 insertions(+), 269 deletions(-) diff --git a/CONSUMPTION.md b/CONSUMPTION.md index 72b3a5f..ee683f5 100644 --- a/CONSUMPTION.md +++ b/CONSUMPTION.md @@ -38,6 +38,31 @@ future CI/PR-review integration: currently consumed by nothing. Keep it — but do not mistake it for active configuration of the session model. +## Release channel: `stable` + +Merging to `main` is **not** a deployment. All consumers — the machine +CLAUDE.md auto-update, `sync-bcquality-knowledge.ps1`, the setup agent's +fetch URLs, and the agent templates' knowledge references — read from the +**`stable`** branch, never from `main`. `main` is where PRs land and CI runs; +`stable` is what every developer machine actually executes. + +Deploying is a deliberate act (Michael only): + + git checkout stable + git merge --ff-only main + git push origin stable + git checkout main + +Optionally cut a version tag at the same commit (`git tag vX.Y.Z && git push +origin vX.Y.Z`) for a historical record. If a bad change reaches `stable`, +roll back by force-moving `stable` to the previous good commit — consumers +follow the branch, so recovery is one push. + +Rationale: `main` used to be the live deploy channel — any merge silently +overwrote `bc-mcp-bridge.js` (which handles S2S credentials) on every +developer machine at next session start. The `stable` gate separates "CI +accepted it" from "the organization runs it". + ## Known deltas to close before activating the Entry flow 1. **`custom/skills/` is empty.** The CURABIS review pass lives in the diff --git a/custom/agents/francis.agent.md b/custom/agents/francis.agent.md index 74c8b0d..aef0c23 100644 --- a/custom/agents/francis.agent.md +++ b/custom/agents/francis.agent.md @@ -78,7 +78,7 @@ reviews what happened. He asks one question about every significant event: He compares against the full BCQuality knowledge base: ``` -BASE = https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge +BASE = https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge ``` Domains: `architecture/`, `testing/`, `mcp/` diff --git a/custom/scripts/Invoke-CurabisEvidence.ps1 b/custom/scripts/Invoke-CurabisEvidence.ps1 index 725315a..498eafe 100644 --- a/custom/scripts/Invoke-CurabisEvidence.ps1 +++ b/custom/scripts/Invoke-CurabisEvidence.ps1 @@ -29,7 +29,7 @@ param( [string]$BCQualityHome, # Bruges naar der ikke er en lokal klon: knowledge-filer HTTP-tjekkes herfra. - [string]$RawBase = 'https://raw.githubusercontent.com/Curabis/BCQuality/main', + [string]$RawBase = 'https://raw.githubusercontent.com/Curabis/BCQuality/stable', [switch]$Quiet ) diff --git a/custom/setup/curabis-standard.agent.md b/custom/setup/curabis-standard.agent.md index d312233..9a9dbf6 100644 --- a/custom/setup/curabis-standard.agent.md +++ b/custom/setup/curabis-standard.agent.md @@ -1,7 +1,7 @@ --- kind: action-skill id: curabis-standard-setup -version: 9 +version: 10 title: CURABIS Standard — Project Setup description: > Configures a new or existing repository to the CURABIS Standard development @@ -37,8 +37,8 @@ Detect which mode based on the trigger phrase and proceed accordingly. ## Source URLs (BCQuality — always fetch fresh) ``` -BASE = https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/setup -AGENTS_BASE = https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/agents +BASE = https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/setup +AGENTS_BASE = https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/agents ``` | Artefakt | URL | @@ -168,7 +168,7 @@ If `~/.claude/bcquality-knowledge/` is missing or empty, self-heal before contin If the sync script itself is missing, first download it AS RAW BYTES (do not decode/re-encode — use `Invoke-WebRequest -OutFile`) from -`https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/setup/sync-bcquality-knowledge.ps1` +`https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/setup/sync-bcquality-knowledge.ps1` to `~/.claude/sync-bcquality-knowledge.ps1`, then run it. These rules are always active. diff --git a/custom/setup/machine/CLAUDE.md b/custom/setup/machine/CLAUDE.md index db8518d..aa59f2a 100644 --- a/custom/setup/machine/CLAUDE.md +++ b/custom/setup/machine/CLAUDE.md @@ -8,11 +8,11 @@ These instructions apply to every Claude Code session, regardless of project. If the current project has `.github/.agents/bcquality.agent.md`: 1. Fetch the latest commit SHA for `custom/setup/` in BCQuality: - `https://api.github.com/repos/Curabis/BCQuality/commits?path=custom/setup&per_page=1` + `https://api.github.com/repos/Curabis/BCQuality/commits?path=custom/setup&sha=stable&per_page=1` 2. Read stored SHA from `~/.claude/.bcquality-version` (may not exist yet) 3. If SHA is different (or file missing): a. Fetch and execute Mode B from: - `https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/setup/curabis-standard.agent.md` + `https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/setup/curabis-standard.agent.md` b. Write new SHA to `~/.claude/.bcquality-version` c. Report: "BCQuality opdateret til [short-sha] — [antal] filer tjekket" 4. If SHA is unchanged: continue silently @@ -25,7 +25,7 @@ unless something actually changed. When the user says either of these commands, fetch and follow the setup agent: ``` -https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/setup/curabis-standard.agent.md +https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/setup/curabis-standard.agent.md ``` - **"Konfigurer dette projekt til CURABIS Standard"** → fuld setup af nyt repo diff --git a/custom/setup/sync-bcquality-knowledge.ps1 b/custom/setup/sync-bcquality-knowledge.ps1 index 375bc28..0814226 100644 --- a/custom/setup/sync-bcquality-knowledge.ps1 +++ b/custom/setup/sync-bcquality-knowledge.ps1 @@ -1,128 +1,128 @@ -# Refresh the MACHINE-LOCAL mirror of the Curabis BCQuality knowledge base. -# -# Mirrors three layers from https://github.com/Curabis/BCQuality: -# custom/ - Curabis org-specific rules (ALWAYS read in full each session) -# community/ - BC community patterns (loaded on relevance via INDEX.md) -# microsoft/ - platform guardrails (loaded on relevance via INDEX.md) -# -# The upstream file list is discovered dynamically from the GitHub tree API, so -# new/removed upstream files propagate automatically - nothing is hardcoded. -# After downloading, an INDEX.md is generated (one line per file, with domain + -# keywords from each file's frontmatter) so an agent can scan and pull only the -# files relevant to a task instead of loading all ~100 every session. -# -# The mirror is per developer machine (~/.claude/bcquality-knowledge/), shared -# by every CURABIS repo on it. It is NEVER committed to a project repository - -# see BCQuality rule bcquality-knowledge-must-mirror-to-machine-not-repo. -# One sync per machine covers every repo. Run periodically: -# powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.claude\sync-bcquality-knowledge.ps1" - -$ErrorActionPreference = 'Stop' - -$repo = 'Curabis/BCQuality' -$branch = 'main' -$dest = Join-Path $env:USERPROFILE '.claude\bcquality-knowledge' -$staging = "$dest.tmp" -$rawBase = "https://raw.githubusercontent.com/$repo/$branch" -$treeUrl = "https://api.github.com/repos/$repo/git/trees/$branch" + '?recursive=1' - -# Upstream path prefix -> local layer folder -$layerMap = [ordered]@{ - 'custom/knowledge/' = 'custom' - 'community/knowledge/' = 'community' - 'microsoft/knowledge/' = 'microsoft' -} - -function Get-Frontmatter { - param([string]$Path) - $lines = Get-Content -Path $Path - $fm = @{} - if ($lines.Count -eq 0 -or $lines[0].Trim() -ne '---') { return $fm } - for ($i = 1; $i -lt $lines.Count; $i++) { - if ($lines[$i].Trim() -eq '---') { break } - if ($lines[$i] -match '^\s*([\w-]+):\s*(.*)$') { - $fm[$matches[1]] = $matches[2].Trim() - } - } - return $fm -} - -Write-Host "Fetching file tree from $repo@$branch ..." -$headers = @{ 'User-Agent' = 'wareco-bcquality-sync'; 'Accept' = 'application/vnd.github+json' } -$tree = (Invoke-RestMethod -Uri $treeUrl -Headers $headers).tree - -# Build the download worklist from the tree -$files = @() -foreach ($node in $tree) { - if ($node.type -ne 'blob') { continue } - if ($node.path -notlike '*.md') { continue } - foreach ($prefix in $layerMap.Keys) { - if ($node.path.StartsWith($prefix)) { - $relative = $node.path.Substring($prefix.Length) # e.g. performance/avoid-commit-inside-loops.md - $files += [pscustomobject]@{ - Url = "$rawBase/$($node.path)" - Layer = $layerMap[$prefix] - Relative = $relative - LocalPath = Join-Path $staging (Join-Path $layerMap[$prefix] $relative) - } - break - } - } -} - -if ($files.Count -eq 0) { throw 'No knowledge files found in upstream tree - aborting.' } - -# Download into a staging folder so a mid-run failure never wipes the live copy -if (Test-Path $staging) { Remove-Item -Recurse -Force $staging } -New-Item -ItemType Directory -Force $staging | Out-Null - -Write-Host "Downloading $($files.Count) knowledge files ..." -$rc = 0 -foreach ($f in $files) { - New-Item -ItemType Directory -Force (Split-Path $f.LocalPath) | Out-Null - try { - Invoke-WebRequest -Uri $f.Url -OutFile $f.LocalPath -UseBasicParsing -ErrorAction Stop - Write-Host "OK $($f.Layer)/$($f.Relative)" - } catch { - Write-Error "FAIL $($f.Layer)/$($f.Relative)" - $rc = 1 - } -} - -# Generate INDEX.md (relevance index for all layers) -Write-Host "Generating INDEX.md ..." -$idx = [System.Collections.Generic.List[string]]::new() -$idx.Add('# BCQuality Knowledge Index') -$idx.Add('') -$idx.Add('') -$idx.Add('') -$idx.Add('Layers: `custom` is ALWAYS read in full each session. For `community` and') -$idx.Add('`microsoft`, scan this index and read only the files whose domain/keywords') -$idx.Add('match the task at hand.') -$idx.Add('') - -foreach ($layer in @('custom', 'community', 'microsoft')) { - $layerFiles = $files | Where-Object { $_.Layer -eq $layer } | Sort-Object Relative - if (-not $layerFiles) { continue } - $note = if ($layer -eq 'custom') { ' (always-on)' } else { ' (load on relevance)' } - $idx.Add("## $layer$note") - $idx.Add('') - foreach ($f in $layerFiles) { - $fm = Get-Frontmatter $f.LocalPath - $domain = if ($fm.ContainsKey('domain')) { $fm['domain'] } else { '' } - $keywords = if ($fm.ContainsKey('keywords')) { $fm['keywords'].Trim('[', ']') } else { '' } - $rel = $f.Relative -replace '\.md$', '' - $idx.Add("- ``$layer/$rel`` - domain: $domain; keywords: $keywords") - } - $idx.Add('') -} -Set-Content -Path (Join-Path $staging 'INDEX.md') -Value $idx -Encoding utf8 - -# Swap staging into place -if (Test-Path $dest) { Remove-Item -Recurse -Force $dest } -Rename-Item -Path $staging -NewName (Split-Path $dest -Leaf) - -Write-Host '' -Write-Host "Done. $($files.Count) files across $($layerMap.Count) layers." -Write-Host "Machine-local mirror updated: $dest" -exit $rc +# Refresh the MACHINE-LOCAL mirror of the Curabis BCQuality knowledge base. +# +# Mirrors three layers from https://github.com/Curabis/BCQuality: +# custom/ - Curabis org-specific rules (ALWAYS read in full each session) +# community/ - BC community patterns (loaded on relevance via INDEX.md) +# microsoft/ - platform guardrails (loaded on relevance via INDEX.md) +# +# The upstream file list is discovered dynamically from the GitHub tree API, so +# new/removed upstream files propagate automatically - nothing is hardcoded. +# After downloading, an INDEX.md is generated (one line per file, with domain + +# keywords from each file's frontmatter) so an agent can scan and pull only the +# files relevant to a task instead of loading all ~100 every session. +# +# The mirror is per developer machine (~/.claude/bcquality-knowledge/), shared +# by every CURABIS repo on it. It is NEVER committed to a project repository - +# see BCQuality rule bcquality-knowledge-must-mirror-to-machine-not-repo. +# One sync per machine covers every repo. Run periodically: +# powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.claude\sync-bcquality-knowledge.ps1" + +$ErrorActionPreference = 'Stop' + +$repo = 'Curabis/BCQuality' +$branch = 'stable' +$dest = Join-Path $env:USERPROFILE '.claude\bcquality-knowledge' +$staging = "$dest.tmp" +$rawBase = "https://raw.githubusercontent.com/$repo/$branch" +$treeUrl = "https://api.github.com/repos/$repo/git/trees/$branch" + '?recursive=1' + +# Upstream path prefix -> local layer folder +$layerMap = [ordered]@{ + 'custom/knowledge/' = 'custom' + 'community/knowledge/' = 'community' + 'microsoft/knowledge/' = 'microsoft' +} + +function Get-Frontmatter { + param([string]$Path) + $lines = Get-Content -Path $Path + $fm = @{} + if ($lines.Count -eq 0 -or $lines[0].Trim() -ne '---') { return $fm } + for ($i = 1; $i -lt $lines.Count; $i++) { + if ($lines[$i].Trim() -eq '---') { break } + if ($lines[$i] -match '^\s*([\w-]+):\s*(.*)$') { + $fm[$matches[1]] = $matches[2].Trim() + } + } + return $fm +} + +Write-Host "Fetching file tree from $repo@$branch ..." +$headers = @{ 'User-Agent' = 'wareco-bcquality-sync'; 'Accept' = 'application/vnd.github+json' } +$tree = (Invoke-RestMethod -Uri $treeUrl -Headers $headers).tree + +# Build the download worklist from the tree +$files = @() +foreach ($node in $tree) { + if ($node.type -ne 'blob') { continue } + if ($node.path -notlike '*.md') { continue } + foreach ($prefix in $layerMap.Keys) { + if ($node.path.StartsWith($prefix)) { + $relative = $node.path.Substring($prefix.Length) # e.g. performance/avoid-commit-inside-loops.md + $files += [pscustomobject]@{ + Url = "$rawBase/$($node.path)" + Layer = $layerMap[$prefix] + Relative = $relative + LocalPath = Join-Path $staging (Join-Path $layerMap[$prefix] $relative) + } + break + } + } +} + +if ($files.Count -eq 0) { throw 'No knowledge files found in upstream tree - aborting.' } + +# Download into a staging folder so a mid-run failure never wipes the live copy +if (Test-Path $staging) { Remove-Item -Recurse -Force $staging } +New-Item -ItemType Directory -Force $staging | Out-Null + +Write-Host "Downloading $($files.Count) knowledge files ..." +$rc = 0 +foreach ($f in $files) { + New-Item -ItemType Directory -Force (Split-Path $f.LocalPath) | Out-Null + try { + Invoke-WebRequest -Uri $f.Url -OutFile $f.LocalPath -UseBasicParsing -ErrorAction Stop + Write-Host "OK $($f.Layer)/$($f.Relative)" + } catch { + Write-Error "FAIL $($f.Layer)/$($f.Relative)" + $rc = 1 + } +} + +# Generate INDEX.md (relevance index for all layers) +Write-Host "Generating INDEX.md ..." +$idx = [System.Collections.Generic.List[string]]::new() +$idx.Add('# BCQuality Knowledge Index') +$idx.Add('') +$idx.Add('') +$idx.Add('') +$idx.Add('Layers: `custom` is ALWAYS read in full each session. For `community` and') +$idx.Add('`microsoft`, scan this index and read only the files whose domain/keywords') +$idx.Add('match the task at hand.') +$idx.Add('') + +foreach ($layer in @('custom', 'community', 'microsoft')) { + $layerFiles = $files | Where-Object { $_.Layer -eq $layer } | Sort-Object Relative + if (-not $layerFiles) { continue } + $note = if ($layer -eq 'custom') { ' (always-on)' } else { ' (load on relevance)' } + $idx.Add("## $layer$note") + $idx.Add('') + foreach ($f in $layerFiles) { + $fm = Get-Frontmatter $f.LocalPath + $domain = if ($fm.ContainsKey('domain')) { $fm['domain'] } else { '' } + $keywords = if ($fm.ContainsKey('keywords')) { $fm['keywords'].Trim('[', ']') } else { '' } + $rel = $f.Relative -replace '\.md$', '' + $idx.Add("- ``$layer/$rel`` - domain: $domain; keywords: $keywords") + } + $idx.Add('') +} +Set-Content -Path (Join-Path $staging 'INDEX.md') -Value $idx -Encoding utf8 + +# Swap staging into place +if (Test-Path $dest) { Remove-Item -Recurse -Force $dest } +Rename-Item -Path $staging -NewName (Split-Path $dest -Leaf) + +Write-Host '' +Write-Host "Done. $($files.Count) files across $($layerMap.Count) layers." +Write-Host "Machine-local mirror updated: $dest" +exit $rc diff --git a/custom/setup/templates/al-triage.agent.md b/custom/setup/templates/al-triage.agent.md index 4c668ed..ed8168f 100644 --- a/custom/setup/templates/al-triage.agent.md +++ b/custom/setup/templates/al-triage.agent.md @@ -1,110 +1,110 @@ ---- -kind: action-skill -id: curabis-al-triage -version: 1 -title: CURABIS AL triage -description: On-demand reactive diagnosis of a failing build, test, or runtime error. Reproduces the symptom, finds the root cause, and recommends a minimal fix. Read-only - never applies changes. -inputs: [error-message, file-path, test-name, stack-trace] -outputs: [diagnosis-report] -bc-version: [all] -technologies: [al] -countries: [w1] -application-area: [all] -domain: diagnostics -keywords: [triage, diagnose, root-cause, minimal-fix, compile-error, test-failure, runtime-error, reproduce, regression] -sub-skills: - - microsoft/skills/review/al-code-review.md ---- - -# CURABIS AL triage - -## Who I Am - -My name is Dominique Jean Larrey. I was born on 8 July 1766 in Beaudéan, France, -and died on 25 July 1842 in Lyon. I was chief surgeon of Napoleon Bonaparte's Grande -Armée and I served in over sixty battles across twenty years of almost continuous war. - -I invented **triage**. Before my system, the wounded were treated in the order they -arrived at the field hospital — which meant those nearest the front were treated last, -often after hours of waiting, often too late. I reversed this. I classified the wounded -by urgency of need, not by rank or order of arrival, and I moved treatment forward to -the battlefield rather than waiting for the wounded to come to me. - -I designed the **flying ambulance** — a horse-drawn vehicle that could move rapidly -across the battlefield to collect the wounded during the fighting itself, not after it. -This was radical. The previous practice was to wait until a battle ended. By then, -many who could have been saved were not. - -Napoleon called me "the most virtuous man I have ever known." After Waterloo, where I -served on the losing side, the Duke of Wellington ordered that my life be spared on -the battlefield. Enemies respected the work. - -I did not work on the easy cases. I worked on the ones where speed and accuracy -of diagnosis were the difference between recovery and loss. - -Here at CURABIS, I am called when something is already broken. I find the cause. -I recommend the minimal fix. I do not apply it — that is the developer's decision. - -On-demand specialist. Invoke this agent when something is **already broken** - a build -error, a failing test, an AppSourceCop violation, or a runtime error - and you need a -diagnosis, not a feature. This agent operates outside the normal build loop, runs -**read-only**, and **never blocks**: it recommends a minimal fix, it does not apply one. - -Loop: **reproduce -> root-cause -> minimal-fix recommendation.** - -## Source - -Layer 1 - Microsoft BCQuality: https://github.com/microsoft/BCQuality - -Layer 2 - CURABIS custom knowledge (fetch before citing a finding): -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/architecture/pages-must-not-contain-business-logic.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/architecture/namespace-must-be-verified-from-source.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/architecture/al-identifiers-must-be-english.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/architecture/clarify-before-building.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/testing/test-setup-must-use-library-codeunit.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/testing/test-data-must-be-random-and-complete.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/testing/tests-must-adapt-to-existing-code.md - -If a source is unreachable, **degrade gracefully**: fall back to the triage protocol -below plus the CURABIS-ARCH rules in `bcquality.agent.md`, note that BCQuality was -unavailable, and carry on. Nothing blocks. - -## Tools - -Use the AL MCP server (already allowed in `.claude/settings.json`) to reproduce and -localize before forming any hypothesis: -- `al_compile` / `al_getdiagnostics` - reproduce a build error and read the exact diagnostic code. -- `al_run_tests` - reproduce a failing test. -- `al_symbolsearch` / `al_symbolrelations` - locate the offending object and what depends on it. -- `al_getpackagedependencies` - check for version/dependency mismatches. - -## Action - triage protocol - -CURABIS-TRIAGE-001 Reproduce first. Capture the exact symptom (diagnostic code, test - name, error text) via the AL MCP tools before theorising. No reproduction = state that - and stop; do not guess. -CURABIS-TRIAGE-002 Localize. Identify the precise object, procedure, and line. Use - `al_symbolsearch` / `al_symbolrelations` - do not assume namespaces or signatures. -CURABIS-TRIAGE-003 Root-cause, not symptom. Name the underlying cause. A compile error on - a Modify() is a symptom; the missing FindSet(true) or the page-level data write is the - cause. Cross-check against CURABIS-ARCH-001..010. -CURABIS-TRIAGE-004 Minimal fix. Recommend the smallest change that removes the root cause. - No refactors, no opportunistic cleanup, no scope creep. -CURABIS-TRIAGE-005 Cite or flag. Back every finding with a specific BCQuality knowledge - file or an AL diagnostic code. A finding with no citation must be labelled - "UNVERIFIED HYPOTHESIS" so the reader knows to confirm it. -CURABIS-TRIAGE-006 Read-only. Output a diagnosis report only. Never edit, never apply the - fix - hand the recommendation back to the developer or the build loop. -CURABIS-TRIAGE-007 Regression awareness. Before recommending, check what `al_symbolrelations` - says depends on the object so the minimal fix does not break callers. - -## Output format - -``` -SYMPTOM -LOCATION -ROOT CAUSE -MINIMAL FIX -EVIDENCE -BLAST RADIUS -``` +--- +kind: action-skill +id: curabis-al-triage +version: 1 +title: CURABIS AL triage +description: On-demand reactive diagnosis of a failing build, test, or runtime error. Reproduces the symptom, finds the root cause, and recommends a minimal fix. Read-only - never applies changes. +inputs: [error-message, file-path, test-name, stack-trace] +outputs: [diagnosis-report] +bc-version: [all] +technologies: [al] +countries: [w1] +application-area: [all] +domain: diagnostics +keywords: [triage, diagnose, root-cause, minimal-fix, compile-error, test-failure, runtime-error, reproduce, regression] +sub-skills: + - microsoft/skills/review/al-code-review.md +--- + +# CURABIS AL triage + +## Who I Am + +My name is Dominique Jean Larrey. I was born on 8 July 1766 in Beaudéan, France, +and died on 25 July 1842 in Lyon. I was chief surgeon of Napoleon Bonaparte's Grande +Armée and I served in over sixty battles across twenty years of almost continuous war. + +I invented **triage**. Before my system, the wounded were treated in the order they +arrived at the field hospital — which meant those nearest the front were treated last, +often after hours of waiting, often too late. I reversed this. I classified the wounded +by urgency of need, not by rank or order of arrival, and I moved treatment forward to +the battlefield rather than waiting for the wounded to come to me. + +I designed the **flying ambulance** — a horse-drawn vehicle that could move rapidly +across the battlefield to collect the wounded during the fighting itself, not after it. +This was radical. The previous practice was to wait until a battle ended. By then, +many who could have been saved were not. + +Napoleon called me "the most virtuous man I have ever known." After Waterloo, where I +served on the losing side, the Duke of Wellington ordered that my life be spared on +the battlefield. Enemies respected the work. + +I did not work on the easy cases. I worked on the ones where speed and accuracy +of diagnosis were the difference between recovery and loss. + +Here at CURABIS, I am called when something is already broken. I find the cause. +I recommend the minimal fix. I do not apply it — that is the developer's decision. + +On-demand specialist. Invoke this agent when something is **already broken** - a build +error, a failing test, an AppSourceCop violation, or a runtime error - and you need a +diagnosis, not a feature. This agent operates outside the normal build loop, runs +**read-only**, and **never blocks**: it recommends a minimal fix, it does not apply one. + +Loop: **reproduce -> root-cause -> minimal-fix recommendation.** + +## Source + +Layer 1 - Microsoft BCQuality: https://github.com/microsoft/BCQuality + +Layer 2 - CURABIS custom knowledge (fetch before citing a finding): +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/architecture/pages-must-not-contain-business-logic.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/architecture/namespace-must-be-verified-from-source.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/architecture/al-identifiers-must-be-english.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/architecture/clarify-before-building.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/testing/test-setup-must-use-library-codeunit.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/testing/test-data-must-be-random-and-complete.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/testing/tests-must-adapt-to-existing-code.md + +If a source is unreachable, **degrade gracefully**: fall back to the triage protocol +below plus the CURABIS-ARCH rules in `bcquality.agent.md`, note that BCQuality was +unavailable, and carry on. Nothing blocks. + +## Tools + +Use the AL MCP server (already allowed in `.claude/settings.json`) to reproduce and +localize before forming any hypothesis: +- `al_compile` / `al_getdiagnostics` - reproduce a build error and read the exact diagnostic code. +- `al_run_tests` - reproduce a failing test. +- `al_symbolsearch` / `al_symbolrelations` - locate the offending object and what depends on it. +- `al_getpackagedependencies` - check for version/dependency mismatches. + +## Action - triage protocol + +CURABIS-TRIAGE-001 Reproduce first. Capture the exact symptom (diagnostic code, test + name, error text) via the AL MCP tools before theorising. No reproduction = state that + and stop; do not guess. +CURABIS-TRIAGE-002 Localize. Identify the precise object, procedure, and line. Use + `al_symbolsearch` / `al_symbolrelations` - do not assume namespaces or signatures. +CURABIS-TRIAGE-003 Root-cause, not symptom. Name the underlying cause. A compile error on + a Modify() is a symptom; the missing FindSet(true) or the page-level data write is the + cause. Cross-check against CURABIS-ARCH-001..010. +CURABIS-TRIAGE-004 Minimal fix. Recommend the smallest change that removes the root cause. + No refactors, no opportunistic cleanup, no scope creep. +CURABIS-TRIAGE-005 Cite or flag. Back every finding with a specific BCQuality knowledge + file or an AL diagnostic code. A finding with no citation must be labelled + "UNVERIFIED HYPOTHESIS" so the reader knows to confirm it. +CURABIS-TRIAGE-006 Read-only. Output a diagnosis report only. Never edit, never apply the + fix - hand the recommendation back to the developer or the build loop. +CURABIS-TRIAGE-007 Regression awareness. Before recommending, check what `al_symbolrelations` + says depends on the object so the minimal fix does not break callers. + +## Output format + +``` +SYMPTOM +LOCATION +ROOT CAUSE +MINIMAL FIX +EVIDENCE +BLAST RADIUS +``` diff --git a/custom/setup/templates/bcquality.agent.md b/custom/setup/templates/bcquality.agent.md index f2f1d48..a71821f 100644 --- a/custom/setup/templates/bcquality.agent.md +++ b/custom/setup/templates/bcquality.agent.md @@ -47,28 +47,28 @@ of the quality in the code they write. Layer 1 - Microsoft BCQuality: https://github.com/microsoft/BCQuality Layer 2 - CURABIS custom knowledge (fetch before applying rules): -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/architecture/pages-must-not-contain-business-logic.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/architecture/namespace-must-be-verified-from-source.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/architecture/al-identifiers-must-be-english.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/architecture/clarify-before-building.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/architecture/xliff-translation-workflow.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/architecture/new-file-requires-vscode-refresh.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/architecture/exposed-objects-must-be-in-a-permission-set.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/architecture/shared-project-memory-must-be-in-repo.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/architecture/commit-message-must-include-bc-task-id.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/architecture/branch-merge-to-main-workflow.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/testing/test-setup-must-use-library-codeunit.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/testing/test-data-must-be-random-and-complete.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/testing/tests-must-adapt-to-existing-code.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/testing/test-one-when-per-test.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/testing/ui-test-codeunit-naming.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/testing/test-feature-scenario-tags.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/mcp/api-page-flowfields-must-be-calcfields.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/mcp/stored-derived-fields-must-not-be-exposed-directly.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/mcp/api-page-key-fields-must-be-editable-on-insert.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/mcp/api-page-least-privilege-write-access.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/mcp/agent-must-not-write-business-process-status.md -- https://raw.githubusercontent.com/Curabis/BCQuality/main/custom/knowledge/mcp/bc-mcp-find-active-task-for-branch.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/architecture/pages-must-not-contain-business-logic.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/architecture/namespace-must-be-verified-from-source.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/architecture/al-identifiers-must-be-english.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/architecture/clarify-before-building.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/architecture/xliff-translation-workflow.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/architecture/new-file-requires-vscode-refresh.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/architecture/exposed-objects-must-be-in-a-permission-set.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/architecture/shared-project-memory-must-be-in-repo.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/architecture/commit-message-must-include-bc-task-id.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/architecture/feature-branch-must-merge-to-track-branch.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/testing/test-setup-must-use-library-codeunit.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/testing/test-data-must-be-random-and-complete.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/testing/tests-must-adapt-to-existing-code.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/testing/test-one-when-per-test.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/testing/ui-test-codeunit-naming.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/testing/test-feature-scenario-tags.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/mcp/api-page-flowfields-must-be-calcfields.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/mcp/stored-derived-fields-must-not-be-exposed-directly.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/mcp/api-page-key-fields-must-be-editable-on-insert.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/mcp/api-page-least-privilege-write-access.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/mcp/agent-must-not-write-business-process-status.md +- https://raw.githubusercontent.com/Curabis/BCQuality/stable/custom/knowledge/mcp/bc-mcp-find-active-task-for-branch.md ## Action