feat(ms-ai-architect): R22 decision-b Enhet 3 — Status-backfill 25 none + ai-act dual-header-dedup 4 (Missing Status/Last-updated 29+4→0) [skip-docs]
To operasjoner, én økt (⊥ R7), begge ren metadata-normalisering (verdi aldri fabrikkert). Premiss-korreksjon (ground truth 2026-07-07): roadmap sa «27 none + 4 ai-act». Målt: 29 mangler bold **Status:** = 25 rene none + 4 ai-act (plain Status: GA). De «27» inkluderte 2 for mye — 2 filer (custom-dashboards-ai-operations, zero-trust-ai-services) har bold **Status:** KUN forbi byte 500 (present for full-fil-audit, usynlig for 500B header-parser) → egen header-slanking-residual (§8-register), utenfor Enhet 3. Op A — Status-backfill 25 rene none: utvidet backfill-status.mjs MANIFEST 14→39 (samme statusForFile + insertMetaField + hard per-fil-invariant, idempotent skip på de 14 R21-gjorte). Alle 25 → **Status:** Established Practice (ingen matcher template|matrix|benchmarks|register). Diff +25/-0. Op B — ai-act dual-header-dedup (4 filer): ny driver dedup-plain-header.mjs + 2 rene primitiver i transform.mjs — boldifyPlainField (plain→bold, verdi bevart byte-eksakt, header-scoped, idempotent) + dropRedundantPlainField (sletter plain KUN når bold m/ identisk verdi beviser redundans; kaster ved avvik/manglende bold). Per fil: plain Last updated: + Status: GA → bold (2026-06-18/2026-02, GA bevart), redundant plain Category: fjernet. Hard per-fil-invariant (net -1 linje, begge felt bold m/ bevart verdi, ingen plain-header igjen, body byte-identisk). Diff -12/+8. Verifisering: test-backfill-status 8/8 + test-dedup-plain-header 13/13; audit Missing Status 29→0, Missing English Last updated 4→0; skills-diff 29 filer +33/-12 (kun **Status:** + 8 bold-swaps), diff-kontekst inspisert per fil; begge drivere idempotent (re-run 0 writes); suite 806/806 exit 0; none=8 uendret (Enhet 4).
This commit is contained in:
parent
1ab4fc34cf
commit
de0d94cbc1
35 changed files with 510 additions and 57 deletions
|
|
@ -1,23 +1,28 @@
|
|||
// tests/kb-update/test-backfill-status.test.mjs
|
||||
// TDD for R21 — Status backfill on the 18 English-dialect not-due reference files that
|
||||
// lack **Status:**. The applier (backfill-status.mjs) is a manifest-driven driver over the
|
||||
// already-tested insertMetaField primitive; the ONLY new production logic is the pure
|
||||
// deterministic value rule statusForFile() + the frozen MANIFEST. This suite pins both:
|
||||
// TDD for the Status-backfill mechanism (R21 + Enhet 3). The applier (backfill-status.mjs)
|
||||
// is a manifest-driven driver over the already-tested insertMetaField primitive; the ONLY
|
||||
// new production logic is the pure deterministic value rule statusForFile() + the frozen
|
||||
// MANIFEST. This suite pins both:
|
||||
// - statusForFile: filename token (template|matrix|benchmarks|register) → 'Reference',
|
||||
// else 'Established Practice'. Operator-approved vocabulary (2026-07-06), scope-confirmed
|
||||
// 18 files (ground truth: not-due ∩ missing-**Status:** ∩ English-dialect).
|
||||
// - MANIFEST self-consistency: 18 distinct entries, each value === statusForFile(path).
|
||||
// The 21 Last-updated-relabels + 5 unreliable-git + 3 Norwegian-dialect-Status are OUT of
|
||||
// R21 (corrected decision-b residual) and intentionally NOT in this manifest.
|
||||
// else 'Established Practice'. Operator-approved vocabulary (2026-07-06).
|
||||
// - MANIFEST self-consistency: distinct entries, each value === statusForFile(path).
|
||||
//
|
||||
// Scope history:
|
||||
// R21 (2026-07-06) — 14 English-dialect advisor/architecture files (7 Reference + 7 EP).
|
||||
// Enhet 3 (2026-07-07) — +25 non-advisor "none"-dialect files that lack **Status:** entirely
|
||||
// (ground-truth measured: 25, NOT the roadmap's "27" — 2 of the roadmap count were files
|
||||
// whose bold **Status:** sits past byte 500, i.e. present-but-header-invisible, a separate
|
||||
// header-slanking residual, not a missing-Status file). None of the 25 match the artifact
|
||||
// token → all 'Established Practice'. The 4 dual-header ai-act-* files are handled by the
|
||||
// plain→bold dedup driver (dedup-plain-header.mjs), NOT here — they carry an authored
|
||||
// `Status: GA` we preserve, so they must stay OUT of this derive-a-value manifest.
|
||||
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { statusForFile, MANIFEST, ALLOWED_STATUS } from '../../scripts/kb-update/backfill-status.mjs';
|
||||
|
||||
// The 14 scope-confirmed R21 targets (clean advisor/architecture). The 4 ms-ai-governance
|
||||
// ai-act-* files that matched the token rule are NOT here: they carry a plain-text `Status: GA`
|
||||
// in a dual-header block (bold-regex-invisible), so they are deferred to the decision-b residual.
|
||||
const REFERENCE = [
|
||||
// The 14 R21 advisor targets (clean advisor/architecture).
|
||||
const ADVISOR_REFERENCE = [
|
||||
'adr-template.md',
|
||||
'ai-utredning-template.md',
|
||||
'capacity-feasibility-benchmarks.md',
|
||||
|
|
@ -26,7 +31,7 @@ const REFERENCE = [
|
|||
'poc-template.md',
|
||||
'source-traceability-assumption-register.md',
|
||||
];
|
||||
const ESTABLISHED = [
|
||||
const ADVISOR_ESTABLISHED = [
|
||||
'alternativanalyse-methodology.md',
|
||||
'cost-models.md',
|
||||
'decision-trees.md',
|
||||
|
|
@ -36,12 +41,42 @@ const ESTABLISHED = [
|
|||
'security.md',
|
||||
];
|
||||
|
||||
// The 25 Enhet-3 non-advisor targets (missing **Status:** entirely). All → Established
|
||||
// Practice (none carries a template/matrix/benchmarks/register token).
|
||||
const NON_ADVISOR_ESTABLISHED = [
|
||||
'skills/ms-ai-engineering/references/mlops-genaiops/cost-optimization-mlops-pipelines.md',
|
||||
'skills/ms-ai-engineering/references/mlops-genaiops/feedback-loops-continuous-improvement.md',
|
||||
'skills/ms-ai-engineering/references/mlops-genaiops/genaiops-llm-specific-practices.md',
|
||||
'skills/ms-ai-engineering/references/mlops-genaiops/governance-audit-ml-operations.md',
|
||||
'skills/ms-ai-engineering/references/mlops-genaiops/inferencing-optimization-caching.md',
|
||||
'skills/ms-ai-engineering/references/mlops-genaiops/infrastructure-as-code-mlops.md',
|
||||
'skills/ms-ai-engineering/references/mlops-genaiops/llm-evaluation-production.md',
|
||||
'skills/ms-ai-engineering/references/mlops-genaiops/mlops-security-access-control.md',
|
||||
'skills/ms-ai-engineering/references/mlops-genaiops/mlops-teams-collaboration-tools.md',
|
||||
'skills/ms-ai-engineering/references/mlops-genaiops/model-deployment-strategies-azure.md',
|
||||
'skills/ms-ai-engineering/references/mlops-genaiops/monitoring-observability-ml-systems.md',
|
||||
'skills/ms-ai-engineering/references/mlops-genaiops/prompt-flow-production-deployment.md',
|
||||
'skills/ms-ai-engineering/references/mlops-genaiops/responsible-ai-mlops-integration.md',
|
||||
'skills/ms-ai-governance/references/monitoring-observability/anomaly-detection-ai-systems.md',
|
||||
'skills/ms-ai-governance/references/monitoring-observability/azure-monitor-setup-ai-workloads.md',
|
||||
'skills/ms-ai-governance/references/monitoring-observability/log-analytics-kql-ai-queries.md',
|
||||
'skills/ms-ai-governance/references/monitoring-observability/token-usage-tracking-attribution.md',
|
||||
'skills/ms-ai-governance/references/responsible-ai/ai-center-of-excellence-setup.md',
|
||||
'skills/ms-ai-governance/references/responsible-ai/ai-governance-structure-framework.md',
|
||||
'skills/ms-ai-governance/references/responsible-ai/red-teaming-ai-models.md',
|
||||
'skills/ms-ai-security/references/ai-security-engineering/ai-red-team-operations-practical.md',
|
||||
'skills/ms-ai-security/references/ai-security-engineering/data-leakage-prevention-ai.md',
|
||||
'skills/ms-ai-security/references/ai-security-engineering/secure-model-deployment-hardening.md',
|
||||
'skills/ms-ai-security/references/ai-security-engineering/security-copilot-integration.md',
|
||||
'skills/ms-ai-security/references/ai-security-engineering/supply-chain-security-ai-models.md',
|
||||
];
|
||||
|
||||
test('statusForFile: artifact-token filenames → Reference', () => {
|
||||
for (const b of REFERENCE) assert.equal(statusForFile(b), 'Reference', b);
|
||||
for (const b of ADVISOR_REFERENCE) assert.equal(statusForFile(b), 'Reference', b);
|
||||
});
|
||||
|
||||
test('statusForFile: methodology/guidance/obligation filenames → Established Practice', () => {
|
||||
for (const b of ESTABLISHED) assert.equal(statusForFile(b), 'Established Practice', b);
|
||||
for (const b of ADVISOR_ESTABLISHED) assert.equal(statusForFile(b), 'Established Practice', b);
|
||||
});
|
||||
|
||||
test('statusForFile: keys on basename only, not on ancestor folders', () => {
|
||||
|
|
@ -52,29 +87,38 @@ test('statusForFile: keys on basename only, not on ancestor folders', () => {
|
|||
});
|
||||
|
||||
test('statusForFile: always returns an allowed value', () => {
|
||||
for (const b of [...REFERENCE, ...ESTABLISHED, 'anything-else.md']) {
|
||||
for (const b of [...ADVISOR_REFERENCE, ...ADVISOR_ESTABLISHED, 'anything-else.md']) {
|
||||
assert.ok(ALLOWED_STATUS.includes(statusForFile(b)), b);
|
||||
}
|
||||
});
|
||||
|
||||
test('MANIFEST: exactly 14 distinct entries, each value === statusForFile(path)', () => {
|
||||
assert.equal(MANIFEST.length, 14);
|
||||
test('MANIFEST: exactly 39 distinct entries, each value === statusForFile(path)', () => {
|
||||
assert.equal(MANIFEST.length, 39);
|
||||
const paths = new Set(MANIFEST.map((m) => m.path));
|
||||
assert.equal(paths.size, 14, 'duplicate path in MANIFEST');
|
||||
assert.equal(paths.size, 39, 'duplicate path in MANIFEST');
|
||||
for (const { path, status } of MANIFEST) {
|
||||
assert.ok(ALLOWED_STATUS.includes(status), `bad status for ${path}`);
|
||||
assert.equal(status, statusForFile(path), `manifest/rule mismatch for ${path}`);
|
||||
}
|
||||
});
|
||||
|
||||
test('MANIFEST: 7 Reference + 7 Established Practice (scope-confirmed split)', () => {
|
||||
test('MANIFEST: 7 Reference + 32 Established Practice (R21 14 + Enhet 3 25)', () => {
|
||||
const ref = MANIFEST.filter((m) => m.status === 'Reference').length;
|
||||
const est = MANIFEST.filter((m) => m.status === 'Established Practice').length;
|
||||
assert.equal(ref, 7);
|
||||
assert.equal(est, 7);
|
||||
assert.equal(est, 32);
|
||||
});
|
||||
|
||||
test('MANIFEST: excludes the 4 dual-header ai-act-* files (decision-b residual)', () => {
|
||||
test('MANIFEST: all 25 Enhet-3 non-advisor targets present and Established Practice', () => {
|
||||
for (const p of NON_ADVISOR_ESTABLISHED) {
|
||||
const entry = MANIFEST.find((m) => m.path === p);
|
||||
assert.ok(entry, `missing from MANIFEST: ${p}`);
|
||||
assert.equal(entry.status, 'Established Practice', p);
|
||||
assert.equal(statusForFile(p), 'Established Practice', p);
|
||||
}
|
||||
});
|
||||
|
||||
test('MANIFEST: excludes the 4 dual-header ai-act-* files (handled by dedup driver, authored Status: GA preserved)', () => {
|
||||
const deferred = [
|
||||
'ai-act-classification-methodology.md',
|
||||
'ai-act-deployer-obligations.md',
|
||||
|
|
@ -82,6 +126,6 @@ test('MANIFEST: excludes the 4 dual-header ai-act-* files (decision-b residual)'
|
|||
'ai-act-provider-obligations.md',
|
||||
];
|
||||
for (const d of deferred) {
|
||||
assert.ok(!MANIFEST.some((m) => m.path.endsWith(d)), `${d} must be deferred, not in MANIFEST`);
|
||||
assert.ok(!MANIFEST.some((m) => m.path.endsWith(d)), `${d} must not be in the Status-derive MANIFEST`);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
123
tests/kb-update/test-dedup-plain-header.test.mjs
Normal file
123
tests/kb-update/test-dedup-plain-header.test.mjs
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
// tests/kb-update/test-dedup-plain-header.test.mjs
|
||||
// TDD for Enhet 3 Op B — the dual-header plain→bold dedup on the 4 ms-ai-governance
|
||||
// ai-act-* files. Those files carry an authored, PLAIN-TEXT block
|
||||
// Last updated: <date>
|
||||
// Status: GA
|
||||
// Category: <value> ← redundant: a bold **Category:** <same value> already exists
|
||||
// (R20 inserted the bold Category; the plain block is the original dual header). This is NOT a
|
||||
// derive-a-value backfill (backfill-status.mjs owns that) — the authored values are PRESERVED
|
||||
// byte-exact; only their label decoration is normalized to bold, and the provably-redundant
|
||||
// plain Category line is removed. Two new pure primitives + a pure composition are pinned here.
|
||||
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { boldifyPlainField, dropRedundantPlainField } from '../../scripts/kb-update/lib/transform.mjs';
|
||||
import { dedupPlainHeader, MANIFEST } from '../../scripts/kb-update/dedup-plain-header.mjs';
|
||||
|
||||
// An ai-act-shaped fixture: bold Type+Category (Category from R20), then the plain block,
|
||||
// then a body that itself mentions "Status:" in prose (must never be touched).
|
||||
const FIXTURE = [
|
||||
'# EU AI Act — Systematisk Klassifiseringsmetodikk',
|
||||
'**Type:** regulatory',
|
||||
'**Category:** Responsible AI & Governance',
|
||||
'',
|
||||
'Last updated: 2026-06-18',
|
||||
'Status: GA',
|
||||
'Category: Responsible AI & Governance',
|
||||
'',
|
||||
'---',
|
||||
'',
|
||||
'## Innhold',
|
||||
'',
|
||||
'A body paragraph that says Status: draft in prose — must be left alone.',
|
||||
'',
|
||||
].join('\n');
|
||||
|
||||
// ── boldifyPlainField ────────────────────────────────────────────────────────
|
||||
test('boldifyPlainField: plain header field → bold, value preserved byte-exact', () => {
|
||||
const out = boldifyPlainField(FIXTURE, 'Last updated');
|
||||
assert.ok(out.includes('**Last updated:** 2026-06-18'), 'bold line present');
|
||||
assert.ok(!/^Last updated:/m.test(out.split('\n---')[0]), 'plain header line gone');
|
||||
});
|
||||
|
||||
test('boldifyPlainField: idempotent — a bold field already present is unchanged', () => {
|
||||
const once = boldifyPlainField(FIXTURE, 'Status');
|
||||
const twice = boldifyPlainField(once, 'Status');
|
||||
assert.equal(twice, once);
|
||||
});
|
||||
|
||||
test('boldifyPlainField: no plain field in header → unchanged', () => {
|
||||
assert.equal(boldifyPlainField(FIXTURE, 'Nonexistent'), FIXTURE);
|
||||
});
|
||||
|
||||
test('boldifyPlainField: never touches a match in the body (below the header region)', () => {
|
||||
const out = boldifyPlainField(FIXTURE, 'Status');
|
||||
assert.ok(out.includes('says Status: draft in prose'), 'body prose untouched');
|
||||
// exactly one bold Status inserted (the header one), body "Status:" not bolded
|
||||
assert.equal((out.match(/\*\*Status:\*\*/g) || []).length, 1);
|
||||
});
|
||||
|
||||
test('boldifyPlainField: body byte-identical (only the header line changes)', () => {
|
||||
const out = boldifyPlainField(FIXTURE, 'Status');
|
||||
const bodyOf = (c) => c.slice(c.indexOf('\n---'));
|
||||
assert.equal(bodyOf(out), bodyOf(FIXTURE));
|
||||
});
|
||||
|
||||
// ── dropRedundantPlainField ──────────────────────────────────────────────────
|
||||
test('dropRedundantPlainField: drops the plain line when a bold field with the same value exists', () => {
|
||||
const out = dropRedundantPlainField(FIXTURE, 'Category');
|
||||
const header = out.split('\n---')[0];
|
||||
assert.ok(/\*\*Category:\*\* Responsible AI & Governance/.test(header), 'bold Category kept');
|
||||
assert.ok(!/^Category:/m.test(header), 'plain Category removed');
|
||||
assert.equal(out.split('\n').length, FIXTURE.split('\n').length - 1, 'exactly one line removed');
|
||||
});
|
||||
|
||||
test('dropRedundantPlainField: throws when plain value ≠ bold value (not redundant, human decision)', () => {
|
||||
const mismatched = FIXTURE.replace('Category: Responsible AI & Governance', 'Category: Something Else');
|
||||
assert.throws(() => dropRedundantPlainField(mismatched, 'Category'), /not redundant|≠/);
|
||||
});
|
||||
|
||||
test('dropRedundantPlainField: throws when no bold field exists to prove redundancy', () => {
|
||||
const noBold = FIXTURE.replace('**Category:** Responsible AI & Governance\n', '');
|
||||
assert.throws(() => dropRedundantPlainField(noBold, 'Category'), /no bold/i);
|
||||
});
|
||||
|
||||
test('dropRedundantPlainField: no-op when the plain line is absent (idempotent)', () => {
|
||||
const once = dropRedundantPlainField(FIXTURE, 'Category');
|
||||
assert.equal(dropRedundantPlainField(once, 'Category'), once);
|
||||
});
|
||||
|
||||
// ── dedupPlainHeader (full composition) ──────────────────────────────────────
|
||||
test('dedupPlainHeader: boldifies Last updated + Status, drops redundant plain Category', () => {
|
||||
const out = dedupPlainHeader(FIXTURE);
|
||||
const header = out.split('\n---')[0];
|
||||
assert.ok(/\*\*Last updated:\*\* 2026-06-18/.test(header), 'Last updated bolded, value preserved');
|
||||
assert.ok(/\*\*Status:\*\* GA/.test(header), 'Status bolded, GA preserved');
|
||||
assert.equal((header.match(/\*\*Category:\*\*/g) || []).length, 1, 'exactly one bold Category');
|
||||
assert.ok(!/^(Last updated|Status|Category):/m.test(header), 'no plain header fields remain');
|
||||
});
|
||||
|
||||
test('dedupPlainHeader: net one line removed, body byte-identical', () => {
|
||||
const out = dedupPlainHeader(FIXTURE);
|
||||
assert.equal(out.split('\n').length, FIXTURE.split('\n').length - 1);
|
||||
const bodyOf = (c) => c.slice(c.indexOf('\n---'));
|
||||
assert.equal(bodyOf(out), bodyOf(FIXTURE));
|
||||
});
|
||||
|
||||
test('dedupPlainHeader: idempotent — a second pass is a no-op', () => {
|
||||
const once = dedupPlainHeader(FIXTURE);
|
||||
assert.equal(dedupPlainHeader(once), once);
|
||||
});
|
||||
|
||||
// ── MANIFEST ─────────────────────────────────────────────────────────────────
|
||||
test('MANIFEST: exactly the 4 dual-header ai-act-* files', () => {
|
||||
assert.equal(MANIFEST.length, 4);
|
||||
assert.equal(new Set(MANIFEST).size, 4, 'no duplicates');
|
||||
const expected = [
|
||||
'skills/ms-ai-governance/references/responsible-ai/ai-act-classification-methodology.md',
|
||||
'skills/ms-ai-governance/references/responsible-ai/ai-act-deployer-obligations.md',
|
||||
'skills/ms-ai-governance/references/responsible-ai/ai-act-fria-template.md',
|
||||
'skills/ms-ai-governance/references/responsible-ai/ai-act-provider-obligations.md',
|
||||
];
|
||||
for (const p of expected) assert.ok(MANIFEST.includes(p), `missing ${p}`);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue