feat(ms-ai-architect): Spor D Steg B — skill-quality lifecycle-gate + score-cache (TDD)
B1: gateSkill(report, name) — pure post-mutation verdict (blocked/provisional/ improvements), wired into apply-skill-op.mjs to re-score the affected skill from fresh disk after create/merge/sanitize-apply. K10 floor enforced immediately; unjudged → provisional + nudge to re-run the judge pass. retire → skipped. B2: buildScoreCache(result) — compact, deterministic cache shape + score-skill.mjs --write [path] → data/skill-score-report.json (always whole-corpus). Gitignored (derived/regenerable; avoids churn in the public repo). Consumed by Steg C surfacing. 8 new tests (tests/kb-eval/test-skill-score-gate.test.mjs). kb-eval 150 pass, validate 239 pass. Live score unchanged: advisor 91, eng/gov/infra/sec 96, 0 < 90. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c578482933
commit
92cd93771b
5 changed files with 294 additions and 3 deletions
|
|
@ -250,6 +250,67 @@ export function scoreReport(report, opts = {}) {
|
|||
return { target, scored, below };
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-score ONE affected skill out of a freshly built corpus report and return a
|
||||
* lifecycle-gate verdict (Spor D, STEG B). Used by apply-skill-op.mjs after a
|
||||
* create/merge/sanitize mutation: the whole corpus is needed for K10 sibling
|
||||
* overlap, but only the affected skill is judged. The deterministic floor (K10)
|
||||
* is enforced immediately via `blocked`; an unjudged skill is `provisional`
|
||||
* (the K1 floor cannot be enforced -> the caller nudges to re-run the judge).
|
||||
* @param {{skills: object[]}} report buildReport() output (fresh disk)
|
||||
* @param {string} skillName the mutated skill to re-score
|
||||
* @param {{target?: number, floorCap?: number}} [opts]
|
||||
* @returns {object} { name, found, score?, meetsTarget?, blocked?, provisional?, judged?, floored?, improvements? }
|
||||
*/
|
||||
export function gateSkill(report, skillName, opts = {}) {
|
||||
const target = opts.target ?? TARGET;
|
||||
const { scored } = scoreReport(report, { ...opts, target });
|
||||
const s = scored.find((x) => x.name === skillName);
|
||||
if (!s) return { name: skillName, found: false };
|
||||
return {
|
||||
name: skillName,
|
||||
found: true,
|
||||
score: s.score,
|
||||
meetsTarget: s.meetsTarget,
|
||||
blocked: !s.meetsTarget,
|
||||
provisional: s.provisional,
|
||||
judged: s.judged,
|
||||
floored: s.floored,
|
||||
improvements: s.improvements,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Project a scoreReport() result into the compact, PURE cache shape persisted as
|
||||
* data/skill-score-report.json and consumed by the STEG C SessionStart surfacing
|
||||
* (which must read the cache, never score live). Drops the verbose criteria[] and
|
||||
* keeps only what the one-liner needs; `below` is a list of names. Deterministic
|
||||
* given an injected `generatedAt` (no Date.now in the pure layer).
|
||||
* @param {{target: number, scored: object[]}} result scoreReport() output
|
||||
* @param {{generatedAt?: string|null}} [opts]
|
||||
* @returns {{generatedAt: string|null, target: number, scored: object[], below: string[]}}
|
||||
*/
|
||||
export function buildScoreCache(result, opts = {}) {
|
||||
const target = result?.target ?? TARGET;
|
||||
const scored = (result?.scored || []).map((s) => ({
|
||||
name: s.name,
|
||||
score: s.score,
|
||||
meetsTarget: s.meetsTarget,
|
||||
provisional: s.provisional,
|
||||
floored: s.floored,
|
||||
judged: s.judged,
|
||||
topFix: s.improvements?.[0]
|
||||
? { key: s.improvements[0].key, label: s.improvements[0].label, fix: s.improvements[0].fix }
|
||||
: null,
|
||||
}));
|
||||
return {
|
||||
generatedAt: opts.generatedAt ?? null,
|
||||
target,
|
||||
scored,
|
||||
below: scored.filter((s) => !s.meetsTarget).map((s) => s.name),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a human-readable quality report (pure). Each skill shows its score and
|
||||
* status; below-target skills list their sorted improvements (biggest weighted
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue