diff --git a/agents/adr-writer-agent.md b/agents/adr-writer-agent.md index 11f6352..84f98fa 100644 --- a/agents/adr-writer-agent.md +++ b/agents/adr-writer-agent.md @@ -2,12 +2,12 @@ name: adr-writer-agent description: | Generates Architecture Decision Records (ADR) in MADR v3.0 format from structured input. - Reads adr-template.md, fills in from session context, and writes to file. + Reads adr-template.md, fills in from session context, and returns the ADR markdown to the main context. Use when architect:adr needs to generate a complete ADR document. Triggers on: ADR generation, decision documentation, architect:adr delegation. model: opus color: orange -tools: ["Read", "Write", "Glob"] +tools: ["Read", "Glob"] --- # ADR Writer Agent @@ -87,9 +87,9 @@ Fill in every section of the MADR template: **Validering og oppfølging**: Concrete next steps with responsible party. -### 4. Write to File +### 4. Return to Main Context -Write the ADR to the location specified in the input. Default: `docs/adr/ADR-NNN-[slug].md` +Return the complete ADR markdown as your final message. The main context (the `/architect:adr` command) writes it to file — do not write files yourself (you run as a subagent). ## Output Format @@ -101,7 +101,7 @@ The generated ADR should be: ## Quality Checklist -Before writing: +Before returning: - [ ] All template sections filled (no placeholders) - [ ] Compliance section included (even if "Not assessed") - [ ] Confidence level reflects actual analysis quality diff --git a/agents/architecture-review-agent.md b/agents/architecture-review-agent.md index ccb189c..6daa152 100644 --- a/agents/architecture-review-agent.md +++ b/agents/architecture-review-agent.md @@ -164,13 +164,13 @@ Read relevant knowledge base files: - `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-advisor/references/architecture/licensing-matrix.md` — License requirements Load domain-specific references only when dimension requires depth (max 2-3 additional): -- AI Act: `responsible-ai/ai-act-compliance-guide.md`, `responsible-ai/ai-act-annex-iii-checklist.md` -- Governance: `responsible-ai/ai-governance-structure-framework.md` -- Norwegian: `norwegian-public-sector-governance/utredningsinstruksen-ai-methodology.md` -- Security: `ai-security-engineering/ai-threat-modeling-stride.md` -- Cost: `cost-optimization/azure-ai-foundry-cost-governance.md`, `cost-optimization/deterministic-cost-calculation-model.md` -- RAG-arkitektur (når løsningen er RAG-/gjenfinningsbasert): `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/rag-architecture/rag-core-patterns.md`, `rag-architecture/agentic-rag-patterns.md`, `rag-architecture/rag-evaluation-frameworks.md` -- MLOps/GenAIOps (når løsningen har produksjons-/livssyklusfokus): `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/mlops-genaiops/genaiops-llm-specific-practices.md`, `mlops-genaiops/monitoring-observability-ml-systems.md`, `mlops-genaiops/model-deployment-strategies-azure.md` +- AI Act: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/responsible-ai/ai-act-compliance-guide.md`, `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/responsible-ai/ai-act-annex-iii-checklist.md` +- Governance: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/responsible-ai/ai-governance-structure-framework.md` +- Norwegian: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/norwegian-public-sector-governance/utredningsinstruksen-ai-methodology.md` +- Security: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-security/references/ai-security-engineering/ai-threat-modeling-stride.md` +- Cost: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-security/references/cost-optimization/azure-ai-foundry-cost-governance.md`, `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-security/references/cost-optimization/deterministic-cost-calculation-model.md` +- RAG-arkitektur (når løsningen er RAG-/gjenfinningsbasert): `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/rag-architecture/rag-core-patterns.md`, `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/rag-architecture/agentic-rag-patterns.md`, `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/rag-architecture/rag-evaluation-frameworks.md` +- MLOps/GenAIOps (når løsningen har produksjons-/livssyklusfokus): `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/mlops-genaiops/genaiops-llm-specific-practices.md`, `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/mlops-genaiops/monitoring-observability-ml-systems.md`, `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/mlops-genaiops/model-deployment-strategies-azure.md` ## Virksomhetskontekst (automatisk) diff --git a/agents/cost-estimation-agent.md b/agents/cost-estimation-agent.md index b424ff6..9081a3b 100644 --- a/agents/cost-estimation-agent.md +++ b/agents/cost-estimation-agent.md @@ -60,9 +60,9 @@ Read these core files: - `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-advisor/references/architecture/cost-models.md` — Cost model templates Load additional files only when estimate requires specific depth: -- PTU: `cost-optimization/ptu-vs-paygo-economics.md` -- Caching: `cost-optimization/semantic-caching-patterns.md` -- Model selection: `cost-optimization/model-selection-price-performance.md` +- PTU: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-security/references/cost-optimization/ptu-vs-paygo-economics.md` +- Caching: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-security/references/cost-optimization/semantic-caching-patterns.md` +- Model selection: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-security/references/cost-optimization/model-selection-price-performance.md` ## Virksomhetskontekst (automatisk) diff --git a/agents/dpia-agent.md b/agents/dpia-agent.md index d10f057..7f70484 100644 --- a/agents/dpia-agent.md +++ b/agents/dpia-agent.md @@ -22,10 +22,10 @@ Read these core files: - `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/responsible-ai/ai-impact-assessment-framework.md` — Konsekvensvurdering Load additional files only when assessment requires specific depth: -- Bias: `responsible-ai/bias-detection-mitigation-strategies.md` -- PII: `ai-security-engineering/pii-detection-norwegian-context.md` -- Data leakage: `ai-security-engineering/data-leakage-prevention-ai.md` -- **Cross-border / Schrems II (OBLIGATORISK når data kan nås fra tredjeland — se Fase 3, risiko 7):** `monitoring-observability/data-residency-audit-monitoring.md` — EDPB seks-stegs-TIA, CLOUD Act/FISA 702/EO 12333-restanalyse, EO 14086/DPF-status, tekniske tilleggstiltak +- Bias: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/responsible-ai/bias-detection-mitigation-strategies.md` +- PII: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-security/references/ai-security-engineering/pii-detection-norwegian-context.md` +- Data leakage: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-security/references/ai-security-engineering/data-leakage-prevention-ai.md` +- **Cross-border / Schrems II (OBLIGATORISK når data kan nås fra tredjeland — se Fase 3, risiko 7):** `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/monitoring-observability/data-residency-audit-monitoring.md` — EDPB seks-stegs-TIA, CLOUD Act/FISA 702/EO 12333-restanalyse, EO 14086/DPF-status, tekniske tilleggstiltak ## Virksomhetskontekst (automatisk) @@ -47,7 +47,7 @@ Før DPIA-vurderingen, sjekk om AI Act-klassifisering er utført: - Integrer deployer-forpliktelser fra `ai-act-deployer-obligations.md` som tiltak i Fase 4 ### Hvis ikke klassifisert -- Spør om det bør gjøres: "Er det gjennomført AI Act-klassifisering for dette systemet? Hvis nei, anbefaler vi `/architect:classify` — men DPIA fortsetter uansett." +- Marker i rapporten at AI Act-klassifisering ikke er dokumentert, og anbefal `/architect:classify` som neste steg (du kjører som subagent uten brukertur — still ingen spørsmål) - Fortsett DPIA som normalt — klassifisering er ikke forutsetning ### Ekstra KB-referanser for AI Act @@ -93,7 +93,7 @@ Risk categories for AI systems: #### Cross-border / Schrems II — obligatorisk TIA (risiko 7) -Når systemet bruker en amerikansk-eid skyleverandør (Azure/Microsoft 365/Foundry) eller data på annen måte kan nås fra tredjeland, **er det ikke nok å navngi risikoen** — load `monitoring-observability/data-residency-audit-monitoring.md` og gjennomfør EDPB seks-stegs Transfer Impact Assessment: +Når systemet bruker en amerikansk-eid skyleverandør (Azure/Microsoft 365/Foundry) eller data på annen måte kan nås fra tredjeland, **er det ikke nok å navngi risikoen** — load `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/monitoring-observability/data-residency-audit-monitoring.md` og gjennomfør EDPB seks-stegs Transfer Impact Assessment: 1. Kartlegg overføringene (inkl. residual: support, troubleshooting, telemetri) 2. Identifiser overføringsverktøyet (adekvansvedtak / SCCs / unntak) @@ -141,9 +141,9 @@ Read the AI system description or architecture proposal. Extract: ### 2. Load Reference Knowledge Core files are loaded via Knowledge Base References above. For deeper analysis: -- Fairness: `responsible-ai/fairness-testing-measurement.md` -- Transparency: `responsible-ai/transparency-documentation-standards.md` -- Human oversight: `responsible-ai/human-in-the-loop-oversight.md` +- Fairness: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/responsible-ai/fairness-testing-measurement.md` +- Transparency: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/responsible-ai/transparency-documentation-standards.md` +- Human oversight: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/responsible-ai/human-in-the-loop-oversight.md` ### 3. Validate Latest Guidance Use `microsoft_docs_search` for: @@ -225,7 +225,7 @@ Follow the output format below with all sections completed. If missing information: - State assumptions clearly -- Request specific details needed +- Note which specific inputs are missing rather than requesting them (you run as a non-interactive subagent with no user turn) - Provide conditional assessments - Note "Kan ikke vurdere [area] uten [info]" diff --git a/agents/research-agent.md b/agents/research-agent.md index db1b188..fb12f15 100644 --- a/agents/research-agent.md +++ b/agents/research-agent.md @@ -34,8 +34,8 @@ Et kompakt sammendrag av virksomhetskonteksten injiseres ambient i hovedøkten v ## Lokal KB-baseline (betinget — RAG / MLOps / engineering-temaer) Når forskningstemaet er RAG, gjenfinning, MLOps eller GenAIOps, les den relevante engineering-kjernefilen **først** som hypotese-baseline — verifiser den deretter mot live Microsoft Learn. KB-en kan være utdatert; **MCP-resultatet er fasit**. -- RAG/gjenfinning: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/rag-architecture/rag-core-patterns.md`, `rag-architecture/agentic-rag-patterns.md` -- MLOps/GenAIOps: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/mlops-genaiops/genaiops-llm-specific-practices.md`, `mlops-genaiops/llm-evaluation-production.md` +- RAG/gjenfinning: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/rag-architecture/rag-core-patterns.md`, `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/rag-architecture/agentic-rag-patterns.md` +- MLOps/GenAIOps: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/mlops-genaiops/genaiops-llm-specific-practices.md`, `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/mlops-genaiops/llm-evaluation-production.md` Les maks 2 baseline-filer. **Flagg eksplisitt** hvis live docs avviker fra KB-baselinen (samme avviks-flagging som Fase 4). diff --git a/agents/ros-analysis-agent.md b/agents/ros-analysis-agent.md index 991329d..6ad95da 100644 --- a/agents/ros-analysis-agent.md +++ b/agents/ros-analysis-agent.md @@ -36,12 +36,12 @@ Alle stier under `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/norwe | Sektor oppdaget (helse/transport/finans/justis/utdanning) | `ros-sector-checklists.md` | | Multi-agent / agent-orkestrering | `ros-maestro-multiagent.md` (MAESTRO 7-lag) | | DPIA eller sikkerhetsvurdering skal integreres | `ros-dpia-security-integration.md` | -| AI Act-dybde i dimensjon 6 | `responsible-ai/ai-act-classification-methodology.md` + `responsible-ai/ai-act-provider-obligations.md` (maks 2) | +| AI Act-dybde i dimensjon 6 | `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/responsible-ai/ai-act-classification-methodology.md` + `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/responsible-ai/ai-act-provider-obligations.md` (maks 2) | ### Referanse (last kun ved eksplisitt behov, ikke default) - `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-security/references/ai-security-engineering/security-scoring-rubrics-6x5.md` — scoringsmønster-referanse - `ros-analyse-ai-systems.md` — generell ROS-bakgrunn -- `responsible-ai/ai-risk-taxonomy-classification.md` — risikotaksonomi +- `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/responsible-ai/ai-risk-taxonomy-classification.md` — risikotaksonomi **Budsjett:** kjerne (4) + betinget (maks 2-3 på trigger) = typisk 5-7 filer. Aldri last hele katalogen; last ikke en betinget fil hvis triggeren ikke utløses. @@ -273,7 +273,7 @@ Risk Levels: Low (1-6), Medium (7-12), High (13-19), Critical (20-25) If missing information: - State assumptions clearly -- Request specific details needed +- Note which specific inputs are missing rather than requesting them (you run as a non-interactive subagent with no user turn) - Provide conditional assessments - Note "Kan ikke vurdere [area] uten [info]" diff --git a/agents/security-assessment-agent.md b/agents/security-assessment-agent.md index b7dad8a..b4f734a 100644 --- a/agents/security-assessment-agent.md +++ b/agents/security-assessment-agent.md @@ -26,9 +26,9 @@ Read these core files: - `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-security/references/ai-security-engineering/ai-threat-modeling-stride.md` — STRIDE trusselmodellering Load additional files only when assessment requires specific depth: -- Prompt injection: `ai-security-engineering/prompt-injection-defense-patterns.md` -- Governance: `responsible-ai/ai-act-compliance-guide.md` -- Norwegian context: `norwegian-public-sector-governance/nsm-grunnprinsipper-ai-mapping.md` +- Prompt injection: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-security/references/ai-security-engineering/prompt-injection-defense-patterns.md` +- Governance: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/responsible-ai/ai-act-compliance-guide.md` +- Norwegian context: `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/norwegian-public-sector-governance/nsm-grunnprinsipper-ai-mapping.md` ## Virksomhetskontekst (automatisk) diff --git a/commands/dpia.md b/commands/dpia.md index d4cdc15..7b68767 100644 --- a/commands/dpia.md +++ b/commands/dpia.md @@ -41,6 +41,7 @@ Gjennomfør en komplett DPIA for følgende AI-system: **Registrerte:** [hvem som berøres] **Behandlingsgrunnlag:** [GDPR art. 6/9] **Kontekst:** [sektor/kontekst — offentlig, privat, finans, helse, etc.] +**AI Act-klassifisering (fra /architect:classify, hvis utført):** [risikonivå + rolle + Annex III-kategori — ellers "ikke klassifisert"] Les kunnskapsbasene (kjerne): - ${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/norwegian-public-sector-governance/dpia-norwegian-methodology-ai.md diff --git a/commands/poc.md b/commands/poc.md index 2546671..9c035c5 100644 --- a/commands/poc.md +++ b/commands/poc.md @@ -34,8 +34,8 @@ Les `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-advisor/references/architecture/poc-temp ### 3b. Les domene-spesifikke mønstre (betinget) Hvis use-caset treffer et engineering-domene, les 1-2 kjernefiler for å forankre scope og suksesskriterier (ikke hele katalogen): -- **RAG / gjenfinning:** `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/rag-architecture/rag-core-patterns.md`, `rag-architecture/rag-evaluation-frameworks.md` — sett målbare gjenfinnings-/grounding-kriterier -- **MLOps / produksjonssetting:** `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/mlops-genaiops/genaiops-llm-specific-practices.md`, `mlops-genaiops/llm-evaluation-production.md` — POC-evaluering + driftskriterier +- **RAG / gjenfinning:** `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/rag-architecture/rag-core-patterns.md`, `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/rag-architecture/rag-evaluation-frameworks.md` — sett målbare gjenfinnings-/grounding-kriterier +- **MLOps / produksjonssetting:** `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/mlops-genaiops/genaiops-llm-specific-practices.md`, `${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-engineering/references/mlops-genaiops/llm-evaluation-production.md` — POC-evaluering + driftskriterier ### 4. Generer POC-plan diff --git a/commands/ros.md b/commands/ros.md index 4234f74..1789d16 100644 --- a/commands/ros.md +++ b/commands/ros.md @@ -43,6 +43,8 @@ Gjennomfør en [komplett / quick] ROS-analyse for følgende AI-system: **Sektor:** [sektor] **Borgermøtende:** [ja/nei] **Kontekst:** [ytterligere kontekst] +**AI Act-klassifisering (dimensjon 6, fra /architect:classify):** [risikonivå + rolle — ellers "ikke klassifisert"] +**DPIA-funn (fra /architect:dpia, hvis utført):** [sentrale personvernrisikoer — ellers "ikke utført"] [**Modus:** Quick (top-10 risikoer, trafikklys) — if --quick] Les kunnskapsbasene per last-kontrakten i agentfilen — kjerne (alltid) + betinget (kun på trigger): @@ -57,7 +59,7 @@ Betinget (kun når triggeren utløses): - ros-sector-checklists.md (hvis relevant sektor oppdaget) - ros-maestro-multiagent.md (hvis multi-agent / agent-orkestrering) - ros-dpia-security-integration.md (hvis DPIA/sikkerhet skal integreres) -- responsible-ai/ai-act-classification-methodology.md + ai-act-provider-obligations.md (hvis AI Act-dybde i dimensjon 6) +- ${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/responsible-ai/ai-act-classification-methodology.md + ${CLAUDE_PLUGIN_ROOT}/skills/ms-ai-governance/references/responsible-ai/ai-act-provider-obligations.md (hvis AI Act-dybde i dimensjon 6) Lever en [komplett ROS-rapport med alle 8 faser / Quick ROS med top-10 og trafikklys]." ``` diff --git a/tests/kb-update/test-rx-p2-wiring.test.mjs b/tests/kb-update/test-rx-p2-wiring.test.mjs new file mode 100644 index 0000000..424aa10 --- /dev/null +++ b/tests/kb-update/test-rx-p2-wiring.test.mjs @@ -0,0 +1,45 @@ +// RX-P2 regression guards: classify→dpia→ros chain wiring (del 1), removal of the +// unexecutable "ask user" subagent instructions (del 2), and single ADR write-ownership +// (del 4). Path anchoring (del 3) + its lint (del 5) are enforced by validate-plugin.sh +// Check 6d via test-validate-plugin.test.mjs. +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; + +const here = dirname(fileURLToPath(import.meta.url)); +const root = join(here, '..', '..'); // tests/kb-update -> plugin root +const read = (rel) => readFileSync(join(root, rel), 'utf8'); + +// --- Del 1: chain wiring — the Task templates must carry explicit chain-data fields --- +test('dpia.md Task template passes AI Act classification as chain-data', () => { + const dpia = read('commands/dpia.md'); + assert.match(dpia, /\*\*AI Act-klassifisering \(fra \/architect:classify/); +}); + +test('ros.md Task template passes AI Act classification (dim. 6) + DPIA findings as chain-data', () => { + const ros = read('commands/ros.md'); + assert.match(ros, /\*\*AI Act-klassifisering \(dimensjon 6/); + assert.match(ros, /\*\*DPIA-funn \(fra \/architect:dpia/); +}); + +// --- Del 2: no unexecutable "ask the user" instructions in Task-spawned subagents --- +test('dpia-agent.md no longer instructs the subagent to ask the user', () => { + const agent = read('agents/dpia-agent.md'); + assert.doesNotMatch(agent, /Spør om det bør gjøres/); + assert.doesNotMatch(agent, /Request specific details needed/); +}); + +test('ros-analysis-agent.md no longer instructs the subagent to ask the user', () => { + const agent = read('agents/ros-analysis-agent.md'); + assert.doesNotMatch(agent, /Request specific details needed/); +}); + +// --- Del 4: adr-writer-agent returns content; the command is the single writer --- +test('adr-writer-agent.md does not carry the Write tool and does not write files', () => { + const agent = read('agents/adr-writer-agent.md'); + const toolsLine = agent.split('\n').find((l) => l.startsWith('tools:')) || ''; + assert.doesNotMatch(toolsLine, /Write/, 'adr-writer-agent must not have the Write tool (subagents never write)'); + assert.doesNotMatch(agent, /### 4\. Write to File/); +}); diff --git a/tests/kb-update/test-validate-plugin.test.mjs b/tests/kb-update/test-validate-plugin.test.mjs index 6040773..5f4709d 100644 --- a/tests/kb-update/test-validate-plugin.test.mjs +++ b/tests/kb-update/test-validate-plugin.test.mjs @@ -6,6 +6,7 @@ import assert from 'node:assert/strict'; import { execFileSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; import { dirname, join } from 'node:path'; +import { writeFileSync, rmSync } from 'node:fs'; const here = dirname(fileURLToPath(import.meta.url)); const pluginRoot = join(here, '..', '..'); // tests/kb-update -> plugin root @@ -23,3 +24,42 @@ test('validate-plugin.sh passes (frontmatter, encoding, KB refs, plugin.json, in assert.match(out, /VALIDATION PASSED/); assert.doesNotMatch(out, /VALIDATION FAILED/); }); + +// RX-P2: prove Check 6d has teeth — an unanchored reference-subdir path must be caught. +// Without a negative probe, the positive test above only proves the plugin is currently +// clean, not that 6d actually fires. +test('validate-plugin.sh Check 6d catches an unanchored reference-subdir path (negative probe)', () => { + const probe = join(pluginRoot, 'agents', '__rx_p2_6d_probe__.md'); + writeFileSync( + probe, + [ + '---', + 'name: rx-p2-6d-probe', + 'description: temporary probe for the 6d negative test', + 'model: opus', + 'color: blue', + 'tools: ["Read"]', + '---', + '', + '# Probe', + '', + 'Load: `responsible-ai/ai-act-compliance-guide.md`', + '', + ].join('\n'), + ); + try { + let failed = false; + let out = ''; + try { + out = execFileSync('bash', [script], { encoding: 'utf8', cwd: pluginRoot }); + } catch (err) { + failed = true; + out = `${err.stdout || ''}${err.stderr || ''}`; + } + assert.ok(failed, 'validate-plugin.sh must exit non-zero when a bare reference-subdir path is present'); + assert.match(out, /bare reference-subdir path/); + assert.match(out, /__rx_p2_6d_probe__\.md/); + } finally { + rmSync(probe, { force: true }); + } +}); diff --git a/tests/validate-plugin.sh b/tests/validate-plugin.sh index 9a09374..ea7be73 100755 --- a/tests/validate-plugin.sh +++ b/tests/validate-plugin.sh @@ -349,6 +349,33 @@ else pass "No sonnet/haiku pinned in Task delegations" fi +# 6d: every bundled reference-subdir path must be ${CLAUDE_PLUGIN_ROOT}-anchored. +# Short-forms like `responsible-ai/foo.md` (a reference subdir + file, without the +# full skills//references/ prefix) resolve only in dev cwd -- installed mode +# breaks. A path is anchored iff the subdir is immediately preceded by '/' +# (.../references//). The (^|[^A-Za-z0-9._/-]) guard fires on bare short-forms +# (preceded by backtick/space/comma/colon) while skipping anchored paths (preceded +# by '/') and compound subdir names (e.g. 'architecture' inside 'rag-architecture', +# preceded by '-'). +REF_SUBDIRS='architecture|copilot-extensibility|development|platforms|prompt-engineering|agent-orchestration|api-management|azure-ai-services|data-engineering|mlops-genaiops|multi-modal|rag-architecture|monitoring-observability|norwegian-public-sector-governance|responsible-ai|bcdr|hybrid-edge|ai-security-engineering|cost-optimization|performance-scalability' +subdir_offenders=0 +for f in "$PLUGIN_ROOT"/commands/*.md "$PLUGIN_ROOT"/agents/*.md; do + [ -f "$f" ] || continue + rel="${f#$PLUGIN_ROOT/}" + bare="$(grep -nE "(^|[^A-Za-z0-9._/-])($REF_SUBDIRS)/[A-Za-z0-9._-]+\.md" "$f" || true)" + if [ -n "$bare" ]; then + while IFS= read -r bline; do + [ -n "$bline" ] || continue + lineno="${bline%%:*}" + fail "$rel:$lineno: bare reference-subdir path (needs \${CLAUDE_PLUGIN_ROOT}/skills//references/ prefix for installed mode)" + subdir_offenders=$((subdir_offenders + 1)) + done <<< "$bare" + fi +done +if [ "$subdir_offenders" -eq 0 ]; then + pass "All reference-subdir paths are \${CLAUDE_PLUGIN_ROOT}-anchored" +fi + echo "" # -------------------------------------------------------