feat(ms-ai-architect): Sesjon 20 — B3 create_skill (dvelende, konstruktiv op) [skip-docs]
B3 + Spor B (krav 5+6) KOMPLETT. create_skill er speilbildet av de destruktive ops: merge/saner/retire beviser "ingen kuratert verdi TAPT"; create beviser "ingen sub-bar skill FØDT" (kvalitetsgulv). Ingen ny domene-skill shippet (svar 3) — mekanismen bevist, ikke brukt. - planCreateSkill (ren): genererer scaffold + selv-validerer mot eval.mjs sine EGNE checkers (K2/K3/K5/K6/refTall + K10) — rubrikken har én kilde. Guardrail ok iff alle deterministiske K passerer + K10<terskel + navn ledig. - TEST_DOMAIN_SPEC: kanonisk dvelende-scaffold (born compliant, K5 ratio 1.0). - runCreatePlan (uren): gated dry-run, 0 skriving til skills/. - applyApprovedAction create-gren: re-plan fersk → revalider (drift+kollisjon) → skriv scaffold + persister taksonomi-tillegg → flipp ledger. - applyCategoryAdditions (taxonomy.mjs): additiv, klobrer aldri eksisterende eier. - CLI create-verb i plan-skill-op + apply-skill-op. TDD: ny test-skill-ops-create.test.mjs (16). kb-eval 84→100. Suiter uendret: validate 239 · kb-update 139 · kb-integrity 192/192. Deterministisk eval K1–K10 for de 5 ekte: 0 regresjon. 0 ekte skills/-mutasjon. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
de3a9a483b
commit
e47fc9bd59
5 changed files with 758 additions and 11 deletions
|
|
@ -17,7 +17,7 @@ import { join, dirname } from 'node:path';
|
|||
import { fileURLToPath } from 'node:url';
|
||||
import { splitFrontmatter, extractDescription } from './eval.mjs';
|
||||
import { loadTaxonomy } from '../kb-update/lib/taxonomy.mjs';
|
||||
import { runMergePlan, runSanitizePlan, runRetirePlan } from './lib/skill-ops.mjs';
|
||||
import { runMergePlan, runSanitizePlan, runRetirePlan, runCreatePlan, TEST_DOMAIN_SPEC } from './lib/skill-ops.mjs';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const PLUGIN_ROOT = join(__dirname, '..', '..');
|
||||
|
|
@ -25,6 +25,7 @@ const SKILLS_DIR = join(PLUGIN_ROOT, 'skills');
|
|||
const AGENTS_DIR = join(PLUGIN_ROOT, 'agents');
|
||||
const LEDGER_DATA_DIR = join(__dirname, '..', 'kb-update', 'data');
|
||||
const TAX_DATA_DIR = LEDGER_DATA_DIR;
|
||||
const PROMPTS_FILE = join(__dirname, 'data', 'k1-trigger-prompts.json');
|
||||
|
||||
/** Read the SKILL.md descriptions from disk (read-only). */
|
||||
function loadDescriptions() {
|
||||
|
|
@ -38,6 +39,11 @@ function loadDescriptions() {
|
|||
return out;
|
||||
}
|
||||
|
||||
/** Read the curated K1 trigger-prompt set (boundary-tension source for K10). */
|
||||
function loadPromptSet() {
|
||||
return existsSync(PROMPTS_FILE) ? JSON.parse(readFileSync(PROMPTS_FILE, 'utf8')) : {};
|
||||
}
|
||||
|
||||
function printPlan({ entry, diff, guardrail }) {
|
||||
const g = guardrail;
|
||||
console.log(`\nmerge_skills — DRY-RUN: ${entry.targets.absorbed} -> ${entry.targets.absorber}\n`);
|
||||
|
|
@ -89,11 +95,33 @@ function printRetirePlan({ entry, diff, guardrail }) {
|
|||
console.log(`\nStatus: ${entry.status} (forslag — anvender INGENTING; krever operatør-godkjenning + apply-sesjon).\n`);
|
||||
}
|
||||
|
||||
function printCreatePlan({ entry, scaffold, guardrail }) {
|
||||
const g = guardrail;
|
||||
console.log(`\ncreate_skill — DRY-RUN: ${entry.targets.name}\n`);
|
||||
console.log(`Guardrail (konstruktiv — født compliant ELLER nektet):`);
|
||||
console.log(
|
||||
` navn-ledig=${g.nameAvailable} K2=${g.k2.pass} K3=${g.k3.pass} K5=${g.k5.pass} ` +
|
||||
`K6=${g.k6.pass} refTall=${g.refConsistency.consistent} K10=${g.k10.pass}`,
|
||||
);
|
||||
console.log(` feilede=${g.failed.length ? g.failed.join(', ') : '0'}`);
|
||||
console.log(` => ${g.ok ? 'OK (scaffold passerer K1–K10 deterministisk — trygt å opprette)' : 'FAILED (sub-bar skill — blokkert)'}\n`);
|
||||
console.log(`Scaffold:`);
|
||||
console.log(` ${scaffold.skillMd.path}`);
|
||||
console.log(` ref-filer: ${scaffold.files.length}`);
|
||||
for (const f of scaffold.files) console.log(` • ${f.path}`);
|
||||
if (scaffold.taxonomyAdditions.length) {
|
||||
console.log(` taksonomi-tillegg (additivt):`);
|
||||
for (const t of scaffold.taxonomyAdditions) console.log(` • ${t.category} -> ${t.skill}`);
|
||||
}
|
||||
console.log(`\nStatus: ${entry.status} (forslag — anvender INGENTING; krever operatør-godkjenning + apply-sesjon).\n`);
|
||||
}
|
||||
|
||||
const USAGE =
|
||||
'Usage:\n' +
|
||||
' node scripts/kb-eval/plan-skill-op.mjs merge <absorber> <absorbed> [--json] [--write [--date YYYY-MM-DD]]\n' +
|
||||
' node scripts/kb-eval/plan-skill-op.mjs sanitize <skill> [--json] [--write [--date YYYY-MM-DD]]\n' +
|
||||
' node scripts/kb-eval/plan-skill-op.mjs retire <skill> [--hard] [--json] [--write [--date YYYY-MM-DD]]';
|
||||
' node scripts/kb-eval/plan-skill-op.mjs retire <skill> [--hard] [--json] [--write [--date YYYY-MM-DD]]\n' +
|
||||
' node scripts/kb-eval/plan-skill-op.mjs create <name> [--json] [--write [--date YYYY-MM-DD]]';
|
||||
|
||||
function main() {
|
||||
const args = process.argv.slice(2);
|
||||
|
|
@ -142,6 +170,18 @@ function main() {
|
|||
});
|
||||
printer = printRetirePlan;
|
||||
label = 'retire_skill';
|
||||
} else if (op === 'create' && positional.length >= 2) {
|
||||
result = runCreatePlan(positional[1], {
|
||||
skillsDir: SKILLS_DIR,
|
||||
dataDir: LEDGER_DATA_DIR,
|
||||
write: doWrite,
|
||||
decided_at,
|
||||
...TEST_DOMAIN_SPEC,
|
||||
existingDescriptions: loadDescriptions(),
|
||||
promptSet: loadPromptSet(),
|
||||
});
|
||||
printer = printCreatePlan;
|
||||
label = 'create_skill';
|
||||
} else {
|
||||
console.error(USAGE);
|
||||
process.exit(2);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue