feat(ms-ai-architect): RX-KB1b — deterministisk footer-dato-avvik-deteksjon + label-whitelist i corpus-audit (flag-to-human, 3 flagg) [skip-docs]

This commit is contained in:
Kjell Tore Guttormsen 2026-07-17 03:23:40 +02:00
commit 722a131eb7
2 changed files with 119 additions and 0 deletions

View file

@ -53,6 +53,49 @@ const RE_CLEAN_DATE = /^\d{4}-\d{2}(-\d{2})?$/;
// pipe.mjs removes the current 87; this detects any reappearance within the non-advisor scope).
const RE_PLAIN_VERIFIED = /(?:^|[^*])Verified:/m;
// ── RX-KB1b: footer date-conflict + label-whitelist ────────────────────────
// A file that carries a header **Last updated:** date AND a norsk footer date under a
// last-updated-EQUIVALENT label ("Sist oppdatert") with a different value contradicts
// itself — it asserts two distinct last-updated dates. That is the only norsk footer
// label that can conflict with the header. LABEL WHITELIST: "Verifisert"/"Sist
// verifisert" record an INDEPENDENT axis (when content was last checked against source,
// not when the file was edited), so a differing date there is expected and is never a
// conflict. Detection is read-only and flag-to-human: the audit reports, the operator
// resolves per file against git/source (aldri-auto-fiks — a footer date can be right and
// the header stale, or vice versa; only a human can adjudicate which).
// Header **Last updated:** DATE — captured value (RE_LAST_UPDATED above only tests presence).
const RE_HEADER_LAST_UPDATED_DATE = /\*\*Last updated:\*\*\s*(\d{4}-\d{2}(?:-\d{2})?)/i;
// Any norsk footer meta-line carrying a date: "**Label:** DATE", "*Label: DATE", "Label: DATE".
// A valid month (01-12) is required, which also excludes template placeholders ([Dato],
// YYYY-MM-DD — they never match \d{4}-(0[1-9]|1[0-2])). Whole-file scan: footers live well
// outside the 500-byte header window. Group 1 = label, group 2 = date.
const RE_FOOTER_META =
/(?:^|\n)[ \t>*_-]*\*{0,2}\s*(Sist oppdatert|Sist verifisert|Verifisert)\s*:?\**\s*(\d{4}-(?:0[1-9]|1[0-2])(?:-\d{2})?)/gi;
// Only this label is last-updated-equivalent (conflict-bearing). Everything else the
// RE_FOOTER_META captures ("sist verifisert", "verifisert") is on the whitelist.
const FOOTER_LABEL_LAST_UPDATED = 'sist oppdatert';
/**
* Footer date-conflict for one file's full content. Returns null when there is no header
* Last-updated date, no last-updated-equivalent footer, or all such footers agree on the
* YYYY-MM prefix. Otherwise returns the header date and the conflicting footer date(s). Pure.
*/
function detectFooterConflict(content, headerLastUpdated) {
if (!headerLastUpdated) return null;
const footerDates = [];
for (const m of content.matchAll(RE_FOOTER_META)) {
if (m[1].toLowerCase() === FOOTER_LABEL_LAST_UPDATED) footerDates.push(m[2]);
}
if (footerDates.length === 0) return null;
const headerPrefix = headerLastUpdated.slice(0, 7);
const conflicting = footerDates.filter((d) => d.slice(0, 7) !== headerPrefix);
if (conflicting.length === 0) return null;
return { headerLastUpdated, footerDates: conflicting };
}
/** Audit a single file's content. Pure. */
function auditContent(content) {
const head = content.slice(0, HEADER_REGION_BYTES);
@ -76,6 +119,9 @@ function auditContent(content) {
else if (/\*\*Category:\*\*/i.test(head)) dialect = 'category';
else if (/\*\*Kategori:\*\*/i.test(head)) dialect = 'kategori';
const headerLuMatch = head.match(RE_HEADER_LAST_UPDATED_DATE);
const footerConflict = detectFooterConflict(content, headerLuMatch ? headerLuMatch[1] : null);
return {
title: RE_TITLE.test(content),
status: RE_STATUS.test(content),
@ -83,6 +129,7 @@ function auditContent(content) {
dialect,
verified,
plainVerified: RE_PLAIN_VERIFIED.test(head),
footerConflict,
};
}
@ -105,6 +152,7 @@ export function auditHeaders(paths, readFile = (p) => readFileSync(p, 'utf8')) {
verifiedPipe: 0,
verifiedDuplicate: 0,
plainVerifiedPipe: 0,
footerConflicts: 0,
missingTitle: 0,
missingStatus: 0,
missingEnglishLastUpdated: 0,
@ -131,6 +179,7 @@ export function auditHeaders(paths, readFile = (p) => readFileSync(p, 'utf8')) {
if (r.verified.duplicateWithinHeaderRegion) aggregate.verifiedDuplicate++;
}
if (r.plainVerified) aggregate.plainVerifiedPipe++;
if (r.footerConflict) aggregate.footerConflicts++;
if (!r.title) aggregate.missingTitle++;
if (!r.status) aggregate.missingStatus++;
if (!r.lastUpdatedEnglish) aggregate.missingEnglishLastUpdated++;
@ -184,6 +233,11 @@ function main(argv) {
console.log(` Verified header present: ${a.verifiedPresent} (date: ${a.verifiedDate}, stale non-date: ${a.verifiedNonDate})`);
console.log(` Verified pipe rows: ${a.verifiedPipe}, duplicates within 500B: ${a.verifiedDuplicate}`);
console.log(` Plain (non-bold) Verified tails (RX-KB1 poison class): ${a.plainVerifiedPipe}`);
console.log(` Footer "Sist oppdatert" ≠ header Last updated (RX-KB1b, flag-to-human): ${a.footerConflicts}`);
for (const [abs, r] of Object.entries(report.files)) {
if (!r.footerConflict) continue;
console.log(` FLAG ${relative(PLUGIN_ROOT, abs)} — header ${r.footerConflict.headerLastUpdated} vs footer ${r.footerConflict.footerDates.join(', ')}`);
}
console.log(` Missing English Last updated: ${a.missingEnglishLastUpdated}`);
console.log(` Missing Status: ${a.missingStatus}`);
console.log(` Missing title: ${a.missingTitle}`);