fix(ms-ai-architect): Enhet 3b — dedup dual-**Dato:** i 5 mlops-genaiops-filer (Created-relabel/drop, git-verifisert) [skip-docs]
Løser dual-header der filer bærer BÅDE **Dato:** (opprettelse) OG **Last updated:** (endring). Ground truth 2026-07-16 + git first-commit-map (2026-04-08 for alle 5): - 4 distinkte (**Dato:** 2026-02-04, FØR git first-commit → ekte opprettelsesdato): relabel **Dato:** → **Created:**, verdi byte-bevart (norsk→engelsk label-rename). - 1 identisk (mlops-security-access-control: **Dato:**=**Last updated:**=2026-06-19, ETTER git first-commit → metadata-artefakt, ikke ekte opprettelsesdato): drop redundant **Dato:**. Relabel ville påstått falsk opprettelsesdato — drop er sannferdig. Ny ren primitiv dropRedundantBoldField (kaster uten identisk-verdi bevis-felt), gjenbrukt relabelHeaderDialect m/ CREATED_MAP. Manifest-drevet dedup-dato.mjs med hard per-fil-invariant FØR skriv (relabel: 1 linje, kun label-token; drop: net -1, Last updated bevart), atomicWriteSync, idempotent. Ingen validator håndhever lukket feltliste → **Created:** er additiv/konform. +15 tester (dropRedundantBoldField, CREATED_MAP-relabel, applyOp, manifest, 2 corpus- guards) + oppdatert stale Enhet-2 carve-out-guard til post-3b-sannhet. Suite 910/910 exit 0. validate-plugin 250 PASS/0 FAIL. Datoløse dual-**Dato:**-filer 5→0.
This commit is contained in:
parent
7b6025a731
commit
f094e242d1
9 changed files with 394 additions and 10 deletions
164
scripts/kb-update/dedup-dato.mjs
Normal file
164
scripts/kb-update/dedup-dato.mjs
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
#!/usr/bin/env node
|
||||
// dedup-dato.mjs — Enhet 3b (2026-07-16, ⊥ R7). Resolve the dual-**Dato:** header on the 5
|
||||
// mlops-genaiops files that carry BOTH a bold **Dato:** (creation) AND a bold **Last updated:**
|
||||
// (modification).
|
||||
//
|
||||
// Ground truth 2026-07-16, re-measured against the committed corpus + the git first-commit
|
||||
// "Created-map" (git first-commit = 2026-04-08 for all 5):
|
||||
// - 4 files carry a DISTINCT creation date — **Dato:** 2026-02-04, authored BEFORE the git
|
||||
// first-commit → a genuine creation date. Action: RELABEL **Dato:** → **Created:**, value
|
||||
// byte-preserved (the same norsk→english label-rename class as Enhet 1/2; **Created:** is a
|
||||
// new-but-additive header label — no validator enforces a closed field list).
|
||||
// - 1 file (mlops-security-access-control) carries IDENTICAL dates — **Dato:** = **Last updated:**
|
||||
// = 2026-06-19, both AFTER the git first-commit → NOT a genuine creation date (a metadata-pass
|
||||
// artifact). Action: DROP the redundant **Dato:**. Relabeling it to **Created:** 2026-06-19
|
||||
// would assert a FALSE creation date, so removal is the truthful action (the Created-map is
|
||||
// what distinguishes the two cases).
|
||||
//
|
||||
// Never derives a value; never deletes a field it cannot prove redundant (dropRedundantBoldField
|
||||
// THROWS unless a bold **Last updated:** with the IDENTICAL value proves it). A hard per-file
|
||||
// invariant is asserted BEFORE any write:
|
||||
// relabel — exactly ONE line changed, that line is the old line with ONLY the label token
|
||||
// swapped (**Dato:**→**Created:**) and the frozen value intact; line count unchanged;
|
||||
// body byte-identical.
|
||||
// drop — exactly ONE line removed (the **Dato:** line); no **Dato:** remains in the header;
|
||||
// **Last updated:** survives; body byte-identical.
|
||||
// Idempotent: a re-run finds **Dato:** gone and is a no-op. Aborts, writing nothing, on any drift.
|
||||
//
|
||||
// Recovery contract: writes are crash-safe (atomicWriteSync tmp+rename — a reader sees the old
|
||||
// file or the new one, never a partial); an interrupted run is recovered by re-running (idempotent).
|
||||
//
|
||||
// Usage: node scripts/kb-update/dedup-dato.mjs [--dry]
|
||||
import { readFileSync, existsSync, realpathSync } from 'node:fs';
|
||||
import { join, dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dropRedundantBoldField } from './lib/transform.mjs';
|
||||
import { relabelHeaderDialect } from './relabel-dialect.mjs';
|
||||
import { atomicWriteSync } from './lib/atomic-write.mjs';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const PLUGIN_ROOT = join(__dirname, '..', '..');
|
||||
const DIR = 'skills/ms-ai-engineering/references/mlops-genaiops';
|
||||
|
||||
// The single norsk→english label pair for the relabel action. **Created:** is intentionally NOT in
|
||||
// relabel-dialect.mjs's LABEL_MAP (that pass is Sist oppdatert/Kategori) nor relabel-dato.mjs's map
|
||||
// (that maps **Dato:**→**Last updated:** for the 16 "rene" single-date files) — the 5 dual files
|
||||
// were deliberately excluded there and are resolved only here.
|
||||
export const CREATED_MAP = [['**Dato:**', '**Created:**']];
|
||||
|
||||
// The label whose identical value proves a **Dato:** redundant in the drop case.
|
||||
export const DROP_LABEL = 'Dato';
|
||||
export const PROOF_LABEL = 'Last updated';
|
||||
|
||||
// Frozen manifest — the 5 dual-**Dato:** mlops-genaiops files (ground truth 2026-07-16). `created`
|
||||
// freezes the authored creation date the relabel must preserve; a corpus drift where the value
|
||||
// changed is caught by the per-file invariant below.
|
||||
export const MANIFEST = [
|
||||
{ rel: `${DIR}/feedback-loops-continuous-improvement.md`, action: 'relabel', created: '2026-02-04' },
|
||||
{ rel: `${DIR}/genaiops-llm-specific-practices.md`, action: 'relabel', created: '2026-02-04' },
|
||||
{ rel: `${DIR}/model-deployment-strategies-azure.md`, action: 'relabel', created: '2026-02-04' },
|
||||
{ rel: `${DIR}/prompt-flow-production-deployment.md`, action: 'relabel', created: '2026-02-04' },
|
||||
{ rel: `${DIR}/mlops-security-access-control.md`, action: 'drop' },
|
||||
];
|
||||
|
||||
/**
|
||||
* The pure per-file op: relabel **Dato:**→**Created:** or drop the redundant bold **Dato:**. Pure.
|
||||
* @param {string} content
|
||||
* @param {'relabel'|'drop'} action
|
||||
* @returns {string}
|
||||
*/
|
||||
export function applyOp(content, action) {
|
||||
if (action === 'relabel') return relabelHeaderDialect(content, CREATED_MAP).content;
|
||||
if (action === 'drop') return dropRedundantBoldField(content, DROP_LABEL, PROOF_LABEL);
|
||||
throw new Error(`applyOp: unknown action '${action}'`);
|
||||
}
|
||||
|
||||
// Header region = lines above the first `## `/`---` (mirrors transform.mjs headerEndIndex).
|
||||
function splitHeaderBody(content) {
|
||||
const lines = content.split('\n');
|
||||
let i = 0;
|
||||
for (; i < lines.length; i++) {
|
||||
if (/^##\s/.test(lines[i]) || /^---\s*$/.test(lines[i])) break;
|
||||
}
|
||||
return { header: lines.slice(0, i).join('\n'), body: lines.slice(i).join('\n') };
|
||||
}
|
||||
|
||||
// Assert the hard per-file invariant. Throws (aborting the run) on any breach.
|
||||
function assertInvariant(m, oldC, newC) {
|
||||
const { rel, action } = m;
|
||||
const o = oldC.split('\n');
|
||||
const n = newC.split('\n');
|
||||
const oldH = splitHeaderBody(oldC);
|
||||
const newH = splitHeaderBody(newC);
|
||||
if (oldH.body !== newH.body) throw new Error(`ABORT ${rel}: body not byte-identical`);
|
||||
if (/\*\*Dato:\*\*/.test(newH.header)) throw new Error(`ABORT ${rel}: header still carries **Dato:** after op`);
|
||||
|
||||
if (action === 'relabel') {
|
||||
if (n.length !== o.length) throw new Error(`ABORT ${rel}: line count changed (${o.length}→${n.length})`);
|
||||
let diffs = 0;
|
||||
let changedLine = -1;
|
||||
for (let i = 0; i < o.length; i++) {
|
||||
if (o[i] === n[i]) continue;
|
||||
diffs++;
|
||||
changedLine = i;
|
||||
}
|
||||
if (diffs !== 1) throw new Error(`ABORT ${rel}: expected exactly one line changed, got ${diffs}`);
|
||||
// The changed line must be the old line with ONLY the label token swapped.
|
||||
if (n[changedLine].replace('**Created:**', '**Dato:**') !== o[changedLine]) {
|
||||
throw new Error(`ABORT ${rel}: changed line ${changedLine} altered beyond the **Dato:**→**Created:** label token`);
|
||||
}
|
||||
if (!new RegExp(`\\*\\*Created:\\*\\* ${m.created}(?:\\s|$)`).test(newH.header)) {
|
||||
throw new Error(`ABORT ${rel}: **Created:** ${m.created} (frozen value) missing after relabel`);
|
||||
}
|
||||
} else {
|
||||
// drop
|
||||
if (n.length !== o.length - 1) throw new Error(`ABORT ${rel}: expected exactly one line removed (was ${o.length}, now ${n.length})`);
|
||||
if (!/\*\*Last updated:\*\*\s*\S/.test(newH.header)) throw new Error(`ABORT ${rel}: **Last updated:** missing after drop`);
|
||||
if (/\*\*Created:\*\*/.test(newH.header)) throw new Error(`ABORT ${rel}: drop must not introduce **Created:**`);
|
||||
}
|
||||
}
|
||||
|
||||
function run({ dry }) {
|
||||
const planned = [];
|
||||
const skipped = [];
|
||||
const missing = [];
|
||||
|
||||
for (const m of MANIFEST) {
|
||||
const abs = join(PLUGIN_ROOT, m.rel);
|
||||
if (!existsSync(abs)) { missing.push(m.rel); continue; }
|
||||
const old = readFileSync(abs, 'utf8');
|
||||
const out = applyOp(old, m.action);
|
||||
if (out === old) { skipped.push(m.rel); continue; } // idempotent: already resolved
|
||||
assertInvariant(m, old, out);
|
||||
planned.push({ rel: m.rel, action: m.action, out });
|
||||
}
|
||||
|
||||
if (missing.length) {
|
||||
console.error(`ABORT — ${missing.length} manifest target(s) not found (corpus drift):`);
|
||||
missing.forEach((x) => console.error(' ' + x));
|
||||
process.exit(1);
|
||||
}
|
||||
if (planned.length + skipped.length !== MANIFEST.length) {
|
||||
throw new Error(`ABORT — accounted ${planned.length + skipped.length} ≠ manifest ${MANIFEST.length}`);
|
||||
}
|
||||
|
||||
const relabels = planned.filter((p) => p.action === 'relabel').length;
|
||||
const drops = planned.filter((p) => p.action === 'drop').length;
|
||||
console.log(`Manifest: ${MANIFEST.length} | to resolve: ${planned.length} (${relabels} relabel + ${drops} drop) | already resolved (skipped): ${skipped.length}`);
|
||||
if (dry) {
|
||||
console.log('\n(dry run — no writes)');
|
||||
for (const p of planned) console.log(` ~ ${p.rel} [${p.action}]`);
|
||||
return;
|
||||
}
|
||||
for (const p of planned) atomicWriteSync(join(PLUGIN_ROOT, p.rel), p.out);
|
||||
console.log(`\nWrote ${planned.length} files.`);
|
||||
}
|
||||
|
||||
const isMain = (() => {
|
||||
try {
|
||||
return realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url));
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
})();
|
||||
if (isMain) run({ dry: process.argv.includes('--dry') });
|
||||
|
|
@ -500,6 +500,52 @@ export function dropRedundantPlainField(content, label) {
|
|||
return lines.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a bold header field — `**<dropLabel>:** <value>` — that is provably redundant with a
|
||||
* DIFFERENT bold field `**<proofLabel>:** <value>` carrying the IDENTICAL value (Enhet 3b dedup
|
||||
* primitive for the dual-**Dato:** mlops-genaiops file whose creation date equals its last-updated
|
||||
* date). The sibling of dropRedundantPlainField, but across two distinct bold labels rather than a
|
||||
* plain/bold pair. Refuses to guess: if no proof field exists, or the two values differ, it THROWS
|
||||
* (that is a human decision — relabeling `**Dato:**`→`**Created:**` there would assert a creation
|
||||
* date the file never truly had). No-op if the drop line is absent (idempotent). Operates in the
|
||||
* header region only (`headerEndIndex`); body — including any `**<dropLabel>:**` template line — is
|
||||
* byte-identical.
|
||||
*
|
||||
* @param {string} content — full existing file content
|
||||
* @param {string} dropLabel — the label to remove, WITHOUT decoration, e.g. 'Dato'
|
||||
* @param {string} proofLabel — the label whose identical value proves redundancy, e.g. 'Last updated'
|
||||
* @returns {string} content with the redundant bold line removed, or unchanged
|
||||
* @throws if either label is blank, no proof field proves redundancy, or the values differ
|
||||
*/
|
||||
export function dropRedundantBoldField(content, dropLabel, proofLabel) {
|
||||
const s = String(content ?? '');
|
||||
const dl = String(dropLabel ?? '').trim();
|
||||
const pl = String(proofLabel ?? '').trim();
|
||||
if (dl === '') throw new Error('dropRedundantBoldField: dropLabel is required');
|
||||
if (pl === '') throw new Error('dropRedundantBoldField: proofLabel is required');
|
||||
const escD = dl.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
const escP = pl.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
const dropRe = new RegExp('^\\s*\\*\\*' + escD + ':\\*\\*\\s*(\\S.*?)\\s*$', 'i');
|
||||
const proofRe = new RegExp('^\\s*\\*\\*' + escP + ':\\*\\*\\s*(\\S.*?)\\s*$', 'i');
|
||||
|
||||
const lines = s.split('\n');
|
||||
const end = headerEndIndex(lines);
|
||||
let dropIdx = -1;
|
||||
let dropVal = null;
|
||||
let proofVal = null;
|
||||
for (let i = 0; i < end; i++) {
|
||||
const dm = dropRe.exec(lines[i]);
|
||||
if (dm && dropIdx === -1) { dropIdx = i; dropVal = dm[1]; }
|
||||
const pm = proofRe.exec(lines[i]);
|
||||
if (pm && proofVal === null) proofVal = pm[1];
|
||||
}
|
||||
if (dropIdx === -1) return s; // nothing to drop (idempotent)
|
||||
if (proofVal === null) throw new Error(`dropRedundantBoldField: no bold **${pl}:** to prove **${dl}:** '${dropVal}' redundant`);
|
||||
if (proofVal !== dropVal) throw new Error(`dropRedundantBoldField: **${dl}:** '${dropVal}' ≠ **${pl}:** '${proofVal}' — not redundant, human decision`);
|
||||
lines.splice(dropIdx, 1);
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Surgically insert-or-update ONLY the `**Verified:**` and `**Verified by:**` header lines
|
||||
* on an EXISTING KB file — the R7–R10 born-verified STAMP primitive. Unlike composeKbFile
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Feedback Loops and Continuous Improvement
|
||||
|
||||
**Category:** MLOps & GenAIOps
|
||||
**Dato:** 2026-02-04
|
||||
**Created:** 2026-02-04
|
||||
**Last updated:** 2026-06-24
|
||||
**Confidence:** HIGH (basert på offisiell Microsoft-dokumentasjon)
|
||||
**Type:** reference
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# GenAIOps - LLM-Specific MLOps Practices
|
||||
|
||||
**Dato:** 2026-02-04
|
||||
**Created:** 2026-02-04
|
||||
**Last updated:** 2026-06-19
|
||||
**Category:** MLOps & GenAIOps
|
||||
**Konfidensgrad:** Høy (basert på 18 MCP-kilder fra Microsoft Learn)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
**Category:** MLOps & GenAIOps
|
||||
**Last updated:** 2026-06-19
|
||||
**Dato:** 2026-06-19
|
||||
**Confidence:** HIGH — Basert på offisiell Microsoft Learn dokumentasjon (8 MCP-oppslag, 16 kilder)
|
||||
**Type:** reference
|
||||
**Source:** https://learn.microsoft.com/azure/machine-learning/concept-enterprise-security
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Model Deployment Strategies on Azure
|
||||
|
||||
**Område:** MLOps & GenAIOps
|
||||
**Dato:** 2026-02-04
|
||||
**Created:** 2026-02-04
|
||||
**Målgruppe:** Arkitekter som planlegger ML-modellutplassering i produksjon
|
||||
**Konfidensgrad:** ⚡️⚡️⚡️ Høy (basert på Microsoft Learn + offisielle code samples)
|
||||
**Type:** reference
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Prompt Flow and Production Deployment
|
||||
|
||||
**Category:** MLOps & GenAIOps
|
||||
**Dato:** 2026-02-04
|
||||
**Created:** 2026-02-04
|
||||
**Last updated:** 2026-06-19
|
||||
**Confidence:** 🟢 Høy (basert på offisiell Microsoft-dokumentasjon fra Microsoft Foundry og Azure Machine Learning)
|
||||
**Type:** reference
|
||||
|
|
|
|||
168
tests/kb-update/test-dedup-dato.test.mjs
Normal file
168
tests/kb-update/test-dedup-dato.test.mjs
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
// tests/kb-update/test-dedup-dato.test.mjs
|
||||
// TDD for Enhet 3b — the dual-**Dato:** dedup on the 5 mlops-genaiops files that carry BOTH a
|
||||
// bold **Dato:** (creation) AND a bold **Last updated:** (modification). Ground truth 2026-07-16
|
||||
// (re-measured against the committed corpus + the git first-commit "Created-map"):
|
||||
// 4 files carry a DISTINCT creation date (**Dato:** 2026-02-04, authored BEFORE the git
|
||||
// first-commit 2026-04-08 → a genuine creation date) → relabel **Dato:** → **Created:**,
|
||||
// value byte-preserved (the same norsk→english label-rename class as Enhet 1/2).
|
||||
// 1 file (mlops-security-access-control) carries IDENTICAL dates (**Dato:**=**Last updated:**=
|
||||
// 2026-06-19, both AFTER the git first-commit → NOT a genuine creation date, a metadata-pass
|
||||
// artifact) → drop the redundant **Dato:**; relabeling it would assert a FALSE creation date.
|
||||
//
|
||||
// This is never a derive-a-value backfill and never an unproven delete: the drop primitive throws
|
||||
// unless a bold proof field with the IDENTICAL value exists. One new pure primitive
|
||||
// (dropRedundantBoldField) + the reused relabelHeaderDialect (CREATED_MAP) are pinned here, plus
|
||||
// a corpus-state guard (the gap-discipline lock) over the 5 committed files.
|
||||
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { join, dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dropRedundantBoldField } from '../../scripts/kb-update/lib/transform.mjs';
|
||||
import { relabelHeaderDialect } from '../../scripts/kb-update/relabel-dialect.mjs';
|
||||
import { MANIFEST, CREATED_MAP, applyOp } from '../../scripts/kb-update/dedup-dato.mjs';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const PLUGIN_ROOT = join(__dirname, '..', '..');
|
||||
const DIR = 'skills/ms-ai-engineering/references/mlops-genaiops';
|
||||
|
||||
// A dual-**Dato:** fixture: bold Category, bold **Dato:** (creation) + bold **Last updated:**
|
||||
// (modification) with DISTINCT values, then a body that mentions "Dato:" in prose (never touched).
|
||||
const FIXTURE = [
|
||||
'# Feedback Loops and Continuous Improvement',
|
||||
'',
|
||||
'**Category:** MLOps & GenAIOps',
|
||||
'**Dato:** 2026-02-04',
|
||||
'**Last updated:** 2026-06-24',
|
||||
'**Status:** Established Practice',
|
||||
'',
|
||||
'## Innhold',
|
||||
'',
|
||||
'A body line mentioning **Dato:** [YYYY-MM-DD] in a template — must be left alone.',
|
||||
'',
|
||||
].join('\n');
|
||||
|
||||
// mlops-security shape: IDENTICAL **Dato:** and **Last updated:** → the drop case.
|
||||
const FIXTURE_IDENTICAL = [
|
||||
'# Security and Access Control in MLOps',
|
||||
'',
|
||||
'**Category:** MLOps & GenAIOps',
|
||||
'**Last updated:** 2026-06-19',
|
||||
'**Dato:** 2026-06-19',
|
||||
'**Status:** Established Practice',
|
||||
'',
|
||||
'---',
|
||||
'',
|
||||
].join('\n');
|
||||
|
||||
// ── dropRedundantBoldField ───────────────────────────────────────────────────
|
||||
test('dropRedundantBoldField: drops **Dato:** when a bold **Last updated:** with the same value proves it redundant', () => {
|
||||
const out = dropRedundantBoldField(FIXTURE_IDENTICAL, 'Dato', 'Last updated');
|
||||
const header = out.split('\n---')[0];
|
||||
assert.ok(/\*\*Last updated:\*\* 2026-06-19/.test(header), 'proof field kept');
|
||||
assert.ok(!/\*\*Dato:\*\*/.test(header), 'redundant **Dato:** removed');
|
||||
assert.equal(out.split('\n').length, FIXTURE_IDENTICAL.split('\n').length - 1, 'exactly one line removed');
|
||||
});
|
||||
|
||||
test('dropRedundantBoldField: throws when the drop and proof values differ (not redundant, human decision)', () => {
|
||||
assert.throws(() => dropRedundantBoldField(FIXTURE, 'Dato', 'Last updated'), /not redundant|≠/);
|
||||
});
|
||||
|
||||
test('dropRedundantBoldField: throws when no proof field exists to prove redundancy', () => {
|
||||
const noProof = FIXTURE_IDENTICAL.replace('**Last updated:** 2026-06-19\n', '');
|
||||
assert.throws(() => dropRedundantBoldField(noProof, 'Dato', 'Last updated'), /no bold/i);
|
||||
});
|
||||
|
||||
test('dropRedundantBoldField: no-op when the drop field is absent (idempotent)', () => {
|
||||
const once = dropRedundantBoldField(FIXTURE_IDENTICAL, 'Dato', 'Last updated');
|
||||
assert.equal(dropRedundantBoldField(once, 'Dato', 'Last updated'), once);
|
||||
});
|
||||
|
||||
test('dropRedundantBoldField: never touches a **Dato:** in the body (below the header region)', () => {
|
||||
// FIXTURE has a distinct-value dual header (would throw) so build an identical-value variant
|
||||
// that ALSO carries a body **Dato:** template line — only the header one may be removed.
|
||||
const withBody = FIXTURE_IDENTICAL.replace('---', '## Innhold\n\n**Dato:** [YYYY-MM-DD] template\n\n---');
|
||||
const out = dropRedundantBoldField(withBody, 'Dato', 'Last updated');
|
||||
assert.ok(out.includes('**Dato:** [YYYY-MM-DD] template'), 'body template **Dato:** untouched');
|
||||
assert.ok(!/\*\*Dato:\*\*/.test(out.split('## Innhold')[0]), 'header **Dato:** removed');
|
||||
});
|
||||
|
||||
test('dropRedundantBoldField: blank labels throw', () => {
|
||||
assert.throws(() => dropRedundantBoldField(FIXTURE_IDENTICAL, '', 'Last updated'), /required/);
|
||||
assert.throws(() => dropRedundantBoldField(FIXTURE_IDENTICAL, 'Dato', ''), /required/);
|
||||
});
|
||||
|
||||
// ── relabel **Dato:** → **Created:** (reused relabelHeaderDialect + CREATED_MAP) ──────────────
|
||||
test('CREATED_MAP: relabels **Dato:** → **Created:**, value byte-preserved, one line, body identical', () => {
|
||||
const { content: out, applied } = relabelHeaderDialect(FIXTURE, CREATED_MAP);
|
||||
assert.equal(applied.length, 1);
|
||||
assert.ok(/\*\*Created:\*\* 2026-02-04/.test(out), 'Created line present with preserved value');
|
||||
assert.ok(!/\*\*Dato:\*\*/.test(out.split('## Innhold')[0]), 'header **Dato:** gone');
|
||||
const bodyOf = (c) => c.slice(c.indexOf('## Innhold'));
|
||||
assert.equal(bodyOf(out), bodyOf(FIXTURE), 'body byte-identical (template **Dato:** untouched)');
|
||||
assert.equal(out.split('\n').length, FIXTURE.split('\n').length, 'line count unchanged');
|
||||
});
|
||||
|
||||
test('CREATED_MAP: idempotent — a file with no **Dato:** in header is unchanged', () => {
|
||||
const { content: once } = relabelHeaderDialect(FIXTURE, CREATED_MAP);
|
||||
const { content: twice, applied } = relabelHeaderDialect(once, CREATED_MAP);
|
||||
assert.equal(twice, once);
|
||||
assert.equal(applied.length, 0);
|
||||
});
|
||||
|
||||
// ── applyOp dispatch ─────────────────────────────────────────────────────────
|
||||
test('applyOp: relabel dispatches to Created relabel', () => {
|
||||
assert.ok(/\*\*Created:\*\* 2026-02-04/.test(applyOp(FIXTURE, 'relabel')));
|
||||
});
|
||||
|
||||
test('applyOp: drop dispatches to redundant-bold drop', () => {
|
||||
const out = applyOp(FIXTURE_IDENTICAL, 'drop');
|
||||
assert.ok(!/\*\*Dato:\*\*/.test(out.split('\n---')[0]));
|
||||
});
|
||||
|
||||
test('applyOp: unknown action throws', () => {
|
||||
assert.throws(() => applyOp(FIXTURE, 'nonsense'), /unknown action/i);
|
||||
});
|
||||
|
||||
// ── MANIFEST ─────────────────────────────────────────────────────────────────
|
||||
test('MANIFEST: exactly the 5 dual-**Dato:** mlops-genaiops files, 4 relabel + 1 drop', () => {
|
||||
assert.equal(MANIFEST.length, 5);
|
||||
assert.equal(new Set(MANIFEST.map((m) => m.rel)).size, 5, 'no duplicate paths');
|
||||
const relabels = MANIFEST.filter((m) => m.action === 'relabel');
|
||||
const drops = MANIFEST.filter((m) => m.action === 'drop');
|
||||
assert.equal(relabels.length, 4);
|
||||
assert.equal(drops.length, 1);
|
||||
assert.equal(drops[0].rel, `${DIR}/mlops-security-access-control.md`, 'the identical-date file is the drop');
|
||||
for (const r of relabels) {
|
||||
assert.match(r.created, /^\d{4}-\d{2}-\d{2}$/, `${r.rel}: frozen created date must be YYYY-MM-DD`);
|
||||
}
|
||||
const expected = [
|
||||
`${DIR}/feedback-loops-continuous-improvement.md`,
|
||||
`${DIR}/genaiops-llm-specific-practices.md`,
|
||||
`${DIR}/model-deployment-strategies-azure.md`,
|
||||
`${DIR}/prompt-flow-production-deployment.md`,
|
||||
`${DIR}/mlops-security-access-control.md`,
|
||||
];
|
||||
for (const p of expected) assert.ok(MANIFEST.some((m) => m.rel === p), `missing ${p}`);
|
||||
});
|
||||
|
||||
// ── Corpus-state guard (gap-discipline lock over the committed files) ─────────
|
||||
test('corpus guard: the 4 distinct files carry **Created:** with the frozen date and no **Dato:** in the header', () => {
|
||||
for (const m of MANIFEST.filter((x) => x.action === 'relabel')) {
|
||||
const content = readFileSync(join(PLUGIN_ROOT, m.rel), 'utf8');
|
||||
const header = content.split(/\n(?:---|## )/)[0];
|
||||
assert.match(header, new RegExp(`\\*\\*Created:\\*\\* ${m.created}`), `${m.rel}: missing **Created:** ${m.created}`);
|
||||
assert.ok(!/\*\*Dato:\*\*/.test(header), `${m.rel}: header still carries **Dato:**`);
|
||||
assert.match(header, /\*\*Last updated:\*\*/, `${m.rel}: **Last updated:** must survive`);
|
||||
}
|
||||
});
|
||||
|
||||
test('corpus guard: mlops-security-access-control has no **Dato:** and keeps **Last updated:** 2026-06-19', () => {
|
||||
const rel = `${DIR}/mlops-security-access-control.md`;
|
||||
const content = readFileSync(join(PLUGIN_ROOT, rel), 'utf8');
|
||||
const header = content.split(/\n(?:---|## )/)[0];
|
||||
assert.ok(!/\*\*Dato:\*\*/.test(header), 'redundant **Dato:** must be gone');
|
||||
assert.ok(!/\*\*Created:\*\*/.test(header), 'no fabricated **Created:** (drop, not relabel)');
|
||||
assert.match(header, /\*\*Last updated:\*\* 2026-06-19/, '**Last updated:** 2026-06-19 must survive');
|
||||
});
|
||||
|
|
@ -12,8 +12,10 @@
|
|||
//
|
||||
// DELIBERATELY OUT of Enhet 2 (carved out after ground-truth audit 2026-07-06):
|
||||
// - 5 DUAL-LABEL files that carry BOTH **Dato:** (creation date) AND **Last updated:** (modified
|
||||
// date) with distinct values. Relabeling would duplicate the label / destroy provenance; the
|
||||
// collision-guard aborts on them by design. Deferred to a dedup unit (Enhet 3-adjacent).
|
||||
// date). Relabeling would duplicate the label / destroy provenance; the collision-guard aborts
|
||||
// on them by design. RESOLVED by Enhet 3b (dedup-dato.mjs, 2026-07-16): **Dato:**→**Created:**
|
||||
// on the 4 with a distinct creation date, dropped on the 1 whose dates were identical — so no
|
||||
// header **Dato:** remains, and Enhet 2's relabel is now a clean no-op on them.
|
||||
// - 8 body/list/placeholder occurrences (advisor YYYY-MM-DD templates, ros-report [YYYY-MM-DD],
|
||||
// 3 body list-items incl. [Dato]) — excluded by header-scoping + isRealDateValue.
|
||||
|
||||
|
|
@ -140,12 +142,17 @@ test('MANIFEST ↔ disk: committed state — English label present, no header **
|
|||
}
|
||||
});
|
||||
|
||||
test('carve-out ↔ disk: the 5 dual-label files still carry BOTH labels (untouched by Enhet 2)', () => {
|
||||
test('carve-out ↔ disk: Enhet 3b resolved the 5 dual-label files — no header **Dato:**, Enhet 2 relabel is a no-op', () => {
|
||||
for (const rel of DUAL_LABEL_FILES) {
|
||||
const abs = join(PLUGIN_ROOT, rel);
|
||||
assert.ok(existsSync(abs), `missing: ${rel}`);
|
||||
const header = headerBlock(readFileSync(abs, 'utf8'));
|
||||
assert.ok(header.some((l) => l.includes('**Dato:**')), `dual file lost its **Dato:** — ${rel}`);
|
||||
const content = readFileSync(abs, 'utf8');
|
||||
const header = headerBlock(content);
|
||||
// Enhet 3b relabeled **Dato:**→**Created:** (4 distinct) or dropped it (1 identical): none remain.
|
||||
assert.ok(!header.some((l) => l.includes('**Dato:**')), `header **Dato:** should be resolved by Enhet 3b — ${rel}`);
|
||||
assert.ok(header.some((l) => l.startsWith('**Last updated:**')), `dual file lost **Last updated:** — ${rel}`);
|
||||
// The durable Enhet-2 invariant: its Dato→Last-updated relabel never owned these (now a clean no-op).
|
||||
const { applied } = relabelHeaderDialect(content, DATO_LABEL_MAP);
|
||||
assert.equal(applied.length, 0, `Enhet 2 relabel must be a no-op on the carved-out ${rel}`);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue