okr/tests/topic-guard.test.mjs
Kjell Tore Guttormsen 482effbad1 fix(okr): B2 ingestion-kode-hygiene + bump 1.7.1 (patch-lane)
8 hygiene-fikser fra review 2026-07-16 par.4 kode-lista, TDD roed-groenn
(suite 138 -> 149):
- innboks-split: slugify translittererer ae/oe (datatap-fiks)
- innboks-frontmatter: beskrivende feil ved manglende sourceMtime
- okf-index: --okf-version bumper eksisterende rot, flagg-tolerant CLI
  (exit 2 ved manglende verdi), sanitizeEntry strip C1/zero-width/bidi/
  Unicode-tag
- write-org-profile: circuit-breaker MERGER i stedet for aa overskrive
  full config (M4); test beviser at eksisterende config overlever
- compose-org-profile: intern ----linje trunkerer ikke blokken
- coaching-hook: at-risk teller status-markerte tabellrader (M1/m1)
- inject-okr-context: topic-guard treffer boeyningsformer (maalene)
- frontmatter: BOM/CRLF-toleranse (falsk mangler-type-fiks)

Versjonsflater bumpet til 1.7.1 (package/plugin/lock/CLAUDE/README/
SKILL x2/package-shape-test) + CHANGELOG 1.7.1-seksjon (B1+B2).
Release-tag + katalog-ref venter paa [G-B] operatoer-go.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 04:02:10 +02:00

88 lines
3 KiB
JavaScript

// topic-guard.test.mjs
// Tester UserPromptSubmit emne-guard (SC6) i inject-okr-context: kun
// OKR-relevante prompter injiserer kontekst; en eksplisitt ikke-matchende
// prompt suppresses; tvil (tomt felt / ingen stdin) -> default-inject.
// Spawner hooken som subprosess med kontrollert cwd + stdin. Zero npm deps.
// Moenster: tests/inject-okr-context.test.mjs (begge-casen + input-opsjon).
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { execFileSync } from 'node:child_process';
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const HOOK = join(
dirname(fileURLToPath(import.meta.url)),
'..',
'hooks',
'scripts',
'inject-okr-context.mjs',
);
function makeProjectConfig(workDir, navn) {
const p = join(workDir, '.claude');
mkdirSync(p, { recursive: true });
writeFileSync(join(p, 'okr.local.md'), `---\nnavn: "${navn}"\n---\n`);
}
function runHook(cwd, input = '') {
// execFileSync returnerer stdout; hooken avslutter alltid med exit 0.
return execFileSync('node', [HOOK], {
cwd,
env: { ...process.env },
input: input,
encoding: 'utf8',
});
}
function withWork(fn) {
const work = mkdtempSync(join(tmpdir(), 'okrtopic-'));
try {
fn(work);
} finally {
rmSync(work, { recursive: true, force: true });
}
}
test('irrelevant prompt: suppresses injeksjon (tom stdout)', () => {
withWork((work) => {
makeProjectConfig(work, 'TopicOrg');
const out = runHook(work, JSON.stringify({ prompt: 'hva er vaeret i dag' }));
assert.equal(out.trim(), '', 'ikke-OKR-prompt skal suppresses selv med gyldig config');
});
});
test('relevant prompt: injiserer OKR-kontekst', () => {
withWork((work) => {
makeProjectConfig(work, 'TopicOrg');
const out = runHook(work, JSON.stringify({ prompt: 'hjelp meg skrive en OKR for neste tertial' }));
assert.match(out, /OKR-kontekst/, 'OKR-relevant prompt skal injisere kontekst');
});
});
test('boeyningsform: "målene" treffer topic-guarden (B2)', () => {
withWork((work) => {
makeProjectConfig(work, 'TopicOrg');
// Bestemt flertall av maal -- \bm[aa]l\b bommet paa denne foer B2.
const out = runHook(work, JSON.stringify({ prompt: 'hvordan ligger vi an mot målene i høst' }));
assert.match(out, /OKR-kontekst/, 'boeyningsformen maalene skal injisere kontekst');
});
});
test('tomt prompt-felt: bevarer inject-default (tvil -> injiser)', () => {
withWork((work) => {
makeProjectConfig(work, 'TopicOrg');
const out = runHook(work, JSON.stringify({ prompt: '' }));
assert.match(out, /OKR-kontekst/, 'tomt prompt-felt -> tvil -> injiser');
});
});
test('ingen stdin: bevarer inject-default (regresjonsvakt)', () => {
withWork((work) => {
makeProjectConfig(work, 'TopicOrg');
const out = runHook(work); // input utelatt -> tom stdin
assert.match(out, /OKR-kontekst/, 'ingen stdin -> tvil -> injiser');
});
});