feat(ms-ai-architect): Spor D Steg C — skill-quality SessionStart-surfacing (TDD) [skip-docs]

summarizeSkillQuality(cache) (pure) in detection-schedule.mjs: one-liner
"Skill-kvalitet: N skills < 90 % (navn)"; null when all skills meet target,
when the cache is missing (gitignored → absent in a fresh clone), or when the
shape is malformed. Reads the CACHED skill-score-report.json (from Steg B) —
never scores live (buildReport reads ~400 ref-files). Wired into
session-start-context.mjs after the course-signals block (same
existsSync/try-catch pattern). 7 new tests (kb-update 316 → 323).

[skip-docs]: README is the public end-user doc; skill-quality scoring is
maintainer-only tooling (the cache is gitignored, so the signal never surfaces
for end-users). The right doc homes ARE updated: CLAUDE.md hook table + a
caveat note (this commit), and docs/skill-quality-scoring-plan.md §3 komponent 4.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-06-23 18:38:35 +02:00
commit 97ebcd737a
4 changed files with 156 additions and 1 deletions

View file

@ -11,6 +11,7 @@ import {
shouldRunDetection,
summarizeSkillLifecycle,
summarizeCourses,
summarizeSkillQuality,
} from '../../scripts/kb-update/lib/detection-schedule.mjs';
import {
resolveOrgDir,
@ -203,6 +204,21 @@ if (existsSync(courseReportPath)) {
}
}
// Skill-quality score signals (Spor D / Steg C) — read-only one-liner; never
// spawns, never scores live. Reads the CACHED skill-score-report.json (written
// by `score-skill.mjs --write`). The cache is gitignored => absent in a fresh
// clone, so this surfaces only for a maintainer who has produced it locally;
// summarizeSkillQuality tolerates the missing/malformed case → null.
const scoreCachePath = join(pluginRoot, 'scripts', 'kb-eval', 'data', 'skill-score-report.json');
if (existsSync(scoreCachePath)) {
try {
const qualitySummary = summarizeSkillQuality(JSON.parse(readFileSync(scoreCachePath, 'utf8')));
if (qualitySummary) parts.push(qualitySummary);
} catch {
// Ignore — advisory only
}
}
if (nearestDeadline) {
parts.push(`EU AI Act: ${nearestDeadline.daysLeft} dager til ${nearestDeadline.label}. Kjør /architect:classify`);
}