ms-ai-architect/scripts/kb-update/lib/kb-headers.mjs
Kjell Tore Guttormsen 5a0ba1fc9e feat(ms-ai-architect): Spor 3 Port 2 — create-time-guard (born-verified contract) [skip-docs]
Type-aware create-guard for reference-filer (Spor 3 Port 1/Port 2):

- kb-headers.mjs: parseTypeHeader/parseVerifiedHeader/parseVerifiedByHeader
  (samme top-500-byte bold-label-skann som parseSourceHeader).
- transform.mjs: buildKbHeader er type-aware (reference krever
  source+verified+verified_by; non-reference kaster pa MS-Learn-source) +
  emitterer Type/Verified/Verified by; validateKbFile type-aware;
  stampVerifiedMeta = fodt-verifisert-gate (stempler KUN ved bestatt
  judge-verdikt, ellers kaster).
- validate-kb-file.mjs (ny): kjorbar gate generatorer kaller for commit
  (exit != 0 ved kontraktbrudd).
- generate-skills.md + kb-update.md + transform-prompt.md: wiret til
  fodt-verifisert kontrakt (header-felt + judge-steg + create-guard-gate).

Suite 586/586 (33 nye + 1 invariant). Plugin-validering 239/0/0.

Utenfor scope (flagget): generate-skills.sh legacy (sonnet/Cosmo/no-source),
Cosmo-persona i generatorene (S-Cosmo), korpus-migrering av 306 filer (Spor 1).
2026-06-29 10:36:21 +02:00

70 lines
2.8 KiB
JavaScript

// kb-headers.mjs — Parse optional authority headers from KB reference files.
// Zero dependencies. Scans only the top of the file (header region) where the
// **Source:** / **Primary source:** line lives, mirroring report-changes'
// parseLastUpdated convention.
const HEADER_REGION_BYTES = 500;
const SOURCE_PATTERNS = [
/\*\*Source:\*\*\s*(\S+)/i,
/\*\*Primary source:\*\*\s*(\S+)/i,
];
// Spor 3 Port 1 frontmatter contract: these live in the SAME top-500-byte bold-label
// region as **Source:**, so build-registry and the create-guard read one header format.
// `Verified:` and `Verified by:` are distinct labels — the date pattern below is
// anchored on the colon right after "Verified" so it never swallows the "by:" line.
const TYPE_PATTERN = /\*\*Type:\*\*\s*(\S+)/i;
const VERIFIED_PATTERN = /\*\*Verified:\*\*\s*(\S+)/i;
const VERIFIED_BY_PATTERN = /\*\*Verified by:\*\*\s*(\S+)/i;
/** Scan only the header region for the first capture of `pattern`, trimmed. */
function scanHeader(content, pattern) {
if (!content || typeof content !== 'string') return null;
const match = content.slice(0, HEADER_REGION_BYTES).match(pattern);
return match ? match[1].trim() : null;
}
/**
* Extract the declared authority source URL from a KB reference file's header.
* @param {string} content — full file content (only the first 500 bytes are scanned)
* @returns {string|null} the source URL, or null if no header is present
*/
export function parseSourceHeader(content) {
if (!content || typeof content !== 'string') return null;
const head = content.slice(0, HEADER_REGION_BYTES);
for (const pattern of SOURCE_PATTERNS) {
const match = head.match(pattern);
if (match) return match[1].trim();
}
return null;
}
/**
* Extract the Port 1 `type` (reference|template|methodology|regulatory), lowercased.
* @param {string} content — full file content (only the first 500 bytes are scanned)
* @returns {string|null} the declared type, or null if absent
*/
export function parseTypeHeader(content) {
const t = scanHeader(content, TYPE_PATTERN);
return t === null ? null : t.toLowerCase();
}
/**
* Extract the Port 1 `verified` date (when the file was last confirmed against source).
* Anchored on `**Verified:**` so it never matches the `**Verified by:**` line.
* @param {string} content — full file content (only the first 500 bytes are scanned)
* @returns {string|null} the verified date (YYYY-MM or YYYY-MM-DD), or null if absent
*/
export function parseVerifiedHeader(content) {
return scanHeader(content, VERIFIED_PATTERN);
}
/**
* Extract the Port 1 `verified_by` field (`judge-vN` / `human`).
* @param {string} content — full file content (only the first 500 bytes are scanned)
* @returns {string|null} the verifier, or null if absent
*/
export function parseVerifiedByHeader(content) {
return scanHeader(content, VERIFIED_BY_PATTERN);
}