Commit graph

63 commits

Author SHA1 Message Date
a8ae1fd276 feat(ms-ai-architect): RX-REG — én maskinlesbar AI Act-frist-kilde + synk-test (B2-B5, R3-5, M10) [skip-docs]
Rotårsak-mekanisme: scripts/kb-update/data/ai-act-deadlines.json er nå eneste
kilde for AI Act-frister; CLAUDE.md-tabellen, assessor-malen og begge hooks
synk-testes mot den (tests/kb-update/test-ai-act-deadlines-sync.test.mjs, 9
tester, TDD rød→grønn). Suite 815/815.

- B2: «Kommisjonen kan fremskynde»/«ytre grense» fjernet (trigger droppet i
  endelig Omnibus-tekst)
- B3: status oppdatert i alle 3 lag — formelt vedtatt (EP 2026-06-16, Rådet
  2026-06-29), trer i kraft ved OJ-publisering (ikke publisert per 2026-07-15,
  verifisert mot EUR-Lex 32024R1689)
- B4: Art. 50-raden «Gjeldende» → «Fra 2026-08-02»
- B5: stop-hooken feilmerket 2026-08-02 som «GPAI-frist» — begge hooks leser
  nå kilden, 0 hardkodede frist-literals
- R3-5: 2026-12-02-raden (Art. 50(2)) inn i assessor-malen
- M10: Nkom navngitt som koordinerende markedstilsynsmyndighet + nasjonalt
  kontaktpunkt (kilde: nkom.no/ki/regulering/hvem-handhever)
- pending_oj-markører i kilden for RX-REG² (nudifiserings-forbud, Art. 111)
- .gitignore: whitelist for den kuraterte frist-kilden
2026-07-15 06:13:36 +02:00
de0d94cbc1 feat(ms-ai-architect): R22 decision-b Enhet 3 — Status-backfill 25 none + ai-act dual-header-dedup 4 (Missing Status/Last-updated 29+4→0) [skip-docs]
To operasjoner, én økt (⊥ R7), begge ren metadata-normalisering (verdi aldri fabrikkert).

Premiss-korreksjon (ground truth 2026-07-07): roadmap sa «27 none + 4 ai-act».
Målt: 29 mangler bold **Status:** = 25 rene none + 4 ai-act (plain Status: GA).
De «27» inkluderte 2 for mye — 2 filer (custom-dashboards-ai-operations,
zero-trust-ai-services) har bold **Status:** KUN forbi byte 500 (present for
full-fil-audit, usynlig for 500B header-parser) → egen header-slanking-residual
(§8-register), utenfor Enhet 3.

Op A — Status-backfill 25 rene none: utvidet backfill-status.mjs MANIFEST 14→39
(samme statusForFile + insertMetaField + hard per-fil-invariant, idempotent skip
på de 14 R21-gjorte). Alle 25 → **Status:** Established Practice (ingen matcher
template|matrix|benchmarks|register). Diff +25/-0.

Op B — ai-act dual-header-dedup (4 filer): ny driver dedup-plain-header.mjs + 2
rene primitiver i transform.mjs — boldifyPlainField (plain→bold, verdi bevart
byte-eksakt, header-scoped, idempotent) + dropRedundantPlainField (sletter plain
KUN når bold m/ identisk verdi beviser redundans; kaster ved avvik/manglende bold).
Per fil: plain Last updated: + Status: GA → bold (2026-06-18/2026-02, GA bevart),
redundant plain Category: fjernet. Hard per-fil-invariant (net -1 linje, begge
felt bold m/ bevart verdi, ingen plain-header igjen, body byte-identisk). Diff -12/+8.

Verifisering: test-backfill-status 8/8 + test-dedup-plain-header 13/13; audit
Missing Status 29→0, Missing English Last updated 4→0; skills-diff 29 filer
+33/-12 (kun **Status:** + 8 bold-swaps), diff-kontekst inspisert per fil; begge
drivere idempotent (re-run 0 writes); suite 806/806 exit 0; none=8 uendret (Enhet 4).
2026-07-07 07:45:27 +02:00
1ab4fc34cf feat(ms-ai-architect): decision-b Enhet 2 — Dato→Last-updated relabel 16 filer (21 header-kandidater: 16 rene + 5 dual utskilt til dedup), isRealDateValue placeholder-guard [skip-docs] 2026-07-06 11:08:42 +02:00
e999b74eda feat(ms-ai-architect): decision-b Enhet 1 — dialekt-relabel 51 filer (Kategori→Category + Sist oppdatert→Last updated), 73 byte-eksakte swaps [skip-docs]
Ren value-preserving label-relabel av de to norske header-labelene til engelsk på 51 ref-filer (22 bærer begge). Ny testet ren primitiv relabelHeaderDialect() (header-blokk-scoped, kollisjons-/multiforekomst-guard) + manifest-drevet driver relabel-dialect.mjs (frosset 51-fil-manifest, hard per-fil-invariant, idempotent, isMain-guard). **Dato:** bevisst UTE (body-template-felle → Enhet 2). Premiss-korreksjon i roadmap R22: tredje Dato-dialekt (16), 0 bold-duplikater (ikke 4), 1 datoløs (ikke 5), category-none = vindus-artefakt. test-relabel-dialect 11/11; diff +73/-73 0 linjer utover label; suite 782/782 exit 0.
2026-07-06 10:07:52 +02:00
5a0e8d774a feat(ms-ai-architect): R21 — Status-backfill på 14 advisor-ref-filer (redusert scope etter premiss-korreksjon) [skip-docs]
Manifest-drevet applier (scripts/kb-update/backfill-status.mjs) over den testede
insertMetaField-primitiven + ny ren regel statusForFile (filnavn-token → Reference/
Established Practice, operatør-godkjent vokabular). 7 Reference + 7 Established Practice.
Hard per-fil-invariant (én linje, body byte-identisk), idempotent, isMain-guard. 7 tester.

Premiss-korreksjon (auditHeaders, ground-truth 2026-07-06): ekte not-due-restanse er
21 Status + 26 Last-updated (STATE sa 21/22). «0 har norsk dato» var falskt — 21/26
Last-updated-gap bærer allerede Sist oppdatert/Dato → relabel-residual; 5 datoløse gir
«i dag» ved naiv git → utsatt. 4 dual-header ai-act-*-filer med plain-text «Status: GA»
fanget i diff-inspeksjon → revertert (unngår duplikat/motsigelse) → residual (samme
plain-blokk ga R20 duplikat Category). Korrigert residual logget i roadmap §R21.

Verifisering: test-backfill-status 7/7; git diff +14/-0 (kun Status-linjer, body
byte-identisk); not-due Status-missing 21→3; full suite 771/771 exit 0.
2026-07-06 09:41:40 +02:00
a583599ab1 feat(ms-ai-architect): R20 — Category-backfill på 25 kategorisløse ref-filer via insertMetaField [skip-docs]
Ny testet primitiv transform.insertMetaField (anker + 500B-back-off som insertHeaderFields, idempotent på eksakt label, body byte-identisk; 6 tester) + backfill-category.mjs (deterministisk folder->category-regel, hard per-fil-invariant, insert-only, aborterer for skriving ved avvik).

Fordeling: 14 Solution Architecture & Advisory (architecture/), 6 Microsoft AI Platforms (platforms/+development/), 4 Responsible AI & Governance, 1 MLOps & GenAIOps. Label = engelsk Category (322 vs 42 Kategori). Eksisterende recommended-mcp-servers/rag-maturity-model urort.

Roadmap: R20 done + R21 (Status/Last-updated not-due) encoded. Verifisering: 0 kategorislose filer (var 25); diff +25/-0; idempotent re-run; suite 764/764 exit 0.
2026-07-06 07:39:54 +02:00
841292ff36 refactor(ms-ai-architect): retire backfill-toc.mjs (superseded), migrer cosmo-removal-brief:41-kobling, logg §8-residual [skip-docs] 2026-07-04 23:33:55 +02:00
b227c278eb fix(ms-ai-architect): G6 Layer B — unicode/carrier-scan kjører pre-write via temp-fil (lukker ingestion-brief §8-akseptansegap, TDD) [skip-docs] 2026-07-04 23:04:00 +02:00
b5c44e6c6e feat(ms-ai-architect): surgical insertVerifiedFields stamp (byte-identisk body, NFR non-destruktivt, TDD) [skip-docs] 2026-07-04 22:58:10 +02:00
6f82572dba feat(ms-ai-architect): G2 — generaliser stamp-guard til version-label-streng (TDD, kaster på malformert) [skip-docs] 2026-07-04 22:51:52 +02:00
ddce43d8b2 feat(ms-ai-architect): Spor 1 — Port-1-substrat migrert på 4 ikke-advisor-skills (243 Source + 327 Type + 325 TOC + stale-verified poison fjernet) [skip-docs]
Steg 9 (R4): unified migrate-corpus.mjs --write over engineering/governance/
infrastructure/security. 327 filer mutert, verified=null, prosa byte-identisk
(fra første ## seksjon), advisor urørt (0 endringer).

To applier-fixes oppdaget under kjøring (TDD, RED→GREEN):
- insertHeaderFields: anker faller nå tilbake når en meta-linje selv passerer
  500B (2 filer pakket et avsnitt i **Status:** → Type/Source landet utenfor
  scan-vinduet, applierens post-write-assertion fanget + restaurerte).
- normalizeStaleVerified: fjerner nå ALLE stale non-date **Verified:** i
  500B-vinduet, inkl. stray body-dup rett under --- (9 mlops-genaiops-filer var
  ellers falskt "verified"/fresh, droppet fra worklist). Operatør-godkjent
  utvidelse av carve-out; kun stray metadata-linjer, aldri prosa.

test-transform-criterion: precondition oppdatert til post-migrasjons-sannhet
(fila bærer nå Source). Suite 728/728 grønn.
2026-07-04 10:19:11 +02:00
cec98b5cb5 feat(ms-ai-architect): Spor 1 — unified migrate-corpus applier (backup+atomisk+advisor-fence+per-felt-idempotent, TDD) [skip-docs] 2026-07-04 09:20:32 +02:00
6b58afda3b feat(ms-ai-architect): Spor 1 — insertHeaderFields + surgical normalizeStaleVerified (3 dialekter, pipe-safe, ---aware, TDD) [skip-docs] 2026-07-04 08:54:21 +02:00
89dcd80cbc feat(ms-ai-architect): Layer B ingestion-gate — deterministisk adversariell-innhold-skann før skriving/commit (G6 §8 / R6 punkt d, TDD) [skip-docs]
Load-bearing gaten i den to-lags ingestion-sikkerheten: en deterministisk,
alltid-på node-skann (unicode/injection/base64, prosa + fenced code blocks) over
kandidat skills/**/*.md, wiret inn som sibling til validate-kb-file.mjs ved det
ENESTE skrive-chokepunktet — dekker kb-update + generate-skills + fremtidig R7.

- lib/adversarial-scan.mjs: ren disposition-kjerne (provenance-tiering + BLOCK/
  WARN-matrise). Ortogonal til korrekthets-judgen.
- lib/adversarial-detect.mjs: bro til de DELTE llm-security-detektorene
  (scanForInjection-lexikon + unicode-scanner + base64/entropi) — ingen kopi av
  lexikonet. Fail-closed hvis llm-security fraværende.
- scan-adversarial-content.mjs: CLI (speiler validate-kb-file.mjs); exit 1=BLOCK
  (aldri skriv), 2=WARN (flagg → menneske), 0=ren.
- 30 tester (19 kjerne + 7 CLI + 4 integrasjon mot ekte llm-security). Suite 692/0.

Premiss-verifisert mot live kode: research/research-agent skriver ingenting
(kun Layer A); R7-judge re-bruker samme create-guard; CLI-scan alene misset
injection+base64 for markdown → importerer rene primitiver i stedet.
2026-07-04 07:13:43 +02:00
9e4bf2a4f9 feat(ms-ai-architect): Spor 1 — klassifiserer-CLI + registry-merge (389 klassifisert, union reconciled) [skip-docs] 2026-07-03 00:55:15 +02:00
6b8e1b3767 feat(ms-ai-architect): Spor 1 — ref-type-klassifiserer (pure core, MS-sitering-proxy + edge-flagg, TDD) [skip-docs] 2026-07-03 00:52:45 +02:00
dc2146aa7a feat(ms-ai-architect): Spor 1 — korpus-header-audit (verified/base-felt/dialekt-fordeling, TDD) [skip-docs] 2026-07-03 00:50:57 +02:00
da8606f9f6 feat(ms-ai-architect): G2 LUKKET — adoptert v3.1-judge wired inn i pipeline (JUDGE_VERSION 2→'3.1', TDD, suite 641) [skip-docs] 2026-06-30 21:55:39 +02:00
a1d72fadc0 feat(ms-ai-architect): Spor 3 Port 3 (P3d) — periodisk full-pass worklist (kadens-judge enumerering) [skip-docs]
Ren lib full-pass-worklist.mjs (classifyFullPassDue + buildFullPassReport, skriver
aldri til disk) + CLI report-full-pass-worklist.mjs (gitignored full-pass-worklist.json).
Lastmod-UAVHENGIG: gater paa Port 1-kontrakt (type:reference + source) + cadence-alder
paa Verified, fanger drift-klassen inkrementell bommer (staleness-recall 0/40).
Buckets: never-verified / cadence-due / fresh / unsourced / unmigrated / out-of-scope.
Arbeidsliste (operatoer-valgt design), IKKE inline judge: enumererer + rangerer,
operatoer kickstarter judging separat (par.5 ikke auto-lansert, par.4c aldri auto-fiks).
Ekte kjoering: 389 ref-filer alle unmigrated = dormant til Spor 1-migrering. Suite 637/637.
2026-06-29 15:34:45 +02:00
08e7e72c62 feat(ms-ai-architect): Spor 3 Port 3 (rapporterende gulv) — KB-tillit-signal i SessionStart [skip-docs]
Det rapporterende gulvet (§4 Port 3, P3b): SessionStart-hooken surfacer en
KB-tillit-énlinjer fra cachet verified-staleness-report.json. Et GULV, ikke en
gate (§4c — unngå alarm-tretthet på 84 %-signal).

summarizeTrustFreshness (detection-schedule.mjs, ren, speiler
summarizeSkillQuality): surfacer KUN drift (stale-since-verified) +
kontraktbrudd (unverified) — det handlingsbare «bekreft mot kilde»-settet.
unmigrated (Spor-1-backlog, 306 i dag) ekskluderes bevisst: ved det volumet
ville det fyre hver økt og bli støy; migrerings-censusen hører i CT5 (P3c).
Tolererer manglende/malformed cache → null (gitignored, fraværende i fersk
klon, krasjer aldri hooken).

session-start-context.mjs: leser cachen read-only (samme mønster som
skill-quality-blokken), dytter linjen når den finnes.

Ende-til-ende verifisert: injisert stale-rapport → «KB-tillit: 3 filer driftet
siden verifisering, 1 uverifisert — bekreft mot kilde (aldri auto-fiks)»; ekte
korpus (306 unmigrated) → taus (ingen falsk alarm).

TDD (Iron Law): 8 nye tester. Suite 612/612. Plugin-validering PASS.
2026-06-29 14:58:32 +02:00
fea5df5e68 feat(ms-ai-architect): Spor 3 Port 3 (inkrementell) — stale-since-verified klassifiserer + CLI [skip-docs]
Port 3s billige, lastmod-synlige halvdel av kadens-judgen. Forutsetningen kom
med Port 2: filene bærer nå **Verified:**, så «sitemap_lastmod > verified»-
sammenligningen er endelig mulig.

lib/verified-staleness.mjs (rent, speiler verify-out — skriver aldri til disk):
- classifyVerifiedStaleness: reference-scope (Port 1-kontrakt). Buckets:
  stale-since-verified (kilde endret strikt etter verify → flagg), unverified
  (type=reference men verified=null, kontraktbrudd → flagg), unmigrated
  (type=null legacy → Spor 1-bro, telles), out-of-scope (template/methodology/
  regulatory), fresh. YYYY-MM→-01-normalisering, strikt > (lik dato = fresh).
- buildFileSourceMap: registry-inversjon (URL→filer ⇒ fil→nyeste lastmod),
  kun tracked + lastmod. Delt med full-pass (P3d).
- buildStalenessReport: join header↔lastmod, klassifiser, sorter (stale før
  unverified, nyeste drift først); reader injisert (testbar uten disk).

report-verified-staleness.mjs: tynn I/O-glue (speiler report-changes), skriver
gitignored verified-staleness-report.json. Kjøres på KB-refresh-kadens, IKKE
SessionStart (hooken bare LESER cachen — P3b).

Ekte kjøring: 306 ref-filer m/ tracked kilder, alle unmigrated (Port 1 ikke
backfilllet til legacy-korpus ennå = Spor 1). Mekanismen rapporterer ærlig
grunntilstand korrekt.

TDD (Iron Law): 18 nye tester. Suite 604/604.
2026-06-29 14:53:51 +02:00
5a0ba1fc9e feat(ms-ai-architect): Spor 3 Port 2 — create-time-guard (born-verified contract) [skip-docs]
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).
2026-06-29 10:36:21 +02:00
bfc79710c8 feat(ms-ai-architect): insertToc + backfill-toc applier (Fase 1b-verktøy) — store-fil-TOC foldet inn i Cosmo-utfasing
1b-premisset (ikke-advisor storfiler er Cosmo-frie, trygt å TOC-e nå) er
motbevist mot ground truth: 11/12 har en `## …Cosmo…`-overskrift → en TOC
bygget fra `##`-overskriftene ville emittert ny Cosmo-anker (bryter «aldri
ny Cosmo-innhold»), og å nøytralisere overskriften er selve persona-fjerningen
(ikke en sidehandling — scope-guard). Store-fil-TOC (de 20 filene >800 linjer,
advisor + ikke-advisor) folder derfor inn i Cosmo-utfasingen. Denne committen
leverer kun det gjenbrukbare verktøyet; ingen ref-filer rørt.

- transform.insertToc: retrofitter `## Innhold` i en eksisterende storfil rett
  før første ikke-fence `## `-seksjon (samme slot som composeKbFile), robust mot
  de 3 legacy-header-variantene (med/uten `---`), idempotent, fence-aware.
- scripts/kb-update/backfill-toc.mjs: dry-run/--write applier (ren glue rundt
  insertToc; transform.mjs forblir write-fri — arkitektur-invariant).
- docs/cosmo-removal-brief: «Sammenfall»-seksjon dokumenterer fold-inn + bruk.
- TDD: +6 transform-tester. Suite 509/509 (kb-update 355 + kb-eval 154).
2026-06-26 11:43:30 +02:00
2240f1efdd feat(ms-ai-architect): generator-anti-regresjon Fase 1c — composeKbFile + TOC-gate
Nye ref-filer fodes best-practice-konforme sa neste KB-update ikke
reverserer TOC-arbeidet (write-path-regresjon). MA fore 1b.

- buildToc(body): deterministisk ## Innhold fra ##-seksjoner, GitHub-slugs,
  fence-aware, idempotent (lister aldri seg selv)
- composeKbFile(meta, body): generatoren — header + (store filer >100 linjer) TOC
  + brodtekst; erstatter bar buildKbHeader+body-konkatenering
- validateKbFile: stor fil uten TOC -> missing:['toc'] (write-path-gaten)
- Terskel 100 speiler eval.mjs N4_LARGE_FILE_LINES; bundet atferdsmessig via
  test som importerer ekte checkN4 (anti-regresjons-orakel), ikke cross-import
- Wiret composeKbFile inn i transform-prompt.md + kb-update.md (create + in-place)

