/** * Seed ruleset for the §B/§C1 mechanical binding-gate. * * Each rule transcribes a mechanically-checkable item from the Maskinrommet * writing contract (maskinrommet/docs/skrivekontrakt.md). The classification * principle (slice 1): BLOCK only what the gate can PROVE with ~zero false * positives (exact forbidden phrases, markdown syntax); WARN on grep-flags that * still need human/AI judgment (a word that *might* be a metaphor, a bare * "modell" that *might* be neutral). Judgment-only / external-data rules * (research/ traceability, term definitions, narrative architecture, the full * AI-tell list) are intentionally NOT here — they stay with voice-scrubber * (tier 2) and editorial-reviewer (tier 3). * * Deferred to a later slice (documented gaps, not silent omissions): * - §C2 "postulerte tall" (numbers without hedge/source) — needs a * hedge-proximity heuristic with non-trivial false-positive risk. * - §C2 "ordrette gjentakelser" (any n-gram repeated >2×) — needs n-gram * analysis; the contract's named phrases are edition-specific. */ import type { Rule } from "./types.js"; export const RULES: Rule[] = [ // ── BLOCK: provable, ~zero false positives ───────────────────────────── { id: "B3-modell-referansepunkt", ref: "§B-3 / §C1", severity: "block", kind: "literal", patterns: [ "det er ikke modellen som", "ikke en bedre modell", "modellen er god nok", "uten å bytte modell", ], message: "Modell-stråmann (regel 3, KTGs mest gjentatte korreksjon): ingen påstand om at modellen er problemet/for svak. Skriv om til vår evne, vilje og kompetanse til å hente ut potensialet.", }, { id: "B10-serie-tese", ref: "§B-10 / §C1", severity: "block", kind: "literal", patterns: ["er ikke modellen"], message: "Serie-tesen / meta-tese (regel 10, korollar til regel 3): «… er ikke modellen» er den tause linsen, aldri en setning vi leverer. Positiv konkret landing («menneskene … er den knappe ressursen») er OK — den abstrakte meta-tesen er ikke.", }, { id: "understrek-emfase", ref: "§C1 / hygiene", severity: "block", kind: "regex", // Markdown underscore-emphasis: opening _ at a boundary, closing _ before // whitespace/punctuation. snake_case (underscores between word chars) is // NOT matched, so identifiers in prose don't false-positive. patterns: ["(^|[\\s(])_[^_\\n]+_(?=[\\s).,!?:;]|$)"], message: "Emfase med _understrek_ rendrer rått (hygiene). Bruk **fet** (eller *kursiv* med stjerne).", }, // ── WARN: grep-flag, needs human/AI judgment ─────────────────────────── { id: "B2-metafor", ref: "§B-2", severity: "warn", kind: "regex", patterns: ["\\b(tak|lodd|reise|landskap)\\b"], message: "Mulig metafor som bærer argumentet (regel 2). Bekreft at bruken er konkret/nøytral, ikke utvidet bildespråk («et usynlig tak» → «KI-en når ikke dataene»).", }, { id: "B3-modell-bar", ref: "§B-3", severity: "warn", kind: "count", threshold: 0, patterns: ["\\bmodell"], message: "«modell» nevnt — sjekk at HVERT treff er nøytral faktabruk («en KI-modell er trent på …»), ikke modellen brukt som referansepunkt/stråmann (regel 3).", }, { id: "KI-en-subjekt", ref: "hygiene ★", severity: "warn", kind: "count", threshold: 3, patterns: ["\\bKI-en\\b"], message: "«KI-en» gjentatt som handlende subjekt er dårlig norsk (språk-hygiene). Varier: «KI», «verktøyet», eller omskriv («data KI har tilgang til»).", }, { id: "B9-PS", ref: "§B-9 / §C1", severity: "warn", kind: "regex", patterns: ["(^|\\n)\\s*P\\.?\\s?S\\.?\\b"], message: "PS/etter-closing-blokk (regel 9). Sjekk at den ikke åpner nytt begrep/rammeverk etter handlingskallet — leseren skal lukke på ett konkret handlingsvalg.", }, { id: "C2-tankestrek-tetthet", ref: "§C2", severity: "warn", kind: "density", threshold: 1, per: 50, patterns: ["\\u2014"], // em dash — message: "Tankestrek-tetthet over ~1 per 50 ord (§C2). Bytt halvparten med komma eller punktum; innskudd-formelen «X — Y — Z» bør være sjelden.", }, { id: "C2-versal-tic", ref: "§C2", severity: "warn", kind: "regex", // Case-sensitive, Unicode-aware (handles MÅ/NÅ/SÅ). DENYLIST, not allowlist: // flag only UPPERCASE forms of known Norwegian emphasis words — NOT every // 2+-uppercase run. Acronyms (NPM, DFØ, NAV) are not emphasis words, so they // never flag. (Real-data finding on Del 4/5: an acronym allowlist can't keep // up; the emphasis-word set is small and stable.) flags: "gu", patterns: [ "(?