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).
70 lines
2.8 KiB
JavaScript
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);
|
|
}
|