Sesjon 29: Platform API-beslutning (vs legacy/MCP), Entra app-only registrert i privat tenant, creds i Keychain (secret-utløp ~2028-06), auth verifisert grønn. Full API-kontrakt + 2 kritiske gotchas (updatedAt.gt krever full ISO; produkt- slug azure-ai-foundry død) dokumentert i docs/c3-course-detection-spike.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
35 lines
4.8 KiB
Markdown
35 lines
4.8 KiB
Markdown
# 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=<sist kjørt, full ISO>` → 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.
|