feat(okr): lukket OKF type/tags-vokabular for ingestion-snap [skip-docs]
This commit is contained in:
parent
abfcc6b48e
commit
a9d9c45192
2 changed files with 138 additions and 0 deletions
73
lib/okf-vocab.mjs
Normal file
73
lib/okf-vocab.mjs
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
// okf-vocab.mjs
|
||||
// Lukket kontrollert vokabular for innboks-ingestion (type + tags) og
|
||||
// type->nivaa-ruting. Zero npm dependencies.
|
||||
//
|
||||
// Net-new (premiss #1): handheves KUN paa ingestion-skrivestien (snapType/
|
||||
// snapTags) og av okf-check++ --strict-ingest. Lese-siden (okr-second-brain-
|
||||
// search, okf-check default) behandler fortsatt ukjente typer som gyldige --
|
||||
// denne modulen er den ENESTE strenge porten, aktiv kun ved ingestion.
|
||||
|
||||
// Title-Case kanoniske OKF-typer (jf. catalog-spec Documents/kb Layout).
|
||||
export const TYPE_VOCAB = [
|
||||
'Organisasjonsprofil',
|
||||
'Tildelingsbrev',
|
||||
'Virksomhetsplan',
|
||||
'Overordnede OKR',
|
||||
'OKR',
|
||||
'Retrospektiv',
|
||||
'Status',
|
||||
'Notat',
|
||||
'Dokument',
|
||||
];
|
||||
|
||||
// Safe default naar raw type ikke matcher vokabularet exact (premiss #1).
|
||||
const DEFAULT_TYPE = 'Dokument';
|
||||
|
||||
// Lukket start-sett av Title-Case tags for ingestion-snap.
|
||||
export const TAGS_VOCAB = [
|
||||
'Strategi',
|
||||
'Tildelingsbrev',
|
||||
'Virksomhetsplan',
|
||||
'OKR',
|
||||
'Styring',
|
||||
'Governance',
|
||||
'Retrospektiv',
|
||||
'Status',
|
||||
'Maal',
|
||||
'Risiko',
|
||||
];
|
||||
|
||||
// type -> bundle-nivaa (katalog under bundle-rot). Organisasjonsprofil rutes
|
||||
// til dokumenter/ (IKKE strategisk-kontekst/) for aa ikke konkurrere med den
|
||||
// home-kanoniske ~/.claude/okr/org/profil.md (Revisions #25).
|
||||
const LEVEL_BY_TYPE = {
|
||||
Tildelingsbrev: 'strategisk-kontekst',
|
||||
Virksomhetsplan: 'strategisk-kontekst',
|
||||
'Overordnede OKR': 'strategisk-kontekst',
|
||||
Retrospektiv: 'historikk',
|
||||
OKR: 'dokumenter',
|
||||
Status: 'dokumenter',
|
||||
Notat: 'dokumenter',
|
||||
Dokument: 'dokumenter',
|
||||
Organisasjonsprofil: 'dokumenter',
|
||||
};
|
||||
|
||||
const DEFAULT_LEVEL = 'dokumenter';
|
||||
|
||||
// Exact-match -> kanonisk type; ellers safe default Dokument.
|
||||
export function snapType(raw) {
|
||||
return TYPE_VOCAB.includes(raw) ? raw : DEFAULT_TYPE;
|
||||
}
|
||||
|
||||
// Behold kun tags i det lukkede vokabularet (dropp ukjente); bevar rekkefolge.
|
||||
export function snapTags(rawList) {
|
||||
if (!Array.isArray(rawList)) return [];
|
||||
return rawList.filter((t) => TAGS_VOCAB.includes(t));
|
||||
}
|
||||
|
||||
// type -> bundle-nivaa; ukjent/ikke-vokab -> default dokumenter/. Plassert her
|
||||
// i Session 1 slik at relasjons-steget (Step 6) kan resolvere konseptets
|
||||
// mal-sti FOR skriv (Pass-2 ordering-fiks, Revisions #21).
|
||||
export function routeLevel(type) {
|
||||
return LEVEL_BY_TYPE[type] ?? DEFAULT_LEVEL;
|
||||
}
|
||||
65
tests/okf-vocab.test.mjs
Normal file
65
tests/okf-vocab.test.mjs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// okf-vocab.test.mjs
|
||||
// Tester det lukkede OKF-vokabularet (type+tags) og type->nivaa-ruting for
|
||||
// innboks-ingestion (Step 2). snapType: exact-match -> kanonisk, ellers safe
|
||||
// default Dokument; snapTags dropper ukjente; routeLevel mapper type til
|
||||
// bundle-nivaa. Direkte import (zero npm deps). Moenster: tests/frontmatter.test.mjs.
|
||||
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {
|
||||
TYPE_VOCAB,
|
||||
TAGS_VOCAB,
|
||||
snapType,
|
||||
snapTags,
|
||||
routeLevel,
|
||||
} from '../lib/okf-vocab.mjs';
|
||||
|
||||
test('snapType: kjent type beholdes kanonisk', () => {
|
||||
assert.equal(snapType('OKR'), 'OKR');
|
||||
assert.equal(snapType('Tildelingsbrev'), 'Tildelingsbrev');
|
||||
});
|
||||
|
||||
test('snapType: ukjent type -> safe default Dokument', () => {
|
||||
assert.equal(snapType('ukjent'), 'Dokument');
|
||||
assert.equal(snapType(''), 'Dokument');
|
||||
assert.equal(snapType(undefined), 'Dokument');
|
||||
});
|
||||
|
||||
test('snapTags: dropper ukjente, beholder kjente (bevart rekkefolge)', () => {
|
||||
assert.deepEqual(snapTags(['Strategi', 'xyz']), ['Strategi']);
|
||||
assert.deepEqual(snapTags(['xyz', 'abc']), []);
|
||||
assert.deepEqual(snapTags([]), []);
|
||||
});
|
||||
|
||||
test('snapTags: ikke-array -> tom liste (ingen krasj)', () => {
|
||||
assert.deepEqual(snapTags(undefined), []);
|
||||
assert.deepEqual(snapTags(null), []);
|
||||
});
|
||||
|
||||
test('routeLevel: strategisk-kontekst for foringsdokumenter', () => {
|
||||
assert.equal(routeLevel('Tildelingsbrev'), 'strategisk-kontekst');
|
||||
assert.equal(routeLevel('Virksomhetsplan'), 'strategisk-kontekst');
|
||||
assert.equal(routeLevel('Overordnede OKR'), 'strategisk-kontekst');
|
||||
});
|
||||
|
||||
test('routeLevel: historikk for Retrospektiv', () => {
|
||||
assert.equal(routeLevel('Retrospektiv'), 'historikk');
|
||||
});
|
||||
|
||||
test('routeLevel: dokumenter for OKR/Status/Notat/Dokument/Organisasjonsprofil', () => {
|
||||
assert.equal(routeLevel('OKR'), 'dokumenter');
|
||||
assert.equal(routeLevel('Status'), 'dokumenter');
|
||||
assert.equal(routeLevel('Notat'), 'dokumenter');
|
||||
assert.equal(routeLevel('Dokument'), 'dokumenter');
|
||||
assert.equal(routeLevel('Organisasjonsprofil'), 'dokumenter');
|
||||
});
|
||||
|
||||
test('routeLevel: ukjent type -> default dokumenter', () => {
|
||||
assert.equal(routeLevel('Whatever'), 'dokumenter');
|
||||
});
|
||||
|
||||
test('vokabular non-tomt + default i settet', () => {
|
||||
assert.ok(TYPE_VOCAB.length > 0, 'TYPE_VOCAB non-tomt');
|
||||
assert.ok(TAGS_VOCAB.length > 0, 'TAGS_VOCAB non-tomt');
|
||||
assert.ok(TYPE_VOCAB.includes('Dokument'), 'default Dokument er i vokabularet');
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue