# C3 Spike — Learn Platform API for kurs-deteksjon (Fase 0) _Verifisert grunnlag for C3-spec-en. Skrevet 2026-06-23 (Sesjon 29). **Fase 0 = FERDIG** (auth-oppsett + full API-kartlegging). Neste økt: skrive `docs/c3-course-detection-plan.md` på dette grunnlaget. Ingen detektor-kode før spec er godkjent._ ## Beslutning (operatør, S29) Kurs-deteksjon (krav 3) bygges på **Microsoft Learn Platform API** (`/api/v1`, Entra ID app-only) — IKKE legacy `/api/catalog/` (anonym, deprekeres «starting June 2026») og IKKE microsoft-learn-MCP (docs-only, ingen dato/produkt-filter). MCP er feil verktøy; Platform API er future-proof. Begrunnelse: kunnskapskjernen skal stå på egne ben. ## Oppsett — FERDIG (engangs, operatørens private miljø) - Entra-app `ms-ai-architect-learn-catalog` registrert i operatørens **private** Entra-tenant (single-tenant, ingen redirect-URI, **ingen API-tillatelser** — offentlig innhold krever ingen app-rolle; bekreftet ved at token virker uten). - **Hemmeligheter i macOS Keychain** (account `ktg`): `learn-platform-client-secret` (utløp **~2028-06**, 24 mnd — eneste vedlikeholdspunkt), `learn-platform-tenant-id`, `learn-platform-client-id`. Aldri i repo/env. (Literal-IDer bevisst ikke i committet doc.) - Auth verifisert grønn: client-credentials → token (scope `https://learn.microsoft.com/.default`) → HTTP 200 mot `/api/v1/modules`. - **Detektoren leser creds rett fra Keychain ved kjøretid** (`security find-generic-password`) — ingen `~/.zshenv`/env-eksponering (strengere). Mønster bevist i efemert `/private/tmp/claude-learn-api-verify.sh` (slettes; reproduserbart). ## Verifisert API-kontrakt - **Base:** `https://learn.microsoft.com/api/v1` · **påkrevd:** `?api-version=2023-11-01-preview` (kun preview-versjon finnes; kortere støttesyklus). - **Per-type endepunkter** (ikke ett kombinert katalog-svar): `/api/v1/modules` ✅, `/api/v1/learning-paths` ✅ (**kebab-case**, ikke camelCase). `/api/v1/products`-taksonomi finnes IKKE (404). - **Respons:** `{"value":[…], "nextLink":…}` — cursor-paginering via `nextLink`; `maxpagesize` ≤ 100 (default 30). - **Modul-felt:** `id` (UID, stabil nøkkel), `title`, `updatedAt` (ISO 8601), `products[].id`, `roles[]`, `levels[]`, `subjects[]`, `units[]`, `url`, `summary`, `durationInMinutes`. Learning path: samme + `modules[]`. - **Filter-semantikk:** flere params = AND; komma-separerte verdier i én param = OR. Produkt-filter virker **server-side** (`products=azure-openai` → 34 treff = ekte filtrering, ikke ignorert). ## Gotchas (MÅ håndteres i spec/kode — verifisert empirisk) 1. **`updatedAt.gt` krever FULL ISO 8601 datetime.** `updatedAt.gt=2026-01-01T00:00:00Z` → virker (100). Dato-only `updatedAt.gt=2026-01-01` → **fail-closed (0 treff)**, til tross for at doc-eksempelet bruker dato-only. Dette er hjertet i currency-deteksjonen — pin formatet. 2. **Produkt-slugs må enumereres fra live data.** Doc-eksempelet `azure-ai-foundry` → **0** (ikke en levende module-slug). Funnet i domenet (delvis, fra første 100 moduler): `ai-builder, microsoft-copilot-studio, ms-copilot, agent-365, power-automate, power-platform, power-apps, power-pages` + `azure-openai` (34 via filter). Siden `/api/v1/products` ikke finnes: enumerér ved å paginere alle moduler og samle distinct `products[].id`, eller finn et taksonomi-endepunkt. 3. **Deteksjonslogikk:** ny UID = nytt kurs · endret `updatedAt` = oppdatert kurs · forsvunnet UID = slettet. `updatedAt` endres IKKE ved minor edits (best-practices-doc). 4. **Locale:** `locale=nb-no` returnerer treff men faller tilbake til en-us-metadata der oversettelse mangler → bruk `en-us` som primær. ## Foreslått design for spec (til godkjenning neste økt) - **Node-klient (Claude-fri, passer decision-ledger-arkitekturen):** Keychain-creds → token → paginer `/api/v1/modules` + `/api/v1/learning-paths` filtrert på domene-produkter + `updatedAt.gt=` → diff mot lokalt register av kjente UIDs. - **Output = leads inn i `decisions.json`** (operatør-gate): «disse nye/endrede kursene finnes i dine dekkede produkter — vurder om temaet bør dekkes i KB». IKKE auto-ingest av kursinnhold som KB-filer («oppdage … som bør dekkes»). - **Skill-mapping:** produkt-slug → skill som **config**, ikke hardkoding (slug-sett finaliseres fra live taksonomi). - **Arkitektur-invariant (uendret):** deteksjon skriver ALDRI til KB direkte; kun forslag via `decisions.json` etter operatør-gate. Scheduler-entrypoint strukturelt Claude-fri. ## Verifiseringskilder (offisielle) - Platform API overview / get-started / developer-reference / best-practices / release-notes / FAQ — alle under `learn.microsoft.com/training/support/integrations-learn-platform-api-*`. - Empirisk: probe-kjøringer mot live `/api/v1/modules` (S29), token-auth bekreftet.