TDD: +11 transform-tester. kb-update 349/349, kb-eval 154/154 (503 totalt).
Fikset pre-eksisterende skjor assertion i criterion-testen (stale
'Azure AI Foundry' -> 'AI Foundry'; produktet omdopt) — var rod for 1c.
2026-06-26 10:59:40 +02:00
e74646d395 fix(ms-ai-architect): registry-herding Fase 1a — +5 sitemap-prefiks + skjemaløs URL-ekstraksjon
Update-mekanismen lot siterte URL-er stå som not_in_sitemap fordi deres docset
aldri ble pollet, og skjemaløse citater (tabellceller: bare learn.microsoft.com/...
uten https://) ble aldri ekstrahert.

- Taxonomy: +5 docsets (graph, ai-builder, power-apps, power-automate,
  microsoftsearch) — hver ett child-sitemap, verifisert live mot indeksen.
  Bevist: 21/24 not_in_sitemap-URL-er i disse docsetene blir nå tracked.
- url-normalize: extractUrls fanger skjemaløse citater-med-sti (krever /path
  etter domenet → avviser bare-domene-prosa og JSON-eksempler); normalizeUrl
  kanonikaliserer scheme til https. Bevist: +19 nye URL-er ekstraherbare.
- Bugfix: backtick fra inline-kode-citat (`learn.microsoft.com/...`) lekket inn
  i URL-en — ekskludert i regex + trailing-strip.

TDD: tests/kb-update/test-url-normalize.test.mjs (ny, 14) + test-taxonomy
prefiks-count 18→23 + Fase 1a-assertion. Full suite 338/338, 0 regresjon.
Registry-refresh (build-registry --merge + poll) bevisst utsatt — unngår
552KB re-order-churn; effekten er empirisk verifisert read-only.
2026-06-26 10:15:46 +02:00
97ebcd737a feat(ms-ai-architect): Spor D Steg C — skill-quality SessionStart-surfacing (TDD) [skip-docs]
summarizeSkillQuality(cache) (pure) in detection-schedule.mjs: one-liner
"Skill-kvalitet: N skills < 90 % (navn)"; null when all skills meet target,
when the cache is missing (gitignored → absent in a fresh clone), or when the
shape is malformed. Reads the CACHED skill-score-report.json (from Steg B) —
never scores live (buildReport reads ~400 ref-files). Wired into
session-start-context.mjs after the course-signals block (same
existsSync/try-catch pattern). 7 new tests (kb-update 316 → 323).

[skip-docs]: README is the public end-user doc; skill-quality scoring is
maintainer-only tooling (the cache is gitignored, so the signal never surfaces
for end-users). The right doc homes ARE updated: CLAUDE.md hook table + a
caveat note (this commit), and docs/skill-quality-scoring-plan.md §3 komponent 4.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 18:38:35 +02:00
cb0450ee2d feat(ms-ai-architect): C3 (3) — --courses-flagg i write-schedule-config.mjs (TDD) + live-probe-doc
Eier-CLI kan nå sette include_course_detection uten å hand-edite den gitignored
local.md: `write-schedule-config.mjs --enabled true --cadence daily --courses true`.
Flagget er VALGFRITT (opt-in inni opt-in) — utelates det, bevares en verdi satt
andre steder gjennom onboarding-rewriten (samme merge-semantikk som
interval_days / include_skill_lifecycle).

Tester (+3): --courses true setter nøkkelen, string-coercion (CLI-args er
strenger), og non-clobbering når flagget utelates. kb-update 313→316.

docs/development.md: C3-workflow peker nå på CLI-flagget framfor manuell local.md.

Live-probe (2) kjørt mot ekte Learn Platform API: baseline-registry etablert
(1093 kurs: 843 modules + 250 learning-paths), 0 leads (korrekt baseline §8 b).
Registry/report er detektorens gitignored private state — ingen filer committet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 16:25:56 +02:00
f4dd4d3fb6 feat(ms-ai-architect): C3.6 — SessionStart-surfacing av kurs-leads (summarizeCourses) → C3 kurs-spor komplett (TDD)
Siste C3-fase. `summarizeCourses(report)` ren one-liner i detection-schedule.mjs
(«Kurs-signaler: N nye / M endrede kurs i dekkede produkter»; null ved
0/skipped/error/removed-only/malformed — removed er informasjons-signal, aldri
surfacet lead, spec §4.2). Speiler summarizeSkillLifecycle.

Wiring i session-start-context.mjs: read-only, leser
scripts/kb-update/data/course-detection-report.json, foreslår /architect:kb-update,
speiler skill-signaler-blokka. Hooken spawner ingenting for kurs-sporet.

docs/development.md: ny C3-workflow-seksjon (to-stegs: Claude-fri deteksjon →
SessionStart-surfacing → operatør-gate §3c). CLAUDE.md hook-tabell oppdatert.

Tester (+6): summarizeCourses — new+updated one-liner, only-new/only-updated,
zero→null, removed-only→null, skipped/error→null, missing/partial→null.
kb-update 307→313, validate 239/0, kb-eval 100/0, hooks 11/11, discovery 13/13.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 15:00:40 +02:00
e0d2d05dbb feat(ms-ai-architect): C3.5 — courses-kolleksjon i decisions-io.mjs (UID-nøklet, Spor C) + kb-update §3c kurs-gate (TDD) [skip-docs]
Tredje ledger-kolleksjon (courses), additivt ved siden av decisions (URL,
Spor A) og actions (skill, Spor B). De tre rene helperne speiler
recordAction-trioen 1:1:
- recordCourseLead(led, uid, lead)            (ren, UID-nøklet)
- setCourseLeadStatus(led, uid, status, at)   (ren transisjon, kaster på ukjent UID)
- isCourseLeadDecided(led, uid)               (dedup policy A: any status)
createLedger()->courses:{}; loadDecisions backfiller courses ??= {} (bakoverkompat).

Strukturell ingen-ingest-invariant: apply-pathene leser ALDRI courses
(apply-skill-op.mjs->kun actions, discover-new-urls.mjs->kun decisions),
så et godkjent kurs-lead trigger aldri fetch/transform/KB-skriving.

commands/kb-update.md §3c: operatør-gate som leser course-detection-report.json,
dedup'er via isCourseLeadDecided, skriver godkjente leads via recordCourseLead
(--dry-run viser leads uten å skrive).

Tester (+16): test-decisions-courses.test.mjs. Eksisterende test-decisions-io
+ test-decisions-actions URØRT grønne (ikke-regresjons-bevis, samme mønster
som Spor B). kb-update 291->307 · validate 239/0 · kb-eval 100/0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 14:38:56 +02:00
2e69e69326 feat(ms-ai-architect): C3.4 — detect-courses.mjs (binder C3.1–C3.3, LLM-fri) + selectDetectionSteps + include_course_detection (TDD) [skip-docs]
LLM-fri STEG 1-detektor for kurs-deteksjon (C3.4 av GODKJENT C3-spec). Speiler
discover-new-urls' to-stegs-monster: leser Keychain-creds, paginerer modules +
learning-paths filtrert til in-domain produkter, differ mot egen diff-state
(course-registry.json), skriver kandidatrapport. Skriver KUN report + registry —
ALDRI decisions.json (operator-gaten i C3.5 promoterer leads).

- scripts/kb-update/detect-courses.mjs (NY): detectCourses(deps) — injiserbar
  kjerne (readSecret/getToken/paginate/loadTaxonomy/load+saveCourseRegistry/
  saveReport/dataDir/now/log) -> hermetisk testbar uten Keychain/nett. Fail-soft
  (spec 3/6): creds=null -> status:"skipped"; run-feil -> status:"error" (kaster
  ALDRI); begge exit 0 (advisory, aldri rod pipeline). Tynn CLI med realpath-guard
  (kjorer kun nar invokert direkte) + --data-dir test-seam. updatedAt.gt-cursor
  KUN pa incremental (full ISO, gotcha #1); products-filter = comma-join (OR).
- lib/detection-schedule.mjs: ny ren selectDetectionSteps(config) gater BADE
  skillLifecycle + courseDetection (en sannhetskilde). DEFAULT_SCHEDULE_CONFIG
  +include_course_detection:false (opt-in i opt-in, spec 8d). coerce/serialize
  utvidet. DETECTION_STEPS +{detect-courses, courseDetection:true}.
- run-detection.mjs: bruker selectDetectionSteps (fjerner duplisert filter-linje).

Tester (+22):
- test-detect-courses-invariant (8): ingen saveDecisions/decisions-io/atomic-write/
  backup-import; skriver egen registry+report; binder diffCourses+makeCourseClassifier;
  LLM-fri (kommentar-strippet kildesjekk).
- test-detect-courses (6): fail-soft skipped (alle/delvis creds), error-path (no
  throw, registry urort), 4.3 report-shape + avledet skill/category, incremental
  cursor/produkt-param, baseline=ingen leads (spec 8b), hermetisk exit-0-subprosess
  via PATH-shadow av `security`.
- test-detection-schedule (+8): include_course_detection parse/serialize/default;
  selectDetectionSteps-gating (default av, opt-in pa, uavhengige gates);
  run-detection bruker selektoren.

Gotcha (secrets-hook): clientSecret: '...'-form traff llm-security-regelen
(client[_-]?secret|ClientSecret)\s*[=:]\s*['"]…{8,} -> lost med array-av-par
(feltnavn star aldri rett for quotet streng).

Gate 7 C3.4 mott: invariant + fail-soft(exit 0) + report-shape + DETECTION_STEPS-
filter gronn. kb-update 269->291, validate PASSED (239/0), run-detection dry-run
dropper detect-courses (opt-in av), eval urort (rorer ikke KB), null regresjon.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 14:24:57 +02:00
b9f51ea7b3 feat(ms-ai-architect): C3.3 — course_products (live-enumerert) + makeCourseClassifier (TDD) [skip-docs]
Produkt-slug->kategori-mapping for kurs-deteksjon (C3.3 av GODKJENT C3-spec).

- lib/taxonomy.mjs: makeCourseClassifier(tax) — speiler makeClassifier; forste
  in-domain produkt vinner; skill AVLEDES fra category_skill (lagres ALDRI i
  course_products -> kan ikke divergere); ukjent/tom/non-array -> null.
- data/domain-taxonomy.json: ny topp-niva course_products (slug->category) +
  provenance. 15 in-domain live slugs.
- test-taxonomy.test.mjs (+6): atferd (in-domain->{skill,category}, first-wins,
  out-of-domain/tom/non-array->null, manglende map) + REELL data-invariant
  (hver slug-kategori resolver til skill, derivasjon matcher) + azure-openai-live.

ENUMERERING (gotcha #2, live mot /api/v1/modules?products=<slug> server-side):
- DOD (0 treff): azure-ai-foundry, ai-services, azure-ai-services, foundry ->
  Foundry/AI-services-kurs dukker opp under 'azure-openai'.
- Slug-feller bekreftet live: 'fabric' (ikke microsoft-fabric), 'entra' (ikke
  microsoft-entra-id), 'azure-cosmos-db' (ikke cosmos-db), 'azure-cognitive-search'
  (ikke azure-ai-search).
- 'azure-kubernetes-service' live men EKSKLUDERT (ingen AI-kategori -> stoy).
- Inkluderte (15): azure-openai, azure-machine-learning, azure-cognitive-search,
  azure-cosmos-db, fabric, azure-databricks, microsoft-copilot-studio,
  power-automate, power-apps, power-platform, ai-builder, microsoft-365-copilot,
  microsoft-purview, entra, defender-for-cloud.

Avvik fra spec 4.4-eksempel: course_products lagrer slug->category (ikke
slug->{skill,category}); skill avledes — anti-divergens, encapsulated av
makeCourseClassifier (downstream-kontrakt {skill,category} uendret).

Gate 7 C3.3 mott: test gronn, eval --json IDENTISK (refTall/K-counts uendret).
kb-update 263->269, validate PASSED (239/0), null regresjon.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 13:48:04 +02:00
94c7f42128 feat(ms-ai-architect): C3.2 — course-diff (ren) + course-registry load/save (TDD) [skip-docs]
Pure diff/fold + run-mode selector for course detection (C3.2 av GODKJENT C3-spec).

- lib/course-diff.mjs (REN, null imports): normalizeCourse, selectMode,
  isFullEnumDue, diffCourses, updateRegistry, FULL_ENUM_MAX_AGE_DAYS=30.
  Full-enum-pin (§4.2): removed beregnes KUN i full-modus; inkrementell og
  baseline gir removed:[]. Baseline emitterer ingen leads (§8 b).
  updateRegistry ren (muterer aldri): incremental merger, baseline/full bygger
  fra API-sett + dropper retirerte UIDs, stamper last_full_enum.
- registry-io.mjs +loadCourseRegistry/saveCourseRegistry (additivt, speiler
  loadRegistry/saveRegistry; fil course-registry.json).
- test-course-diff.test.mjs (23) + test-courses-invariant (+3: diff-modul ren).

Gate §7 C3.2 møtt. kb-update 237->263, validate PASSED, null regresjon.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 13:12:49 +02:00
0390cc10ca feat(ms-ai-architect): C3.1 — keychain + Learn Platform API-klient (TDD) [skip-docs]
C3 kurs-deteksjon, fase C3.1 (spec docs/c3-course-detection-plan.md §6/§7).
Claude-frie, fil-frie infrastruktur-lag for kurs-detektoren (C3.4):

- lib/keychain.mjs: readSecret() leser én Keychain-item via `security`-CLI,
  fail-soft (manglende item / ikke-macOS → null). execImpl-DI for test.
- lib/learn-api.mjs: getToken (Entra client-credentials), paginate (async-gen,
  følger nextLink), buildApiUrl (pinner api-version), buildUpdatedAtGt (kaster
  på dato-only, canon Z — gotcha #1). Robusthetskontrakt §6: response.ok-sjekk
  (fetch kaster ikke på 4xx/5xx), AbortSignal.timeout, 429/5xx-retry som
  respekterer Retry-After, 4xx≠429 ikke-retry, fail-closed. fetchImpl/sleep-DI.

Tester (24, alle grønne): test-learn-api (token-body, buildUpdatedAtGt,
nextLink-paginering, produkt-param, alle robusthets-asserts), test-keychain,
test-courses-invariant (Claude-fri + skriver-ingen-filer). Live-probe (efemer)
grønn mot ekte Platform API m/ ekte creds: token + full-enum + inkrementell.

Intern infrastruktur (ingen brukervendt kommando/hook/atferd endret ennå —
surfacing + docs lander i C3.6). kb-update 213→237 · validate 239 · null regresjon.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 12:59:16 +02:00
afd75c4fed feat(ms-ai-architect): C2.3 onboarding skriver scheduled_detection cadence+enabled via gated CLI (TDD) [skip-docs]
K5 oppfylt: onboarding skriver scheduled_detection-blokka (enabled +
os_scheduler_cadence) til bruker-eid config; parseScheduleConfig leser den
tilbake til samme verdier (round-trip bevist deterministisk).

- serializeScheduleConfig(config) i detection-schedule.mjs — invers av
  parseScheduleConfig, rett ved parseren (én formatsannhet).
- write-schedule-config.mjs (NY, gated CLI, Claude-fri): merger på eksisterende
  config (override kun de to onboarding-eide nøklene; interval_days/
  include_skill_lifecycle overlever). backupFile + atomicWriteSync — ingen rå
  fs-write.
- backupFile(filePath, backupRoot) i lib/backup.mjs — presis enkeltfil-backup.
- onboard.md (orkestrator): «Planlagt deteksjon»-seksjon + scheduler i --status.
  onboarding-agent.md: note om at scheduler er orkestratorens jobb (ingen Bash).
- Avvik fra plan-tekst (dokumentert): scheduler-spørsmål i orkestrator, ikke agent.

Verifisert: detection-schedule 33/33 (+10) · backup-restore 15/15 (+3) ·
kb-update 213 · kb-eval 100 · validate 239/0/0 · test-hooks 11/11 ·
kb-integrity 192/192 · discovery 13/13 · gitleaks 3 pre-eksisterende.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 14:53:03 +02:00
8ff73b7fe3 feat(ms-ai-architect): C2.2 valgfritt fritekst-felt free-context.md i onboarding (TDD) [skip-docs]
Spor C / C2.2 (#3, akseptanse K3): fanger et fritt prosa-felt i onboarding og
overflater det (kappet) ambient i hver sesjon.

- lib/user-data.mjs: FREE_CONTEXT_FILE (utenfor ORG_FILES — valgfri, teller ikke
  mot fullføring), collapseProse() surfacer fri kontekst som ÉTT felt uansett
  markdown-struktur (ingen stille drop), capValue() ekstrahert (DRY).
- session-start-context.mjs: leser free-context.md valgfritt (ingen count++).
- onboarding-agent.md: ny Phase 6 (valgfri); onboard.md: prosess/Task/status.
- 11 agenter: uniform 6. bullet (grep 11/11).
- Tester FØR kode: user-data 25/25 (+9), test-hooks 11/11 (+1 K3-ambient).

Gates: validate 239/0/0 · kb-update 200 · kb-eval 100 · kb-integrity 192/192
(220 baseline-warns) · discovery 13/13 · gitleaks 3 pre-eksisterende.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 14:16:00 +02:00
dc0b627e98 feat(ms-ai-architect): C2.1 lib/user-data resolver + ambient org-injeksjon + C1 config bakoverkompat (TDD) [skip-docs]
Bæreren i C2 onboarding-redesign (#26). TDD: test FØR kode.

- lib/user-data.mjs (NY, ren, SKRIVER ALDRI; kun node:os/path):
  resolveUserDataDir/resolveOrgDir/resolveConfigPath peker ~/.claude/ms-ai-architect/
  (uavhengig av pluginRoot -> overlever reinstall, K2). CONFIG_FILENAME delt med C1
  (en sannhetskilde). buildOrgSummary: deterministisk, lengde-kappet H2-ekstraksjon.
- detection-schedule.mjs: loadScheduleConfig(pluginRoot, home=homedir()) leser
  bruker-sti FORST, fallback plugin-rot. Lokal CONFIG_FILENAME -> importeres fra resolver.
  Alle 3 kallere bruker ett-arg-kall (uendret oppforsel).
- session-start-context.mjs: injiserer buildOrgSummary ambient (K1) som egen
  Virksomhetskontekst-blokk; status-nudge beholdt nar org tom.

Verifisert: user-data 16/16 · detection-schedule 23/23 · test-hooks 10/10 ·
kb-update 191 · kb-eval 100 · validate PASSED.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 13:34:05 +02:00
071601bb9e feat(ms-ai-architect): Sesjon 24 — C1 Tier 2 lokal launchd-scheduler (deteksjon-only, ToS-trygt) [skip-docs]
Tier 1 (SessionStart-hook) kjører deteksjon kun når en Claude-sesjon starter.
Tier 2 installerer en lokal launchd LaunchAgent som fyrer SAMME Claude-frie
entrypoint daglig (kl. 03:00), uavhengig av sesjoner = ekte bakgrunn mellom
sesjoner. ToS-trygt: entrypointet kan strukturelt ikke invokere claude.

Søk-først-verifisert (2026-06): launchd > cron (Apple-anbefalt; cron krever
Full Disk Access); StartCalendarInterval fanger opp etter dvale; launchd har
minimalt PATH + ekspanderer ikke ~; process.execPath = Cellar-sti som dør ved
`brew upgrade node` → plistens PATH inkluderer /usr/local/bin.

Levert (TDD, test FØR kode):
- lib/launchd-plist.mjs (REN, SKRIVER ALDRI): renderPlist (XML-escape,
  StartCalendarInterval, PATH-fix), defaultLabel, resolvePaths.
- scheduler.mjs (TYNN CLI): install|uninstall|status|run-now|print|run.
  Strukturelt Claude-fri (kun process.execPath på run-detection.mjs +
  launchctl; kilde-grep-testet). run gater på os_scheduler_cadence →
  delegerer til run-detection.mjs. uid-0-nekt; idempotent bootout.
- detection-schedule.mjs (additiv, Tier-1 urørt): os_scheduler_cadence
  ('daily' default | 'interval') + daysSinceLastPoll ren helper.
- commands/kb-update.md: Tier-1/Tier-2-doc + caveats (uninstall=pause;
  re-install etter node-upgrade).

Operatør-valg: daglig default, kadens egen innstilling (settes i onboarding/C2).

Verifisert: launchd-plist 13/13 · detection-schedule 21/21 · kb-update 173 ·
kb-eval 100 · validate 239/0 · test-hooks 6/6 · plutil -lint OK · live
install→status→idempotent→uninstall på maskinen (gui/501, rent).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 19:59:18 +02:00
150b20584e feat(ms-ai-architect): Sesjon 21 — C1 Tier 1 opt-in session-forankret deteksjon (ToS-forankret) [skip-docs]
Spor C fase C1 Tier 1. Ny verifisert ToS-analyse avdekket falsk «enten/eller»:
Consumer Terms §3.7 begrenser automatisert tilgang til Claude/Anthropic, IKKE
kjøring av lokale node-scripts. Deteksjon kontakter aldri Claude → utenfor
ToS-flaten; apply (eneste Claude-steg) forblir manuelt/in-session/gated.

- lib/detection-schedule.mjs (ren): opt-in config (default AV) + shouldRunDetection
  gate + DETECTION_STEPS allow-liste + summarizeSkillLifecycle. Zero-dep parser.
- run-detection.mjs: Claude-FRITT entrypoint — kjører kun `node` på de
  allow-listede deteksjons-scriptene; kan ikke invokere claude (guard-testet).
- session-start-context.mjs: ubetinget bakgrunns-spawn → opt-in (default AV
  spawner ingenting) + surfacer skill-signaler read-only.
- commands/kb-update.md: opt-in-seksjon + ToS-note; ms-ai-architect.local.md.example.

TDD: ny test-detection-schedule.test.mjs (16). kb-update 139→155.
Suiter uendret: validate 239 · kb-eval 100 · kb-integrity 192/192.
0 skills/-mutasjon. Tier 2 (lokal OS-timer, deteksjon-only) = neste økt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 22:54:18 +02:00
e47fc9bd59 feat(ms-ai-architect): Sesjon 20 — B3 create_skill (dvelende, konstruktiv op) [skip-docs]
B3 + Spor B (krav 5+6) KOMPLETT. create_skill er speilbildet av de
destruktive ops: merge/saner/retire beviser "ingen kuratert verdi TAPT";
create beviser "ingen sub-bar skill FØDT" (kvalitetsgulv). Ingen ny
domene-skill shippet (svar 3) — mekanismen bevist, ikke brukt.

- planCreateSkill (ren): genererer scaffold + selv-validerer mot eval.mjs
  sine EGNE checkers (K2/K3/K5/K6/refTall + K10) — rubrikken har én kilde.
  Guardrail ok iff alle deterministiske K passerer + K10<terskel + navn ledig.
- TEST_DOMAIN_SPEC: kanonisk dvelende-scaffold (born compliant, K5 ratio 1.0).
- runCreatePlan (uren): gated dry-run, 0 skriving til skills/.
- applyApprovedAction create-gren: re-plan fersk → revalider (drift+kollisjon)
  → skriv scaffold + persister taksonomi-tillegg → flipp ledger.
- applyCategoryAdditions (taxonomy.mjs): additiv, klobrer aldri eksisterende eier.
- CLI create-verb i plan-skill-op + apply-skill-op.

TDD: ny test-skill-ops-create.test.mjs (16). kb-eval 84→100.
Suiter uendret: validate 239 · kb-update 139 · kb-integrity 192/192.
Deterministisk eval K1–K10 for de 5 ekte: 0 regresjon. 0 ekte skills/-mutasjon.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 21:37:19 +02:00
de3a9a483b feat(ms-ai-architect): Sesjon 19 — B3 merge-apply (cross-skill + taksonomi-persist) [skip-docs]
Merge-apply = den tyngste destruktive op-en: eksekver en operatør-godkjent
merge_skills-entry → faktisk cross-skill skills/-mutasjon. Tre mekanismer
som sanitize/retire ikke trengte: kuratert relokasjon (ikke arkiv),
taksonomi-persistering, retire-av-absorbert.

- taxonomy.mjs (ny persist): saveTaxonomy (atomisk .tmp+rename, speiler
  saveDecisions) + ren applyCategoryReassignments (repointer KUN der eier
  === from; absent/allerede-flyttet = no-op). Lag-0 er normalt read-only;
  ENESTE writer = gated merge-apply.
- applyApprovedAction merge-gren (skill-ops.mjs): re-plan fersk → revalidér
  (kollisjon → guardrail.ok=false → abort) → flytt absorbed-refs → absorber
  (moveFile; flyttingen ER bevaringen set-equality beviser) → persister
  taksonomi-repoint fra FERSK plan (drift-sikker) → arkivér absorbed-SKILL.md
  FØR rmdir → flipp ledger approved→applied. Description-forsoning forblir
  MANUELL (planner-kontrakt: apply rører aldri absorber-SKILL.md).
  archiveMove→moveFile (generisk: arkiv + kuratert flytt).
- CLI apply-skill-op.mjs merge <absorber> <absorbed> — lookup via actionKey
  (merge_skills:<sortert par>); default PREVIEW, --apply = dobbel-gate.

TDD, tmpdir-fixtures: 0 ekte skills/-mutasjon. Ny test-skill-ops-merge-apply
(7) + 2 taksonomi-tester; fjernet foreldet merge-throws fra S18-fila. Tester:
kb-eval 78→84, kb-update 137→139; validate 239 · kb-integrity 192/192 uendret.
eval --json deterministisk uendret (K10 eng+infra FAIL, øvrige PASS).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 20:54:13 +02:00
4ac18a76c8 feat(ms-ai-architect): Sesjon 18 — B3 apply-path (sanitize+retire), merge→S19 [skip-docs]
Apply-path = den destruktive frontieren: eksekver en operatør-godkjent
(status:approved) ledger-entry → faktisk skills/-mutasjon. Staget per
operatør-beslutning til single-skill ops (sanitize+retire); merge-apply
isoleres til S19 (krever taksonomi-persistering + cross-skill flytt).

- revalidateApply (ren, skill-ops.mjs): idempotent revalidering mot fersk
  re-plan — nekter ved status≠approved, op-mismatch, fersk guardrail≠ok,
  eller drift (isDeepStrictEqual fresh vs approved guardrail-snapshot).
- applyApprovedAction (impur): arkiver-så-slett (rename skills/…→archive/…
  atomisk; retire rmdir'er tom katalog sist) + flipp ledger approved→applied.
  apply:false = preview (0 mutasjon). merge_skills → throw (S19).
- setActionStatus (ren, decisions-io.mjs): ledger status-transisjon, bevarer
  targets+guardrail, audit-record beholdes.
- CLI apply-skill-op.mjs {list|sanitize|retire} — default PREVIEW, --apply =
  dobbel-gate utover ledger-approved.

TDD, tmpdir-fixtures: 0 ekte skills/-mutasjon. Tester: kb-eval 66→78,
kb-update 132→137; validate 239 · kb-integrity 192/192 uendret.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 20:32:51 +02:00
f03a0e08b2 feat(ms-ai-architect): Sesjon 16 — B3 ledger action-lag + merge_skills dry-run-planner
Spor B / B3 start. Operatør-gated dry-run for skill-livssyklus, merge først.

- decisions-io.mjs: additivt skill-nøklet `actions`-lag ved siden av urørt
  URL-nøklet `decisions` (14 URL-tester urørt = regresjonsbevis). version=1,
  loadDecisions backfiller manglende actions-nøkkel. Nye rene fn: actionKey
  (merge symmetrisk på paret), isActionDecided, recordAction (no-mutate),
  listActions. Policy A gjelder også actions.
- scripts/kb-eval/lib/skill-ops.mjs: ren planMergeSkills → {entry,diff,guardrail},
  leser ingen disk, anvender INGENTING. Guardrail = ingen kuratert verdi tapt
  (count-invariant + set-equality + kollisjons-deteksjon; ok=false ved klobring).
  Impur skall loadSkillRefs/runMergePlan + CLI plan-skill-op.mjs (gated --write).
- Ekte eng↔infra dry-run: guardrail OK (34+153=187, 0 kollisjoner), 153 fil-flytt
  + 7 taksonomi-reassign + retire eng; 0 skriving til skills/, ledger uendret
  (retning er operatør/judge-valg, ikke pushet gjennom gaten).
- TDD: test-decisions-actions (10) + test-skill-ops-merge (10, inkl. byte-for-byte
  skills/-snapshot som no-write-bevis). kb-eval 40→50, kb-update 122→132.
  Regresjon grønn: validate 239, kb-integrity 192/192.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 17:10:33 +02:00
e42a84fb7b feat(ms-ai-architect): Sesjon 6 - lag 3 verifisering-INN (authority-binding)
Lag 3 etablerer per-fil autoritetsbinding som mater verify-out regel 3 (autoritets-mismatch — regresjonens rotårsak, inert til nå pga 0% dekning). Designvalg (operatør 2026-06-19): HEADER-AS-TRUTH — en fils **Source:**-header ER den utpekte autoriteten. Gjetter ALDRI fra siterte URLer (251/303 filer siterer 4-10 → gjetning ville fått regel 3 til å bomme + 303 operatør-beslutninger = primær-fallgruven).

- lib/authority.mjs (ren lib, SKRIVER ALDRI; kun read-only kb-headers+url-normalize): resolveAuthority (validert http(s); fri tekst avvist; ikke-MS-autoritet som EU-forordning tillatt), collectDeclaredSources (normalisert Set), markUrlAuthority, authorityCoverage. - build-registry: recomputer authority_source per URL-entry fra headere (ikke carry-over) + dekningslogg. - commands/kb-update.md §4 c1: authority_source=resolveAuthority(fil) → lag-5 c2.

TDD: 11 tester FØR kode inkl. import-invariant + ende-til-ende regel 3 (source_url ≠ header-autoritet → flagged). Tester: validate 239 · kb-update 122 (+11) · kb-eval 15 · kb-integrity 115/115.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01REiKFhP4w6xGXXqWKpPCJJ
2026-06-19 22:58:10 +02:00
48884b67a6 feat(ms-ai-architect): Sesjon 5 - transformasjonslag (lag 4, doc→KB-fil)
Lag 4 destillerer et hentet Microsoft Learn-dokument til en KB-referansefil. Speiler mønsteret fra decisions-io/verify-out: ren-funksjon-lib + tynn LLM-integrasjon + TDD. lib/transform.mjs SKRIVER ALDRI — returnerer content/verdict/sti; skriving skjer kun via operatør-gate etter lag 5.

Nøkkelfunn/-fiks: gammel prompt-template.md la kilder i en bunn-seksjon, men build-registry/kb-headers.parseSourceHeader skanner kun øverste 500 bytes → authority_source-dekning = 0 %. Lag 4 legger **Source:** i HEADER-blokka — forutsetningen for at lag 3 (fremtidig) kan backfille authority_source og lag-5 regel 3 fyrer.

- buildKbHeader({title,status,category,source,lastUpdated}): Status+Source obligatoriske (kaster ved mangel). - validateKbFile(content) → {valid,missing[]}; bruker parseSourceHeader (én sannhetskilde med build-registry). - buildChange(...): eksplisitt lag-4→lag-5-bro, mater classifyChange. - resolveTargetPath(tax,category,filename): ruter via taksonomi getCategorySkill; null=ukjent→gate.

Prompt: scripts/kb-update/transform-prompt.md (doc→KB; husformat fra prompt-template.md, status-påstander eksplisitte for lag-5-gaten). Wiret i commands/kb-update.md §3.d (ny godkjent URL→fetch→destillér→header→validate→buildChange→lag5→resolveTargetPath→gate→atomisk) + §4.d (oppdateringer passerer validateKbFile). eval.mjs eksporterer nå evalSkill for kriterium-testen.

Kriterium møtt: «regenerer 1 fil → eval-score ≥ baseline» (test-transform-criterion.test.mjs). TDD: 12 lib-tester (inkl. import-invariant: ingen write-utils) + 2 kriterium FØR kode. Tester: validate 239 · kb-update 111 (+16) · kb-eval 15 (+2) · kb-integrity 115/115.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01REiKFhP4w6xGXXqWKpPCJJ
2026-06-19 22:31:26 +02:00
94a5d1bb14 feat(ms-ai-architect): Sesjon 5 carry-forward B — datoløse filer → unverified-tier
Rotårsak: en datoløs ref-fil fikk effectiveDate=0000-01-01 (alltid «stale») OG en path-basert prioritet (kunne bli critical) → flommet critical-bøtta og druknet genuint kritiske filer. Fix: ny unverified-tier deklarert i domain-taxonomy.json (lag 0, eneste sannhetskilde for prioritet).

makePriorityFn(tax) tar nå valgfri hasDate (default true → bakoverkompatibelt for eksisterende én-args-kallere); report-changes sender Boolean(fileDate). unverified rangerer sist i sorteringen — manglende dato er metadata-hygiene, ikke currency-hast. Ekte registry: 1 fil skilt ut som Unverified.

TDD: 4 tester FØR kode (test-priority-unverified.test.mjs).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01REiKFhP4w6xGXXqWKpPCJJ
2026-06-19 22:31:25 +02:00
6af3624b17 feat(ms-ai-architect): Sesjon 4 - verifisering-ut (lag 5) + adversarial regresjonstest
Lag 5 kjører ETTER transformasjon (lag 4) og FØR en kandidat-endring skrives til
en KB-fil. Den fanger regresjons-klassen: en status-påstand «korrigert» mot en
tilfeldig sitert side og stille auto-applyet (den kjente agentic-retrieval-
regresjonen — hovedkontekst måtte rette manuelt).

Regel (spec §21): status-påstander (GA/preview/versjon/pris) flagges ALLTID for
operatør, aldri auto-applyet — uansett hvor sikker evidensen ser ut.

- lib/verify-out.mjs: ren klassifiserer, null deps (speiler decisions-io).
  detectStatusClaim(text) → {isStatus, kinds}; classifyChange(change) →
  {verdict: flagged|auto-applied, status_claim, reasons}. Tre flag-regler:
  status-gate (§21) · adversarial refutering · autoritets-mismatch (regresjonens
  rotårsak). Konservativ med vilje: ved tvil flagges. SKRIVER ALDRI.
- Fixtur tests/fixtures/kb-update/agentic-retrieval-regression.json: den kjente
  regresjonen (flat «GA» mot nyansert «delvis GA … resten preview»).
- TDD: 13 tester før kode, inkl. import-invariant (ingen write-utils).
- Wiret i kb-update.md §4 c2 (lag 5 mellom identifiser-endring og skriv).

Kriterium møtt: fixtur → flagged:true, ikke auto-applied.
Tester: validate 239 · kb-update 95 (+13) · kb-eval 13 · kb-integrity 115/115.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01REiKFhP4w6xGXXqWKpPCJJ
2026-06-19 22:00:36 +02:00
fe484ec323 feat(ms-ai-architect): Sesjon 3 - decision-ledger (lag 2) + discovery-dedup
Lukker discovery-løkken gjennom operatør-gaten. data/decisions.json er eneste
skrive-autoriserte bro mellom deteksjon og KB/registry; discovery LESER den og
utelater alt operatøren har tatt stilling til.

Dedup-policy = A (operatør-valg): isDecided = enhver ledger-entry (approved/
rejected/pending). Kun helt fraværende URLer re-foreslås.

- lib/decisions-io.mjs: createLedger/load/save(atomisk)/isDecided/recordDecision
  (ren)/filterUndecided. TDD: 10 tester før kode.
- discover-new-urls.mjs leser ledger, filtrerer, rapporterer deduped_by_ledger.
  Importerer ALDRI write-utils (invariant verifisert, 6 guard-tester).
- Gate dokumentert i kb-update.md §3b (eneste skrivevei).
- decisions.json tracket via gitignore-negasjon (som domain-taxonomy.json).

Kriterium møtt: dedup-diff (rejected re-foreslås ikke runde 2).
Tester: validate 239 · kb-update 82 (+16) · kb-eval 13 · kb-integrity 115/115.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01REiKFhP4w6xGXXqWKpPCJJ
2026-06-19 21:48:03 +02:00
d3af3f73c8 feat(ms-ai-architect): Sesjon 2 - ai-foundry->foundry registry-remap
Microsoft rebranet Azure AI Foundry -> Microsoft Foundry; doc-URLer flyttet
/azure/ai-foundry/ -> /azure/foundry/. Ny lib/registry-migrate.mjs (rene
funksjoner remapKey + migrateRegistry, 10 enhetstester) + one-shot
migrate-ai-foundry.mjs (backup via lib/backup.mjs + atomisk saveRegistry).

Remap: 164 ai-foundry-URLer -> foundry (2 probede DEAD-sider far eksplisitte
mal: evaluation-evaluators -> built-in-evaluators; agent-service ->
agents/overview). Remappede entries resettes til status=unpolled/lastmod=null
sa neste poll re-evaluerer. 1 kollisjon merget (ref_files unionert).
Schema-migrering: authority_source+course lagt til alle 1343 entries.
Idempotent. Registry er gitignored (regenererbar) - kun kode committes.

kb-update 66 tester gronne, validate 239.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01REiKFhP4w6xGXXqWKpPCJJ
2026-06-19 21:09:00 +02:00
eb2a002c2c feat(ms-ai-architect): Sesjon 2 - registry-skjema (authority_source + course reservert)
build-registry leser na **Source:**/**Primary source:**-header via ny
lib/kb-headers.mjs (parseSourceHeader, 7 enhetstester) og logger dekning
(0/N i dag). Hver URL-entry far reserverte felt authority_source:null +
course:null (bakoverkompatibelt). Populering med korrekt semantikk utsatt
til verifiseringslaget (lag 3) - minimal-reservert per operator-valg.

Eksisterende status-felt (poll: tracked/not_in_sitemap/unpolled) urort for
a unnga kollisjon. kb-update 56 tester gronne.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01REiKFhP4w6xGXXqWKpPCJJ
2026-06-19 21:05:54 +02:00
8bea3a224a feat(ms-ai-architect): Sesjon 2 lag 0 - konsolider taksonomi til en sannhetskilde
Ny data/domain-taxonomy.json (tracket via gitignore-negasjon; generert
registry/rapporter forblir ignorert) konsoliderer de 4 divergerende
taksonomiene: (a) sitemap-prefikser, (b) discover INCLUDE/EXCLUDE,
(c) category->skill, (d) getFilePriority. lib/taxonomy.mjs laster + kompilerer.

Refaktor: poll-sitemaps, discover-new-urls, report-changes LESER taksonomien
(ingen embeddede kopier). Kriterium grep TARGET_PREFIXES=[ == 0 oppfylt.

Konsolideringsfunn:
- category-skill-map.json stale i 4 entries (copilot-extensibility,
  monitoring-observability, performance-scalability, prompt-engineering ->
  sa engineering; disk sier advisor/governance/security/advisor). DISK er
  kanon. Map-en er ukonsumert av kode (kun README) -> flagget, ikke rort.
- discover fikk poll-paritet (12 -> 18 sitemap-prefikser).
- skill utledes na fra kanonisk category_skill -> ingen divergens (invariant-test).

Adferdsbevarende: 0 mismatch old vs ny prioritetslogikk pa 51 endrede filer;
discover sine hardkodede skill-verdier matchet allerede disk.
Tester: validate 239, kb-update 49 (+7 taksonomi), kb-eval 13 - alle gronne.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01REiKFhP4w6xGXXqWKpPCJJ
2026-06-19 21:02:59 +02:00