feat(linkedin-studio): accumulation binding — ratify + §E foldIns (fix #1 slice 2)

Slice 2 av fix #1 («rettelser fester seg»): binder rules.ts til den menneskelige
sannhetskilden (skrivekontrakt §E), så en korreksjon gjort én gang håndheves for
alltid i stedet for å gjenoppdages hver utgave (diagnose-gap 2).

- ratify.ts: importerer RULES direkte (ingen skjør tekst-parsing), krever en
  bijeksjon mot §E gate-bindings-manifestet (id ↔ ref ↔ severity) + dangling-
  §-anker-sjekk. CLI: `--ratify [kontrakt]` / `npm run ratify`. Sti: arg > env
  MASKINROMMET_CONTRACT > default (relativt til modulen).
- edition-state.template: foldIns[] fangst-kø (per-artikkel proveniens,
  pending|promoted|rejected, mekanisk→rules.ts / dømmekraft→§C2).
- 12 nye tester (33 totalt), tsc rent. Live-kontrakt-integrasjonstest ratify-er
  det ekte §E-manifestet rent (10 regler bundet 1:1).

Companion: skrivekontrakt §E (JA-promoter-prosedyre + manifest) i maskinrommet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-06-20 17:48:20 +02:00
commit ff3467de79
6 changed files with 434 additions and 6 deletions

View file

@ -4,9 +4,10 @@ Deterministisk gate som håndhever den **mekaniske** halvdelen av Maskinrommet-s
(`maskinrommet/docs/skrivekontrakt.md`: §B de ti reglene, §C1 regelsjekk-gaten, §C2 prosa-håndverk)
**før et utkast leveres til operatøren** — så de samme mekaniske korreksjonene aldri når KTG to ganger.
Dette er **slice 1** av fix #1 (§C2 bindende + akkumulerende). Den er bevisst _bindende_: ren
string/regex-evaluering, ingen AI, ingen nettverk — den kan ikke hoppes over eller snakkes rundt,
og kjører på millisekunder.
Dette er fix #1 (§C2 bindende + akkumulerende). **Slice 1** = denne gaten: den binder *utkast* til
reglene — bevisst _bindende_, ren string/regex-evaluering, ingen AI, ingen nettverk, så den ikke kan
hoppes over eller snakkes rundt, og kjører på millisekunder. **Slice 2** = `ratify` + §E: den binder
*reglene* (`rules.ts`) til den menneskelige sannhetskilden (kontrakten). Se [Akkumulering](#akkumulering-slice-2).
## Hva gaten gjør (og ikke gjør)
@ -56,7 +57,8 @@ cd scripts/contract-gate
npm install # engangs (tsx + typescript)
node --import tsx src/cli.ts <utkast.md> # kvittering + exit 0/1
node --import tsx src/cli.ts <utkast.md> --json # maskinlesbart
npm test # 21 tester
npm run ratify # slice 2: rules.ts ↔ §E-manifest i sync?
npm test # 33 tester (gate + ratify)
```
Exit: `0` = passert (ingen BLOCK, handoff tillatt), `1` = blokkert, `2` = bruksfeil.
@ -71,3 +73,32 @@ WARN feiler aldri gaten — de surfaces for KTGs dom.
historisk artefakt, ikke gate-feil.
- Versal-tic-redesignet (denylist av emfase-ord, ikke allowlist av akronymer) fjernet
NAV/DFØ/NPM-false-positivene som ekte data avslørte.
## Akkumulering (slice 2)
Slice 1 binder *utkast* til reglene. Slice 2 binder *reglene* til kontrakten — så «rettelser fester
seg» blir mekanisk, ikke håpet-på. Diagnosens gap 2 («rettelser fester seg ikke») lukkes ved at hver
korreksjon KTG gjør får et varig, håndhevet hjem.
**Ruta** (full prosedyre i `maskinrommet/docs/skrivekontrakt.md` §E):
1. **Fang** korreksjonen i utgave-staten (`articles.NN.foldIns[]`) — ingenting mistes.
2. **Klassifiser:** mekanisk (eksakt frase / ord / markdown / telling) → `rules.ts`-regel + §B/§C1/§C2-rad;
dømmekraft → kun §C2-boks (blir hos `editorial-reviewer`, ingen gate-regel).
3. **JA-promoter:** KTG svarer JA/NEI. NEI → `rejected` (beholdes). JA → promotér.
4. **Promotér atomisk:** `rules.ts`-entry + kontrakt-rad + §E-manifest-rad (id·ref·severity·proveniens)
+ merk fold-in `promoted`.
5. **Ratify:** `npm run ratify` MÅ være grønn før promoteringen teller.
**Bindingen** (`src/ratify.ts`): importerer `RULES` direkte (ingen skjør tekst-parsing) og krever en
**bijeksjon** mot gate-bindings-manifestet i §E — hver regel ↔ nøyaktig én manifest-rad, med `ref` +
`severity` identisk, og hver `§`-anker en ekte seksjon. En regel i `rules.ts` uten manifest-rad (gaten
håndhever noe udokumentert), eller en manifest-rad uten regel (en «regel» ingen håndhever), feiler:
```
$ npm run ratify
✓ I sync — 10 regler bundet 1:1 til §E-manifestet (ref + severity stemmer).
```
Kontrakt-sti: argument > `MASKINROMMET_CONTRACT` > default (relativt til modulen). Mangler kontrakten
(fersk klon uten maskinrommet) → exit 2 med klar beskjed; den ekte-kontrakt-testen skippes da.