feat(ms-ai-architect): release v1.10.1 — demo system + screenshot gallery
Adds one-click demo and committed screenshots so forkers see what the plugin produces without running anything. Plugin contract unchanged. - Inline <script id="demo-state-v1"> block (37 KB) built by scripts/build-demo-state.mjs from playground/test-fixtures/*.md - "Last inn demo-data" button on onboarding (replaces all state with demo) - raw_markdown persistence on project.reports[id] with equal-value guard - rehydratePasteImports() auto-fills textareas + re-renders visualizations on project surface mount - tests/screenshot/ standalone Playwright runner (own package.json) - 24 committed screenshots in playground/screenshots/v1.10.0/ (12 surfaces x 2 themes, deviceScaleFactor 2 retina, fullPage) Tests: 215 + 201 + 70 + 7 = 493 PASS, no regressions. Docs updated per OBLIGATORISK three-level rule (plugin README, plugin CLAUDE, marketplace root README, CHANGELOG). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
|
@ -158,7 +158,7 @@ Key command: `/graceful-handoff [topic-slug] [--no-commit] [--no-push] [--dry-ru
|
|||
|
||||
---
|
||||
|
||||
### [MS AI Architect — Azure AI and Microsoft Foundry](plugins/ms-ai-architect/) `v1.10.0` `🇳🇴 Norwegian`
|
||||
### [MS AI Architect — Azure AI and Microsoft Foundry](plugins/ms-ai-architect/) `v1.10.1` `🇳🇴 Norwegian`
|
||||
|
||||
Microsoft AI solution architecture guidance for Norwegian public sector and enterprise.
|
||||
|
||||
|
|
@ -173,6 +173,8 @@ Key commands: `/architect`, `/architect:ros`, `/architect:security`, `/architect
|
|||
|
||||
12 specialized agents · 24 commands · 5 skills (387 reference docs) · 2 hooks · sitemap-based KB monitoring
|
||||
|
||||
**One-click demo (v1.10.1, 2026-05-04):** "Last inn demo-data"-knappen på onboarding bootstrapper en ferdig "Demo kommune" med ett demo-prosjekt og alle 17 rapport-typer pre-importert som `raw_markdown`. Visualisering rehydreres automatisk på project-surface mount. 24 retina-screenshots committed under `playground/screenshots/v1.10.0/` (12 surfaces × 2 tema), så forkere ser pluginen uten å kjøre noe. Standalone Playwright-runner under `tests/screenshot/` (egen `package.json`).
|
||||
|
||||
**Playground (v3, v1.10.0 — felles grunnskjelett + Tier 3-adopsjon, 2026-05-04):** Multi-surface decision-builder + report viewer. The single-file HTML app lives at `playground/ms-ai-architect-playground.html` (~3870+ lines). v1.10.0 introduces a shared visual signature across all 17 report renderers and Aksel-aligned light-mode tokens.
|
||||
|
||||
- **4 surfaces:** Onboarding (4 strukturerte / 14 fritekst, prefill alle command-skjemaer) → Home (project list + 3 entry tracks) → Catalog (24 commands grouped in 5 expansion categories with search) → Project (per-project tabs, command-form prefill, paste-back report import + visualization)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "ms-ai-architect",
|
||||
"version": "1.10.0",
|
||||
"version": "1.10.1",
|
||||
"description": "Microsoft AI Solution Architect - structured architecture guidance for the full Microsoft AI stack",
|
||||
"author": {
|
||||
"name": "Kjell Tore Guttormsen"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,27 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.10.1] - 2026-05-04
|
||||
|
||||
### Added — Demo system + screenshot gallery
|
||||
|
||||
The playground now ships with a one-click demo and committed screenshots so forkers can see what the plugin produces without running anything.
|
||||
|
||||
- **`<script type="application/json" id="demo-state-v1">` inline block** — built by `scripts/build-demo-state.mjs` from `playground/test-fixtures/*.md`. Contains a complete state: 18 onboarding fields prefilled for "Demo kommune", one demo project with all 17 reports as `raw_markdown`. ~37 KB inline, file://-safe (no fetch).
|
||||
- **"Last inn demo-data" button** on the onboarding action-bar. Clicking it replaces all state with the demo and navigates to the project surface.
|
||||
- **`raw_markdown` persistence** — `handlePasteImport` now writes `markdown` to `project.reports[id].raw_markdown` (with equal-value guard to prevent render loops). Survives page reload.
|
||||
- **`rehydratePasteImports()`** — on project surface mount, fills textareas from `raw_markdown` and re-renders visualizations. Hooked via `queueMicrotask` after `innerHTML` commit.
|
||||
- **`tests/screenshot/` tooling** — standalone Playwright runner (its own `package.json`, gitignored `node_modules`). Captures 24 PNGs per release (12 surfaces × 2 themes) at `deviceScaleFactor: 2` retina, `fullPage: true`.
|
||||
- **`playground/screenshots/v1.10.0/`** — 24 committed screenshots (~28 MB total) covering onboarding, home, catalog, project surface (rapporter × 5 tabs, oversikt, kontekst, eksport).
|
||||
|
||||
### Notes on 1.10.1
|
||||
|
||||
- v1.10.0 was tagged earlier on 2026-05-04 with the foundation refactor. v1.10.1 ships the demo + screenshots without changing any v1.10.0 behavior — purely additive: one inline JSON block, one button, two new functions, one tooling directory.
|
||||
- Plugin contract (24 commands, 12 agents, 5 skills, 2 hooks, MCP) remains unchanged.
|
||||
- Tests: 215 plugin-validation + 201 + 70 + 7 = 493 PASS. Pre-existing `tests/test-ros-output.sh` fixture-missing failure is unchanged.
|
||||
|
||||
---
|
||||
|
||||
## [1.10.0] - 2026-05-04
|
||||
|
||||
### Added — Playground v3 felles grunnskjelett (foundation refactor)
|
||||
|
|
|
|||
|
|
@ -196,6 +196,12 @@ Interaktiv decision-builder + rapport-viewer for Microsoft AI-beslutninger. Erst
|
|||
| Manuell A11Y QA | Se `playground/MANUAL-CHECKLIST.md` | 10 seksjoner inkl. axe-core-kjøring per surface |
|
||||
| A11Y-rapport | `playground/A11Y-RAPPORT.md` | Statisk vurdering klar — browser-axe-kjøring pending |
|
||||
|
||||
### Demo system (v1.10.1)
|
||||
|
||||
`scripts/build-demo-state.mjs` leser alle 17 fixture-filer fra `playground/test-fixtures/` og injiserer dem som en `<script type="application/json" id="demo-state-v1">`-blokk i playground HTML (idempotent — erstatter eksisterende blokk). "Last inn demo-data"-knappen på onboarding-overflaten kaller `ACTIONS['load-demo']` som leser blokken, erstatter alle state-grener via Proxy-mutasjon, og navigerer til project-surface med 17 pre-importerte rapporter. `rehydratePasteImports()` kjøres via `queueMicrotask` etter project-surface render — fyller textareas fra `project.reports[id].raw_markdown` og kaller `handlePasteImport` for hver. `handlePasteImport` har equal-value-guard for å unngå render-loop.
|
||||
|
||||
`tests/screenshot/` inneholder en frittstående Playwright-runner med egen `package.json` (gitignored `node_modules`). `node run.mjs` produserer 24 PNG-er (12 surfaces × 2 tema, retina, fullPage) under `playground/screenshots/v1.10.0/`. Disse committes så forkere ser pluginen uten å installere noe.
|
||||
|
||||
### Inline CSS-kandidater for hoisting (v1.11.0)
|
||||
|
||||
Sesjon 3-5 la til inline CSS i `playground/ms-ai-architect-playground.html`. Kandidater for hoisting til `shared/playground-design-system/components-tier3-supplement.css`:
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
*AI-generated: all code produced by Claude Code through dialog-driven development. [Full disclosure →](../../README.md#ai-generated-code-disclosure)*
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
|
@ -375,6 +375,39 @@ All 17 report renderers now wrap output through `renderPageShell()` for a consis
|
|||
open plugins/ms-ai-architect/playground/ms-ai-architect-playground.html
|
||||
```
|
||||
|
||||
### Demo data (one-click)
|
||||
|
||||
Click **"Last inn demo-data"** on the onboarding screen to bootstrap a complete demo:
|
||||
|
||||
- 18 onboarding fields prefilled for "Demo kommune" (Norwegian municipality, deployer, high-risk AI Act)
|
||||
- One demo project ("Innbygger-chatbot for byggesak") with all 17 reports pre-imported as `raw_markdown`
|
||||
- Visualizations rehydrate automatically when the project surface mounts
|
||||
|
||||
This lets you explore every renderer, theme, and surface without any setup. The inline demo state is built by `scripts/build-demo-state.mjs` from `playground/test-fixtures/*.md`. To regenerate after fixture changes:
|
||||
|
||||
```bash
|
||||
node scripts/build-demo-state.mjs
|
||||
```
|
||||
|
||||
### Screenshot gallery
|
||||
|
||||
Screenshots of every surface in both themes live in `playground/screenshots/v1.10.0/`. They are committed so forkers see what the plugin produces without running anything:
|
||||
|
||||
| # | File | What you see |
|
||||
|---|------|--------------|
|
||||
| 01 | `01-onboarding-empty-{dark,light}.png` | Onboarding surface, empty state |
|
||||
| 02 | `02-project-rapporter-regulatory-{dark,light}.png` | All 6 regulatory renderers (classify pyramid, requirements, transparency, FRIA, conformity kanban, DPIA matrix) |
|
||||
| 03 | `03-project-rapporter-security-{dark,light}.png` | 6×5 + 7×5 risk matrices, radar, top-risks, residual-pair, recommendation-card, review kanban |
|
||||
| 03 | `03-project-rapporter-economy-{dark,light}.png` | Cost distribution P10/P50/P90, license capability matrix |
|
||||
| 03 | `03-project-rapporter-documentation-{dark,light}.png` | Migrate mat-ladder, ADR critique-card, summary read-more, POC traffic-light, utredning screen-tabs, compare scenario-cards |
|
||||
| 03 | `03-project-rapporter-tool-{dark,light}.png` | 7 tool commands (no report — pipeline-string builders) |
|
||||
| 04-06 | `04-project-oversikt-{dark,light}.png` etc. | Project screen-tabs (oversikt / kontekst / eksport) |
|
||||
| 07 | `07-home-{dark,light}.png` | Home with project list + 3 entry tracks |
|
||||
| 08 | `08-catalog-{dark,light}.png` | Catalog with 24 commands in 5 expansion-grupper |
|
||||
| 09 | `09-onboarding-prefilled-{dark,light}.png` | Onboarding with state from demo |
|
||||
|
||||
Regenerate via `cd tests/screenshot && npm install && npx playwright install chromium && node run.mjs`.
|
||||
|
||||
### Validation
|
||||
|
||||
| Test | Command | Coverage |
|
||||
|
|
|
|||
|
|
@ -258,6 +258,141 @@
|
|||
<section id="surface-project" data-surface="project" hidden></section>
|
||||
</main>
|
||||
|
||||
<!-- Inlined demo-state for "Last inn demo-data"-knapp. Bygges av
|
||||
scripts/build-demo-state.mjs fra playground/test-fixtures/*.md.
|
||||
IKKE rediger manuelt — kjør skriptet på nytt. -->
|
||||
<script type="application/json" id="demo-state-v1">
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"dataVersion": 2,
|
||||
"shared": {
|
||||
"organization": {
|
||||
"name": "Demo kommune",
|
||||
"description": "Mellomstor norsk kommune med ~8 000 ansatte. Ansvar for skole, helse, byggesak og digitalisering. Bruker pluginen for å vurdere AI-tjenester før innføring.",
|
||||
"sector": "Kommunal",
|
||||
"size": "8 000"
|
||||
},
|
||||
"regulatory": {
|
||||
"regulatory_requirements": "GDPR/Personopplysningsloven, Sikkerhetsloven, Forvaltningsloven, Arkivloven, Helseregisterloven (for helsetjenestene)",
|
||||
"ai_act_role": "deployer",
|
||||
"risk_level": "high"
|
||||
},
|
||||
"technology": {
|
||||
"cloud_platform": "Azure (Norge Øst), M365 E5, on-prem datasenter for kommunale fagsystem",
|
||||
"license_type": "M365 E5 (alle ansatte) + Azure Enterprise Agreement + Power Platform per app",
|
||||
"ai_services_in_use": "Azure OpenAI (GPT-4o), Azure AI Search, Copilot for M365 (pilot 50 brukere), Power Automate AI Builder"
|
||||
},
|
||||
"security": {
|
||||
"data_classification": [
|
||||
"Åpen",
|
||||
"Intern",
|
||||
"Fortrolig"
|
||||
],
|
||||
"data_residency": "EU/EØS — fortrinnsvis Norge",
|
||||
"dpia_practice": "Sentralt personvernombud + kommune-DPO. Mal etter Datatilsynet. DPIA er obligatorisk for alle nye AI-tjenester som behandler personopplysninger.",
|
||||
"certifications": "ISO 27001, NSM grunnprinsipper for IKT-sikkerhet, Digdir Trygg-pilot"
|
||||
},
|
||||
"architecture": {
|
||||
"preferred_platform": "Azure AI Foundry (for nye løsninger), Copilot Studio (for low-code agenter)",
|
||||
"integration_needs": "M365, Public 360 (sak/arkiv), KOMTEK (byggesak), Visma Enterprise HRM, REST API mot folkeregister og matrikkel",
|
||||
"annual_ai_budget": "3 MNOK (2026), forventet 5 MNOK (2027)"
|
||||
},
|
||||
"business": {
|
||||
"governance_model": "Sentralt AI-råd ledes av digitaliseringsdirektør. Beslutninger over 500 kNOK eskalerer til CIO. Tillitsvalgt og personvernombud inkluderes i alle høyrisiko-vurderinger.",
|
||||
"doc_format_preferences": "Markdown for tekniske dokumenter, PDF for styringsdokumenter, Confluence for arbeidsdokumenter",
|
||||
"reference_architecture": "TOGAF-tilpasset, Digdir arkitekturprinsipper, intern Confluence /arkitektur"
|
||||
}
|
||||
},
|
||||
"projects": [
|
||||
{
|
||||
"id": "demo-chatbot",
|
||||
"name": "Demo: Innbygger-chatbot for byggesak",
|
||||
"description": "AI-chatbot som hjelper innbyggere med byggesak-spørsmål. Trenger DPIA, ROS, EU AI Act-klassifisering og kostnadsestimat før beslutning. Alle 17 rapport-typer er pre-importert med eksempel-data.",
|
||||
"scenarios": [
|
||||
"Chatbot/agent",
|
||||
"Beslutningsstøtte"
|
||||
],
|
||||
"createdAt": "2026-05-04T08:00:00.000Z",
|
||||
"reports": {
|
||||
"classify": {
|
||||
"input": {},
|
||||
"raw_markdown": "# EU AI Act — Klassifisering: Demosystem\n\nSystem: Demosystem (Acme AS)\nBeskrivelse: AI-system som identifiserer objekter som krever oppfølging via sensordata + objektregister\n\n## Risikonivå\n\nRisk-level: høy\n\n## Rolle\n\nRolle: Provider og Deployer (utvikler internt + drifter selv)\n\n## Begrunnelse\n\nReasoning: Systemet brukes av offentlig myndighet for håndheving av lov, og påvirker individers rettigheter direkte gjennom automatisert beslutningsstøtte for håndtering. Dette plasserer systemet under Annex III, punkt 6 (rettshåndhevelse) og krever full høyrisiko-compliance per Art. 6(2).\n\n## Forpliktelser\n\n- Risk management system per Art. 9\n- Data governance og -kvalitet per Art. 10\n- Teknisk dokumentasjon per Art. 11\n- Logging og sporbarhet per Art. 12\n- Transparens overfor deployer per Art. 13\n- Menneskelig oversikt per Art. 14\n- Robusthet, sikkerhet og nøyaktighet per Art. 15\n- FRIA (Fundamental Rights Impact Assessment) per Art. 27 — obligatorisk for offentlig sektor\n- Registrering i EU-database per Art. 49\n- Conformity assessment per Art. 43\n\n## Frist\n\nFull compliance innen 2027-08-02 (Annex III høyrisiko full compliance).\n"
|
||||
},
|
||||
"requirements": {
|
||||
"input": {},
|
||||
"raw_markdown": "# EU AI Act — Krav for høyrisiko provider+deployer\n\nSystem: Demosystem (Acme AS)\nKlassifisering: høy risiko, rolle Provider+Deployer\n\n## Krav\n\n| Krav | Status | Kilde |\n|------|--------|-------|\n| Risk Management System etablert og dokumentert | partial | Art. 9 |\n| Treningsdata-governance med kvalitetssjekker | met | Art. 10 |\n| Teknisk dokumentasjon (Annex IV) komplett | partial | Art. 11 |\n| Automatisk logging av hendelser implementert | met | Art. 12 |\n| Transparens-instruksjoner for deployer skrevet | missing | Art. 13 |\n| Human-in-the-loop på alle sanksjonsavgjørelser | met | Art. 14 |\n| Nøyaktighetsmål med stratifisert testing | partial | Art. 15 |\n| Cybersikkerhetstiltak verifisert (NSM Grunnprinsipper) | met | Art. 15 |\n| FRIA gjennomført før idriftsettelse | missing | Art. 27 |\n| Registrering i EU-database planlagt | missing | Art. 49 |\n| Conformity assessment per Annex VI gjennomført | missing | Art. 43 |\n| CE-merking utført før markedsføring | missing | Art. 48 |\n| Post-market monitoring system etablert | partial | Art. 72 |\n| Avviksrapportering til myndigheter rutinert | partial | Art. 73 |\n\n## Sammendrag\n\n- 4 krav er møtt (met)\n- 4 krav er delvis møtt (partial)\n- 6 krav mangler implementering (missing)\n\nPrioritering: FRIA og transparens-instruksjoner må adresseres før idriftsettelse 2027-08-02.\n"
|
||||
},
|
||||
"transparency": {
|
||||
"input": {},
|
||||
"raw_markdown": "# Transparensnotis — Demosystem\n\nTittel: Informasjon om automatisert operasjonell analyse (Art. 13 og Art. 50)\n\n## Hva systemet gjør\n\nAcme AS bruker et AI-system som leser av objekt-ID (Demosystem — automatisert klassifisering) fra sensordata langs produksjonsmiljøet. Systemet identifiserer objekter som har overtrådt terskelverdi gjennom å beregne gjennomsnittlig respons mellom to datapunkt.\n\n## Hvilke data som behandles\n\nBehandlede data inkluderer objekt-ID, tidsstempel, datapunkt, objektklasse og oppslag i Acme AS objektregister. Personlig identifiserbar informasjon kobles ikke til oppføring uten saksbehandler eksplisitte godkjenning.\n\n## Hvordan beslutninger tas\n\nSystemet er beslutningsstøtte, ikke -taker. Hver flagged hendelse går til menneskelig saksbehandler som tar endelig avgjørelse om gebyr eller anmeldelse. AI-output inkluderer konfidensgrad og forklaring av hvorfor saken ble flagget.\n\n## Dine rettigheter\n\nSom registrert har du rett til innsyn (GDPR Art. 15), retting (Art. 16), sletting (Art. 17 — med begrensninger ved lovhjemmel), og å klage til Datatilsynet. Du kan også be om manuell vurdering uten AI-bistand per GDPR Art. 22.\n\n## Kontakt\n\nPersonvernombud: pvo@Acme.no\nTilsyn: Datatilsynet — postkasse@datatilsynet.no\nEU AI Act-tilsyn: under etablering (Digitaliseringsdirektoratet er forventet)\n"
|
||||
},
|
||||
"frimpact": {
|
||||
"input": {},
|
||||
"raw_markdown": "# FRIA (Fundamental Rights Impact Assessment) — Demosystem\n\nSystem: Demosystem (Acme AS)\nHjemmel: EU AI Act Art. 27 (obligatorisk for offentlig sektor)\n\n## Vurderte rettigheter\n\n| Rettighet | Impact | Tiltak |\n|-----------|--------|--------|\n| Menneskeverd | 1 | Ingen reduksjon — saksbehandler tar endelig avgjørelse, ikke AI |\n| Rett til frihet og sikkerhet | 1 | Ingen frihetsberøvelse direkte fra AI; politi/domstol er reell beslutter |\n| Respekt for privatliv | 4 | Massiv overvåking via veikameraer — kompenseres med strenge oppbevaringsregler (90 dager), formålsbegrensning, og minimering av kobling til objektregister |\n| Personvern | 4 | DPIA gjennomført; Datatilsynet konsultert; rettslig grunnlag i interne retningslinjer §13 — likevel høy impact pga skala |\n| Ikke-diskriminering | 3 | Algoritmisk bias-testing på objekt-ID fra utenlandske registre (lavere Demosystem-nøyaktighet) — kvartalsvis review |\n| Ytringsfrihet og informasjonsfrihet | 0 | Ikke berørt |\n| Forsamlingsfrihet | 0 | Ikke berørt |\n| Religionsfrihet | 0 | Ikke berørt |\n| Eiendomsrett | 2 | Gebyr/sanksjoner berører eiendomsrett — kompenseres med klagemulighet og rettslig prøving |\n| Rett til effektivt rettsmiddel | 2 | Klageadgang sikret; menneskelig review garantert; AI-forklaring tilgjengelig for klager |\n| Barns rettigheter | 1 | Lav direkte påvirkning; barn er sjelden registrerte førere |\n| Eldres rettigheter | 2 | Eldre kan ha vanskeligere for å klage digitalt — papir-klage må fortsatt være tilgjengelig |\n\n## Konklusjon\n\nTre rettigheter har høy impact (3-4): privatliv, personvern og ikke-diskriminering. Tiltakene reduserer reell risiko, men FRIA må re-evalueres årlig per Art. 27(2).\n"
|
||||
},
|
||||
"conformity": {
|
||||
"input": {},
|
||||
"raw_markdown": "# Samsvarsvurdering (Art. 43) — Demosystem\n\nSystem: Demosystem (Acme AS)\nVurderingsprosedyre: Annex VI (intern kontroll)\n\n## Sjekkliste\n\n| Krav | Status | Bevis |\n|------|--------|-------|\n| Risk Management System dokumentert | bestått | RMS-rapport v2.1 (2026-04-15) |\n| Treningsdata-governance med kvalitetskriterier | bestått | Data-governance handbook §4.2 |\n| Teknisk dokumentasjon Annex IV komplett | betinget | Mangler ytelsesmål per stratum |\n| Logging av hendelser implementert | bestått | OpenTelemetry-spans i Azure Monitor |\n| Transparens-instruksjoner skrevet | avvist | Skal leveres innen 2026-09-01 |\n| Menneskelig oversikt på saksbehandler | bestått | Workflow-design godkjent av juridisk |\n| Nøyaktighetsmål dokumentert | betinget | 96.3% overall, men ikke per objekt-ID-region |\n| Robusthet under adversarielle forhold | betinget | Test-suite mangler skitne plater og natt-scenarier |\n| Cybersikkerhetstiltak per Art. 15 | bestått | NSM Grunnprinsipper-vurdering bestått |\n| Conformity assessment underskrevet | avvist | Avhengig av FRIA-resultat |\n| EU declaration of conformity utstedt | avvist | Avhenger av Art. 47 |\n| CE-merking påført | avvist | Markedsplassering ikke aktuell (intern bruk) — vurder om Art. 48 gjelder |\n\n## Frister\n\n| Dato | Milepæl | Status |\n|------|---------|--------|\n| 2026-08-02 | GPAI-krav + Annex III høyrisiko | upcoming |\n| 2026-09-01 | Transparens-instruksjoner ferdigstilt | upcoming |\n| 2027-02-01 | FRIA og DPIA-revisjon | upcoming |\n| 2027-08-02 | Full Annex III høyrisiko-compliance | upcoming |\n\n## Konklusjon\n\n5 av 12 krav er fullt møtt; 4 er delvis møtt; 3 mangler implementering. Critical path: transparens-instruksjoner (Art. 13) blokkerer conformity declaration.\n"
|
||||
},
|
||||
"dpia": {
|
||||
"input": {},
|
||||
"raw_markdown": "# DPIA / PVK — Demosystem\n\nSystem: Demosystem (Acme AS)\nMetodikk: Datatilsynets veileder + ISO/IEC 29134\n\n## Risikomatrise (5×5)\n\n| Trussel | Sannsynlighet | Konsekvens | Score | Nivå |\n|---------|---------------|------------|-------|------|\n| Feilaktig objekt-ID-tolkning fører til urettmessig sanksjon | 3 | 4 | 12 | medium |\n| Massiv lokasjonsdata-lekkasje fra objektregister | 2 | 5 | 10 | medium |\n| AI-forklaring viser sensitiv kontekst om eier | 3 | 3 | 9 | medium |\n| Stratifisert bias mot utenlandske objekt-ID | 4 | 3 | 12 | medium |\n| Fysisk angrep på sensordata skaper deteksjonshull | 2 | 2 | 4 | low |\n| Insider-misbruk for sporing av enkeltpersoner | 2 | 5 | 10 | medium |\n| Auto-flagging utløser kjedereaksjon ved system-feil | 1 | 5 | 5 | low |\n| Subject Access Request (GDPR Art. 15) ignoreres | 3 | 3 | 9 | medium |\n\n## Trusler\n\n| ID | Beskrivelse | Severity | Tiltak |\n|----|-------------|----------|--------|\n| T-001 | Feilaktig OCR av objekt-ID | high | Konfidensgrad-cutoff på 0.95; saksbehandler-review under cutoff |\n| T-002 | Lokasjonsdata-lekkasje | critical | Pseudonymisering ved lagring; HSM-backed nøkler i Azure Key Vault |\n| T-003 | Kontekst-eksponering i AI-forklaring | high | Filter på sensitive felt; kontekst kun til autorisert saksbehandler |\n| T-004 | Bias mot utenlandske registre | high | Kvartalsvis stratifisert testing; juster modell ved >5% avvik |\n| T-005 | Insider-misbruk | critical | Audit-logging på alle oppslag; SIEM-deteksjon av unormale mønstre |\n\n## Tiltak\n\n| ID | Tiltak | Status | Eier |\n|----|--------|--------|------|\n| M-001 | Cutoff-konfidensgrad implementert | done | Tech Lead |\n| M-002 | Pseudonymisering pilotert | in-progress | Sikkerhetsarkitekt |\n| M-003 | Bias-test-pipeline etablert | planned | Data Scientist |\n| M-004 | Audit-logging utrullet | done | Drift |\n| M-005 | SIEM-regler kalibrert | in-progress | SOC |\n\n## Konklusjon\n\nRestrisiko: 4×3 → 2×2\n\nRestrisiko etter tiltak: medium-lav. DPIA godkjent av Datatilsynet 2026-04-22.\n"
|
||||
},
|
||||
"security": {
|
||||
"input": {},
|
||||
"raw_markdown": "# Sikkerhetsvurdering 6×5 — Demosystem\n\nSystem: Demosystem (Acme AS)\nRammeverk: NSM Grunnprinsipper + Microsoft Cloud Security + EU AI Act Art. 15\n\n## Score per dimensjon\n\n| Dimensjon | Score | Vurdering |\n|-----------|-------|-----------|\n| Identitet og tilgang | 4 | Entra ID med MFA, conditional access; mangler PIM på enkelte serviceprinciper |\n| Datasikkerhet og personvern | 3 | Customer-managed keys, pseudonymisering pilotert; full Customer Lockbox ikke aktivert |\n| Modell- og prompt-sikkerhet | 3 | Content filters aktivert; jailbreak-deteksjon via Azure AI Content Safety; ingen red-team-runde gjort |\n| Nettverk og perimeter | 5 | Private Endpoint mot alle Azure AI-tjenester; ingen offentlig eksponering |\n| Logging og hendelseshåndtering | 4 | OpenTelemetry → Sentinel; SOC integrert; mangler automatisk avviksdeteksjon for AI-output |\n| Operasjonell og leverandørsikkerhet | 3 | Hovedleverandører verifisert; mangler third-party penetrasjons-test siste 12 mnd |\n\n## Risikomatrise (6×5)\n\n| Risiko | Sannsynlighet | Konsekvens | Score |\n|--------|---------------|------------|-------|\n| Lekkasje av treningsdata | 2 | 5 | 10 |\n| Prompt injection i forklaringsmodell | 3 | 3 | 9 |\n| Modell-tyveri (model extraction) | 2 | 3 | 6 |\n| Adversarielt eksempel forgifter output | 2 | 4 | 8 |\n| Cloud-leverandør-utilgjengelighet | 2 | 4 | 8 |\n| Insider-trussel (unauthorized inference) | 2 | 5 | 10 |\n\n## Funn\n\n| ID | Severity | Lokasjon | Anbefaling |\n|----|----------|----------|------------|\n| S-01 | high | Identity | Aktivér PIM på alle serviceprinciper innen 2026-06-01 |\n| S-02 | medium | Data | Aktivér Customer Lockbox for operasjonelle data |\n| S-03 | high | Model | Gjennomfør formell red-team-runde med Azure AI Red Team-veiledning |\n| S-04 | low | Network | Periodisk verifikasjon av Private Endpoint-konfigurasjon |\n| S-05 | medium | Logging | Implementer ML-basert avviksdeteksjon på AI-output-rate |\n| S-06 | medium | Vendor | Bestilt third-party penetrasjons-test for Q3 2026 |\n\n## Top-risikoer\n\n| ID | Risiko | Score | Severity |\n|----|--------|-------|----------|\n| R-01 | Lekkasje av treningsdata | 10 | high |\n| R-02 | Insider-trussel (unauthorized inference) | 10 | high |\n| R-03 | Prompt injection i forklaringsmodell | 9 | high |\n| R-04 | Adversarielt eksempel forgifter output | 8 | medium |\n| R-05 | Cloud-leverandør-utilgjengelighet | 8 | medium |\n\n## Kategori-snitt\n\n| Kategori | Snitt |\n|----------|-------|\n| Identitet og tilgang | 4 |\n| Datasikkerhet og personvern | 3 |\n| Modell- og prompt-sikkerhet | 3 |\n| Nettverk og perimeter | 5 |\n| Logging og hendelseshåndtering | 4 |\n| Operasjonell og leverandørsikkerhet | 3 |\n\nRestrisiko: 5×4 → 2×3\n\n## Aggregat\n\nTotalscore: 22/30 (73%) — modent men ikke best-i-klassen. Modell- og prompt-sikkerhet er svakeste dimensjon.\n"
|
||||
},
|
||||
"ros": {
|
||||
"input": {},
|
||||
"raw_markdown": "# ROS-analyse — Demosystem\n\nSystem: Demosystem (Acme AS)\nMetodikk: NS 5814 / ISO 31000 + AI-trusselbibliotek\n\n## Risikomatrise (5×5)\n\n| Trussel | Sannsynlighet | Konsekvens | Score | Nivå |\n|---------|---------------|------------|-------|------|\n| Modell-drift som degraderer nøyaktighet | 4 | 3 | 12 | medium |\n| Treningsdata-bias mot småbiler eller MC | 3 | 3 | 9 | medium |\n| Adversarielle plate-design unngår OCR | 2 | 4 | 8 | medium |\n| API-utilgjengelighet i kritisk periode | 2 | 4 | 8 | medium |\n| Klage-saksbehandling overbelastet ved skalering | 4 | 3 | 12 | medium |\n| Datatap pga manglende georedundans | 1 | 5 | 5 | low |\n| Misbruk av AI-forklaring som bevis | 3 | 4 | 12 | medium |\n| Kjedevirkning ved feil i objektregister | 2 | 5 | 10 | medium |\n\n## Radar-akser (7 dimensjoner)\n\n| Akse | Score (1-5) |\n|------|-------------|\n| Tilgjengelighet | 4 |\n| Konfidensialitet | 4 |\n| Integritet | 4 |\n| Sporbarhet | 5 |\n| Pålitelighet | 3 |\n| Robusthet | 3 |\n| Etterlevelse | 4 |\n\n## Trusler\n\n| ID | Beskrivelse | Severity | Tiltak |\n|----|-------------|----------|--------|\n| T-101 | Modell-drift over tid | high | Månedlig retraining-pipeline; alarm ved >2% nøyaktighetsfall |\n| T-102 | Bias mot småbiler/MC | high | Stratifisert evaluering ved hver release |\n| T-103 | Adversarielle plate-design | medium | Robusthetstest mot kjente angreps-mønstre |\n| T-104 | API-utilgjengelighet | medium | Multi-region failover med RTO 1t |\n| T-105 | Saksbehandlings-overbelastning | high | Automatisk batching + prioriteringsregler |\n\n## Tiltak\n\n| ID | Tiltak | Status | Eier |\n|----|--------|--------|------|\n| M-101 | Retraining-pipeline etablert | done | MLOps |\n| M-102 | Stratifisert evalueringssett bygget | in-progress | Data Scientist |\n| M-103 | Robusthetstest planlagt | planned | Sikkerhetsarkitekt |\n| M-104 | Multi-region failover testet | done | Drift |\n| M-105 | Batching-logikk implementert | in-progress | Tech Lead |\n\n## Top-risikoer\n\n| ID | Trussel | Score | Severity |\n|----|---------|-------|----------|\n| T-101 | Modell-drift over tid | 12 | high |\n| T-105 | Saksbehandlings-overbelastning | 12 | high |\n| T-107 | Misbruk av AI-forklaring som bevis | 12 | high |\n| T-108 | Kjedevirkning ved feil i objektregister | 10 | high |\n| T-103 | Bias mot småbiler/MC | 9 | medium |\n\nRestrisiko: 4×3 → 2×2\n\n## Anbefaling\n\nROS godkjent av seksjonsleder 2026-04-25 forutsatt at M-103 (robusthetstest) ferdigstilles innen 2026-06-15. Re-evaluering ved hver modell-release eller ved endring i sak-volum > 20%.\n\n## Konklusjon\n\nRestrisiko etter tiltak: medium. ROS godkjent av seksjonsleder 2026-04-25.\n"
|
||||
},
|
||||
"review": {
|
||||
"input": {},
|
||||
"raw_markdown": "# Arkitekturgjennomgang — Demosystem\n\nSystem: Demosystem (Acme AS)\nVurderingsdato: 2026-04-30\nReviewers: AI-arkitekt, sikkerhetsarkitekt, Datatilsynet\n\n## Funn\n\n| ID | Severity | Status | Lokasjon | Anbefaling |\n|----|----------|--------|----------|------------|\n| F-01 | critical | remove | Authentication layer | Tilgang til AI-forklaringer mangler attribute-based access control — alle saksbehandler ser alle saker. Implementer ABAC basert på sak-tildeling. |\n| F-02 | high | review | Data pipeline | Treningsdata oppdateres månedlig, men ingen formell drift-deteksjon. Etabler statistisk drift-monitoring i Azure Monitor. |\n| F-03 | high | review | Model serving | Modellen serves fra en enkelt regional endpoint uten failover. Replikér til en sekundær region for RTO < 1t. |\n| F-04 | high | review | Logging | Audit-logg lagres 30 dager — under arkivlovens krav for sak-relevant info. Endre retensjon til 7 år for sak-knyttede oppslag. |\n| F-05 | medium | keep | Cost management | Ingen budsjettalarmer på Azure AI Services — prediction-kostnaden kan øke med 4× ved belastnings-topper uten varsel. |\n| F-06 | medium | review | Compliance | FRIA-rapport ikke vedlikeholdt etter modell-endring 2026-03-12. Re-evaluering trengs. |\n| F-07 | medium | keep | UX | saksbehandler-grensesnitt viser ikke konfidensgrad tydelig nok — risiko for over-trust på AI-output. |\n| F-08 | low | suppressed | Documentation | README mangler oppdatert arkitekturdiagram (siste fra 2025-11). |\n| F-09 | low | suppressed | Testing | Manglende E2E-test for utenlandske objekt-ID. |\n\n## Sammendrag\n\nCritical (1): ABAC mangler — må fikses før idriftsettelse.\nHigh (3): Drift-deteksjon, failover, logg-retensjon — må fikses innen 6 mnd.\nMedium (3): Budsjett, FRIA-revisjon, UX-konfidens — bør fikses innen 12 mnd.\nLow (2): Dokumentasjon, testing — opportunity-quality.\n\n## Anbefaling\n\nIdriftsettelse anbefales IKKE før F-01 er løst. F-02 til F-04 må adresseres innen 2026-09-01 for å holde 2027-08-02-fristen.\n"
|
||||
},
|
||||
"cost": {
|
||||
"input": {},
|
||||
"raw_markdown": "# Kostnadsestimat — Demosystem\n\nSystem: Demosystem (Acme AS)\nPeriode: 12 måneder fra produksjonssetting\nValuta: NOK\n\n## Distribusjon (P10/P50/P90)\n\n| Persentil | Månedlig (NOK) | Årlig (NOK) |\n|-----------|----------------|-------------|\n| P10 | 78 000 | 936 000 |\n| P50 | 142 000 | 1 704 000 |\n| P90 | 285 000 | 3 420 000 |\n\n## Månedlig fordeling (P50)\n\n| Komponent | Kostnad (NOK/mnd) |\n|-----------|-------------------|\n| Azure AI Services (OCR + classification) | 64 000 |\n| Azure OpenAI (forklaringsmodell) | 28 000 |\n| Azure AI Search (indeks for objektregister) | 12 000 |\n| Storage (blob + cosmos for audit) | 8 500 |\n| Compute (Container Apps for orchestration) | 11 000 |\n| Networking (Private Endpoints + egress) | 5 200 |\n| Monitoring (Sentinel + Log Analytics) | 9 800 |\n| Backup og DR | 3 500 |\n\n## TCO-tabell (3 år)\n\n| År | Capex | Opex | Total | Akkumulert |\n|----|-------|------|-------|------------|\n| År 1 | 850 000 | 1 704 000 | 2 554 000 | 2 554 000 |\n| År 2 | 120 000 | 1 875 000 | 1 995 000 | 4 549 000 |\n| År 3 | 80 000 | 2 060 000 | 2 140 000 | 6 689 000 |\n\n## Kostnadsdrivere\n\n- Datavolum: ~12 millioner Demosystem-deteksjoner/mnd\n- Forklaring-prompt-tokens: ~250 tokens per flagged hendelse\n- Reservert kapasitet for 99.9% SLA\n\n## Konfidensgradering\n\nP50 er beregnet med 95% konfidens basert på 6 måneder pilot-data. P90 inkluderer 2× volum-skalering ved fullnasjonal utrulling. P10 forutsetter optimaliserte prompt-cache (>40% hit-rate).\n\n## Anbefaling\n\nBruk P50 som budsjettlinje. Sett alarm på 1.4× P50 (≈ 200 000/mnd) for tidlig varsling.\n"
|
||||
},
|
||||
"license": {
|
||||
"input": {},
|
||||
"raw_markdown": "# Lisens-kapabilitetsmatrise — Demosystem\n\nSystem: Demosystem (Acme AS)\nVurderingsdato: 2026-04-30\n\n## Matrise\n\n| Kapabilitet | M365 E3 | M365 E5 | Copilot for M365 | Copilot Studio | Azure AI Foundry |\n|-------------|---------|---------|------------------|----------------|------------------|\n| OCR av objekt-ID | missing | missing | missing | conditional | available |\n| Custom modell-trening | missing | missing | missing | missing | available |\n| Audit-logging på AI-input | missing | available | available | available | available |\n| Customer-managed keys | missing | available | conditional | conditional | available |\n| Private Endpoints | missing | available | missing | conditional | available |\n| saksbehandler-co-pilot UI | missing | missing | available | available | conditional |\n| Norsk språkstøtte i prompts | available | available | available | available | available |\n| Compliance-pakke for leverandøren | missing | available | conditional | conditional | available |\n| Real-time inference (<100ms) | missing | missing | missing | missing | available |\n| Batch-inference for nattlige jobber | missing | missing | missing | missing | available |\n\n## Status-betydning\n\n- available: Inkludert i lisensen, klar til bruk\n- cost: Tilgjengelig som tillegg, krever separat fakturering\n- conditional: Kan brukes med begrensninger eller add-on\n- missing: Ikke tilgjengelig på dette lisensnivået\n\n## Sammendrag\n\nAzure AI Foundry er eneste lisens som dekker alle kjernekapabiliteter. Copilot Studio passer for saksbehandler-UI men kan ikke håndtere OCR/custom modeller alene. Hybrid: Foundry (kjerne) + Copilot Studio (UI) gir best dekning.\n\n## Anbefaling\n\nBruk Azure AI Foundry for AI-tjenester (OCR, klassifisering, forklaring). Hold M365 E5 på saksbehandler-arbeidsstasjoner for audit-logging og compliance-pakke. Vurder Copilot Studio i fase 2 for saksbehandler-co-pilot.\n"
|
||||
},
|
||||
"migrate": {
|
||||
"input": {},
|
||||
"raw_markdown": "# Migrasjonsplan — Demosystem\n\nSystem: Demosystem (Acme AS)\nFra: On-prem OCR + manuell klassifisering\nTil: Azure AI Foundry + saksbehandler-co-pilot\n\n## Faser\n\n### Fase 1 — Foundry-fundament (uker 1-6)\n\nVarighet: 6 uker\nStatus: done\n\nMilepæler:\n- Hub + projects opprettet i West Europe\n- Network isolation: Private Endpoints + Vnet integration\n- Identity: Entra ID-integrasjon med PIM\n- Logging: OpenTelemetry → Sentinel pipeline\n\nSuksesskriterier:\n- Pilot OCR-modell deployert med <100ms latency P95\n- Audit-logg fanger 100% av inferences\n- Sikkerhetsarkitekt godkjenner foundation-design\n\n### Fase 2 — Modell-trening og baseline (uker 7-14)\n\nVarighet: 8 uker\nStatus: done\n\nMilepæler:\n- Treningsdata kuratert (200k norske objekt-ID, stratifisert)\n- Custom modell trent på Azure ML\n- Baseline-nøyaktighet etablert (mål: ≥96% F1)\n- Bias-evaluering på utenlandske registre fullført\n\nSuksesskriterier:\n- F1 ≥ 96% overall, ≥ 92% per objekter-segment\n- Drift-deteksjon kalibrert med terskel\n- ROS-revisjon godkjent\n\n### Fase 3 — saksbehandler-co-pilot (uker 15-22)\n\nVarighet: 8 uker\nStatus: active\n\nMilepæler:\n- Forklaringsmodell (GPT-4 Turbo) integrert via Foundry\n- saksbehandler-UI bygget (Copilot Studio + Power Platform)\n- Workflow: AI flagger → saksbehandler reviewer → klar for sanksjon\n- Brukertest med 12 saksbehandler fra ulike regioner\n\nSuksesskriterier:\n- Saksbehandlingstid -40% vs baseline\n- saksbehandler-tillit >7/10 i post-pilot survey\n- Ingen kritiske UX-feil\n\n### Fase 4 — Compliance og produksjonssetting (uker 23-28)\n\nVarighet: 6 uker\nStatus: planned\n\nMilepæler:\n- FRIA gjennomført og godkjent\n- Conformity assessment ferdigstilt per Annex VI\n- DPIA oppdatert med nye operasjonelle data\n- Produksjonssetting til 3 piloter (Oslo, Bergen, Trondheim)\n\nSuksesskriterier:\n- Personvernombud signerer DPIA\n- Ingen open critical-funn fra arkitekturgjennomgang\n- Stabil 99.9% uptime i 30 dager pilot\n\n## Risiko\n\n| Risiko | Sannsynlighet | Konsekvens | Tiltak |\n|--------|---------------|------------|--------|\n| Custom modell underyter mot 96% mål | medium | high | Backup-strategi: bruk Azure AI Vision OCR som fallback |\n| saksbehandler-motstand mot AI | medium | medium | Tidlig involvering; transparent forklaring; opt-out på enkelt-saker |\n| FRIA blokkerer fase 4 | low | high | Pre-FRIA-kjøring i fase 2 for tidlig varsling |\n| Cost-overrun ved skalering | medium | medium | Reserved capacity-binding etter fase 3 |\n\n## Total varighet\n\n28 uker (~7 måneder). Avhengighet: Foundry-fundament må være ferdig før modell-trening starter.\n"
|
||||
},
|
||||
"adr": {
|
||||
"input": {},
|
||||
"raw_markdown": "# ADR-001 — Velg Azure AI Foundry som primær AI-plattform for Demosystem\n\nStatus: accepted\nDate: 2026-04-30\nDeciders: AI-arkitekt, sikkerhetsarkitekt, seksjonsleder\nConsulted: Datatilsynet, juridisk rådgiver, Drift\nInformed: prosjekteierskap, AI-teamet\n\n## Context and Problem Statement\n\nAcme AS skal modernisere Demosystem fra on-prem OCR-løsning til skybasert AI-plattform. Plattformen må støtte custom modell-trening, audit-logging på inferens-nivå, real-time inferens (<100ms P95), og full compliance med EU AI Act + GDPR + sikkerhetsloven.\n\n## Decision Drivers\n\n- Compliance med EU AI Act høyrisiko-krav (Art. 9-15)\n- Norsk dataresidens-krav\n- Customer-managed keys og Private Endpoints\n- Custom modell-trening kapabilitet\n- Total cost of ownership over 3 år\n- Driftbarhet for AI-teamet\n\n## Considered Options\n\n1. **Azure AI Foundry** — Enterprise AI-plattform med full compliance-pakke\n2. **Azure ML + AKS** — Mer kontroll, men høyere driftskost\n3. **AWS SageMaker** — Konkurransedyktig, men mangler norske compliance-sertifiseringer\n4. **On-prem GPU-cluster** — Maks kontroll, men krever betydelig CapEx og driftskompetanse\n\n## Decision Outcome\n\nChosen option: **Azure AI Foundry**, fordi det balanserer compliance, driftbarhet, og fleksibilitet best for vår bemanning og tidsramme.\n\n### Consequences\n\n- Good: full compliance-pakke for leverandøren, raskere time-to-prod, integrert med eksisterende Entra ID\n- Good: customer-managed keys og Customer Lockbox tilgjengelig\n- Bad: lock-in til Azure, men mitigert via standardiserte modell-formater (ONNX) og data-portabilitet\n- Bad: høyere månedlig kostnad enn ren Azure ML — kompenseres ved redusert egen-drift\n\n## Validation\n\nBeslutning evalueres etter 12 måneder mot KPI-er:\n- Saksbehandlingstid (mål: -40%)\n- Modell-nøyaktighet (mål: ≥96% F1)\n- Total cost (mål: ≤ NOK 1.7M/år)\n- Compliance-status (mål: 100% av krav dekket innen 2027-08-02)\n\n## More Information\n\n- Compare-rapport: see `compare-foundry-vs-aml.md`\n- Cost-analyse: see `cost-tco-3year.md`\n- Security-vurdering: see `security-foundry-baseline.md`\n"
|
||||
},
|
||||
"summary": {
|
||||
"input": {},
|
||||
"raw_markdown": "# Beslutningsnotat — Demosystem\n\nSystem: Demosystem (Acme AS)\nDato: 2026-04-30\nTil: Direktør for Digital og IT\nFra: AI-teamet\n\n## Verdict\n\nVerdict: warning\nSub: Pilot anbefalt med betingelser\n\n## Rationale\n\nArkitekturen er teknisk solid og økonomisk forsvarlig (P50 NOK 1.7M/år), men compliance-arbeidet ligger 6 måneder bak ideell tidslinje. Pilot kan starte etter at FRIA og transparens-instruksjoner er ferdigstilt; full produksjonssetting krever lukking av alle critical funn fra arkitekturgjennomgang.\n\n## Key Metrics\n\n| Metric | Verdi | Mål |\n|--------|-------|-----|\n| Compliance-dekning | 33% (4/12 fullt møtt) | 100% innen 2027-08-02 |\n| Sikkerhetsscore | 22/30 (73%) | ≥27/30 (90%) |\n| TCO 3 år | NOK 6.7M | ≤ NOK 7M |\n| Saksbehandlingstid (pilot) | -32% (estimert) | -40% |\n| ROS-restrisiko | medium | low-medium |\n\n## Next Steps\n\n- Lukk F-01 (ABAC) innen 2026-06-15\n- Gjennomfør FRIA innen 2026-07-15 (Art. 27-frist)\n- Produksjonsdokumentere transparens-instruksjoner innen 2026-09-01\n- Pilot 3 regioner (Oslo, Bergen, Trondheim) Q4 2026\n- Full utrulling Q2 2027\n\n## Restrisiko\n\nEtter foreslåtte tiltak: medium. Hovedeksponering: bias mot utenlandske objekt-ID krever løpende monitoring.\n\n## Anbefaling\n\nGodkjenn pilot-fase med tydelig stage-gate til full produksjonssetting. Avstem med Datatilsynet før fase 4.\n"
|
||||
},
|
||||
"poc": {
|
||||
"input": {},
|
||||
"raw_markdown": "# POC-plan — Demosystem\n\nSystem: Demosystem (Acme AS)\nPOC-mål: Validere at Azure AI Foundry kan dekke OCR + forklaring + audit innen tids- og kostbudsjett\n\n## Faser\n\n### Fase 1 — Foundation (uker 1-2)\n\nVarighet: 2 uker\nStatus: done\n\nMilepæler:\n- Foundry hub + project i West Europe\n- Identity og networking konfigurert\n- Sample-data uploadet (10k anonymiserte objekt-ID)\n\nSuksesskriterier:\n- Inferens-endpoint nåbart fra dev-Vnet via Private Endpoint\n- Audit-logg fanger første test-inferens\n- Cost-monitor viser daglig forbruk i Azure portal\n\n### Fase 2 — OCR-modell (uker 3-5)\n\nVarighet: 3 uker\nStatus: active\n\nMilepæler:\n- Pre-trent Azure AI Vision OCR pilotert\n- Custom fine-tune på 10k objekt-ID\n- Sammenligning av accuracy/latency mellom de to\n\nSuksesskriterier:\n- F1 ≥ 92% på pilot-sett (lavere mål enn produksjon, akseptabelt for POC)\n- Latency P95 < 200ms\n- Inference-cost ≤ NOK 0.04 per kall\n\n### Fase 3 — Forklarings-loop (uker 6-7)\n\nVarighet: 2 uker\nStatus: planned\n\nMilepæler:\n- GPT-4 Turbo via Foundry integrert\n- Prompt-template for forklaring av flagged sak\n- saksbehandler-mock UI (en enkel webside) prøvd ut med 3 brukere\n\nSuksesskriterier:\n- Forklaring referer til konfidens og kontekst korrekt i 95% av tilfellene\n- saksbehandler-feedback kvalitativt positiv (\"forståelig, men trenger justering\")\n- Prompt-tokens under 250 i snitt per sak\n\n### Fase 4 — Compliance-pre-check (uke 8)\n\nVarighet: 1 uke\nStatus: planned\n\nMilepæler:\n- Audit-logg mot EU AI Act Art. 12-krav\n- Customer-managed keys verifisert\n- Pre-DPIA-sjekk gjort med Datatilsynet\n\nSuksesskriterier:\n- Audit-logg dekker 100% av inferences med tidsstempel + bruker\n- Personvernombud signer pre-DPIA-utkast\n- Ingen åpenbare GDPR-blokkere\n\n## Risiko\n\n| Risiko | Sannsynlighet | Konsekvens | Tiltak |\n|--------|---------------|------------|--------|\n| Custom OCR-modell underyter pre-trent | medium | medium | Aksepter pre-trent for POC; planlegg custom for full prod |\n| Foundry-quota i West Europe utilstrekkelig | low | medium | Reserver kapasitet før POC starter |\n| saksbehandler-recruitment forsinker fase 3 | medium | low | Bruk interne ressurser i AI-teamet som mock |\n| Audit-logg-format ikke kompatibelt med Sentinel | low | medium | Test integrasjon i fase 1 |\n\n## POC-Verdict: BETINGET\n\nPilot-fase 1 fullført med F1=0.94 og inference-cost 0.038 NOK/kall (under budsjett). Fase 2 pågår — sammenligning av custom fine-tune mot pre-trent OCR i progress. Forklarings-loop og compliance-pre-check planlagt for siste halvdel.\n\n## Total varighet\n\n8 uker. Beslutningskriterium for full prosjektgodkjenning: alle 4 fasers suksesskriterier møtt.\n"
|
||||
},
|
||||
"utredning": {
|
||||
"input": {},
|
||||
"raw_markdown": "# AI-arkitekturutredning — Demosystem for Acme AS\n\n## 1. Bakgrunn og formål\n\nAcme AS har siden 2018 driftet en on-prem Demosystem-løsning for operasjonell analyse på tvers av leverandørens tjenesteportefølje. Løsningen er basert på et OCR-bibliotek fra 2017 og leveres som et lukket system uten mulighet for retrening eller forbedring av modell. Saksbehandlingen er manuell og tar i snitt 14 minutter per sak. Et internt AI-team utreder modernisering til en skybasert AI-plattform som støtter custom modell-trening, audit-logging på inferens-nivå, og saksbehandler-co-pilot.\n\n## 2. Mandat\n\nUtredningen skal:\n- Anbefale teknologivalg blant Azure AI Foundry, Azure ML+AKS, AWS SageMaker og on-prem GPU-cluster\n- Vurdere compliance-status mot EU AI Act, GDPR, sikkerhetsloven og arkivloven\n- Estimere TCO over 3 år\n- Identifisere risiko og foreslå mitigerende tiltak\n- Definere KPI-er for produksjonssetting\n\n## 3. Metode\n\nUtredningen kombinerer:\n- Kvalitativ analyse av compliance-krav per relevante lover og forskrifter\n- Kvantitativ TCO-analyse basert på 12 millioner Demosystem-deteksjoner/mnd\n- Risikoanalyse per NS 5814 og DPIA per Datatilsynets veileder\n- Markedsundersøkelse av tilgjengelige plattformer fra Azure, AWS og GCP\n\n## 4. Funn\n\n### 4.1 Compliance\n\nEU AI Act klassifiserer systemet som høyrisiko (Annex III, punkt 6 — rettshåndhevelse). Acme AS er Provider og Deployer, hvilket trigger alle krav i Art. 9-15 + Art. 27 (FRIA) + Art. 49 (registrering).\n\n### 4.2 Teknologivalg\n\nAzure AI Foundry er anbefalt primær plattform fordi:\n- Full compliance-pakke for leverandøren\n- Customer-managed keys og Customer Lockbox tilgjengelig\n- Custom modell-trening via integrert Azure ML\n- Norsk dataresidens (West Europe + EU Data Boundary)\n\n### 4.3 TCO\n\n3-års TCO estimert til NOK 6.7M (P50). Hovedkostnad: Azure AI Services (38%) + Azure OpenAI (16%).\n\n### 4.4 Risiko\n\nHovedrisiko: bias mot utenlandske objekt-ID, modell-drift over tid, og manglende ABAC-implementering på saksbehandler-tilgang. Alle har konkrete tiltak.\n\n## 5. Konklusjon\n\nAnbefalt: gjennomfør 8-ukers POC før formell prosjektoppstart. Ved vellykket POC, full implementering over 28 uker mot produksjonssetting Q2 2027.\n\n## 6. Anbefaling\n\nGodkjenn POC-budsjett på NOK 1.2M og forenkle prosjekt-mandat for fase 1-4 ved positiv POC-evaluering.\n\n## 7. Referanser\n\n- EU AI Act 2024/1689\n- GDPR 2016/679\n- Sikkerhetsloven (LOV-2018-06-01-24)\n- Arkivloven (LOV-1992-12-04-126)\n- NS 5814:2008 — Krav til risikovurderinger\n- Datatilsynets veileder for AI og personvern (2024)\n"
|
||||
},
|
||||
"compare": {
|
||||
"input": {},
|
||||
"raw_markdown": "# Sammenligning — Azure AI Foundry vs Azure ML + AKS\n\nSystem: Demosystem (Acme AS)\nSammenligningsdato: 2026-04-30\n\n## Subjects\n\nSubject 1: Azure AI Foundry\nSubject 2: Azure ML + AKS\n\n## Sammenligning\n\n| Aspekt | Azure AI Foundry | Azure ML + AKS | Vinner |\n|--------|------------------|----------------|--------|\n| Time-to-prod | 6-8 uker for fundament | 12-16 uker | Foundry |\n| Custom modell-trening | Integrert via Azure ML under panseret | Direkte Azure ML | Lik |\n| Compliance-pakke for leverandøren | Inkludert | Må bygges selv | Foundry |\n| Driftbarhet for AI-teamet | Lav driftbyrde, mest klikk-ops | Høy driftbyrde, full DevOps | Foundry |\n| Fleksibilitet for custom infrastruktur | Begrenset til Foundry-mønstre | Full kontroll over AKS-cluster | Azure ML + AKS |\n| Audit-logging på inferens | Innebygd | Må konfigureres manuelt | Foundry |\n| Customer-managed keys | Tilgjengelig | Tilgjengelig | Lik |\n| Customer Lockbox | Tilgjengelig | Tilgjengelig | Lik |\n| Private Endpoints | Tilgjengelig | Tilgjengelig | Lik |\n| Real-time inferens (<100ms) | Tilgjengelig via Foundry endpoints | Tilgjengelig via AKS | Lik |\n| Total cost (3 år) | NOK 6.7M | NOK 5.9M | Azure ML + AKS |\n| Lock-in til Azure | Høy | Medium (mer portabilitet i AKS) | Azure ML + AKS |\n| Forklaringsmodell-integrasjon | Native Foundry-integrasjon | Krever egen wrapper | Foundry |\n| Multi-region failover | Innebygd | Må implementeres manuelt | Foundry |\n\n## Sammendrag\n\nAzure AI Foundry vinner på time-to-prod, compliance-pakke, og driftbarhet. Azure ML + AKS vinner på pris (-12%) og fleksibilitet. Differansen i pris (~NOK 800k over 3 år) er liten sammenlignet med besparelsen i drift-tid for AI-teamet.\n\n## Vinner: Azure AI Foundry\n\n## Anbefaling\n\nFor Acme AS med begrenset KI-driftkapasitet anbefales Azure AI Foundry. For organisasjoner med dedikert MLOps-team kan Azure ML + AKS gi marginalt bedre kost-nytte.\n\n## Kontekst\n\nBeslutningen er sterkere drevet av compliance og driftbarhet enn ren kostnad. Foundry's leverandøren-pakke sparer 8-12 uker arbeid med å sertifisere baseline-konfigurasjonen.\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"activeProjectId": "demo-chatbot",
|
||||
"activeSurface": "project",
|
||||
"preferences": {
|
||||
"theme": "dark"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!--
|
||||
Klassisk script (ikke type="module") av to grunner:
|
||||
1. External <script type="module" src="..."> feiler på file:// i Chrome+Firefox
|
||||
|
|
@ -2179,6 +2314,10 @@
|
|||
projectShell +
|
||||
'</div>'
|
||||
);
|
||||
|
||||
// v1.10.0+: rehydrer paste-imports etter at DOM er bygget. queueMicrotask
|
||||
// sikrer at innerHTML har commit-et før vi spørr etter [data-paste-import].
|
||||
queueMicrotask(rehydratePasteImports);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
|
|
@ -4723,9 +4862,42 @@
|
|||
slot.innerHTML = '';
|
||||
if (result.ok) renderer(result.data, slot);
|
||||
else renderError(result.errors, slot);
|
||||
|
||||
// v1.10.0+: persister raw_markdown på aktivt prosjekt så paste-imports
|
||||
// overlever reload + rehydreres når brukeren navigerer tilbake.
|
||||
// Skip equal-value writes — set-trap dispatcher uavhengig av verdi-likhet,
|
||||
// og rehydrate kaller handlePasteImport med eksisterende markdown.
|
||||
// Uten guarden ville det blitt render-loop.
|
||||
const project = findProject(store.state.activeProjectId);
|
||||
if (project && markdown && typeof markdown === 'string' && markdown.trim()) {
|
||||
if (!project.reports) project.reports = {};
|
||||
if (!project.reports[commandId]) project.reports[commandId] = { input: {} };
|
||||
if (project.reports[commandId].raw_markdown !== markdown) {
|
||||
project.reports[commandId].raw_markdown = markdown;
|
||||
}
|
||||
}
|
||||
}
|
||||
window.__handlePasteImport = handlePasteImport;
|
||||
|
||||
// v1.10.0+: Rehydrer paste-imports fra raw_markdown på aktivt prosjekt.
|
||||
// Kalles av project surface render etter at tabs/panels er i DOM.
|
||||
// Filler textareas og kjører handlePasteImport for hver lagret rapport.
|
||||
function rehydratePasteImports() {
|
||||
const project = findProject(store.state.activeProjectId);
|
||||
if (!project || !project.reports) return;
|
||||
const root = getSurfaceEl('project');
|
||||
if (!root) return;
|
||||
Object.keys(project.reports).forEach(function (cmdId) {
|
||||
const rec = project.reports[cmdId];
|
||||
if (!rec || !rec.raw_markdown) return;
|
||||
const ta = root.querySelector('[data-paste-import="' + cmdId + '"]');
|
||||
if (ta) ta.value = rec.raw_markdown;
|
||||
// Render visualiseringen — handlePasteImport finner slot via querySelector.
|
||||
handlePasteImport(cmdId, rec.raw_markdown);
|
||||
});
|
||||
}
|
||||
window.__rehydratePasteImports = rehydratePasteImports;
|
||||
|
||||
// ============================================================
|
||||
// ONBOARDING SURFACE (Step 5)
|
||||
// ============================================================
|
||||
|
|
@ -4967,12 +5139,17 @@
|
|||
const skipBackBtn = orgName
|
||||
? '<button type="button" class="btn btn--ghost" data-action="onboarding-cancel">Tilbake til hjem</button>'
|
||||
: '';
|
||||
const hasDemoBlock = !!document.getElementById('demo-state-v1');
|
||||
const demoBtn = hasDemoBlock
|
||||
? '<button type="button" class="btn btn--secondary" data-action="load-demo" title="Hopper over onboarding og laster ett ferdig demo-prosjekt med alle 17 rapport-typer pre-importert">Last inn demo-data</button>'
|
||||
: '';
|
||||
|
||||
const actionBar = (
|
||||
'<div class="onboarding-actions">' +
|
||||
'<button type="button" class="btn btn--primary" data-action="onboarding-save">Lagre og fortsett</button>' +
|
||||
skipBackBtn +
|
||||
'<span class="onboarding-help">Du kan endre alt senere via Re-onboard.</span>' +
|
||||
demoBtn +
|
||||
'<span class="onboarding-help">Du kan endre alt senere via Re-onboard. Demo-data overskriver eksisterende state.</span>' +
|
||||
'</div>'
|
||||
);
|
||||
|
||||
|
|
@ -5134,6 +5311,34 @@
|
|||
navigate('home');
|
||||
};
|
||||
|
||||
// v1.10.0+: Last inn demo-state fra inline JSON-blokken.
|
||||
// Bygges av scripts/build-demo-state.mjs ved hver release. Erstatter all
|
||||
// eksisterende state med ferdig demo-prosjekt + 17 pre-importerte rapporter.
|
||||
ACTIONS['load-demo'] = function () {
|
||||
const node = document.getElementById('demo-state-v1');
|
||||
if (!node) {
|
||||
console.warn('[playground v3] demo-state-v1 inline JSON ikke funnet — kjør node scripts/build-demo-state.mjs');
|
||||
return;
|
||||
}
|
||||
let demo;
|
||||
try {
|
||||
demo = JSON.parse(node.textContent || '{}');
|
||||
} catch (e) {
|
||||
console.warn('[playground v3] demo-state-v1 JSON parse feilet:', e);
|
||||
return;
|
||||
}
|
||||
// Erstatt top-level state-grener via Proxy-mutasjon for reactivity.
|
||||
// schemaVersion + dataVersion bevares fra demo-state for migrasjons-konsistens.
|
||||
['schemaVersion', 'dataVersion', 'shared', 'projects', 'activeProjectId',
|
||||
'activeSurface', 'preferences'].forEach(function (k) {
|
||||
if (demo[k] !== undefined) store.state[k] = demo[k];
|
||||
});
|
||||
// Reset interne UI-state-variabler så project-render starter i 'rapporter'-tab.
|
||||
currentProjectTab = 'regulatory';
|
||||
currentProjectScreen = 'rapporter';
|
||||
navigate(demo.activeSurface || 'project');
|
||||
};
|
||||
|
||||
ACTIONS['onboarding-focus-error'] = function (ev, el) {
|
||||
ev.preventDefault();
|
||||
const path = el.dataset.errorTarget;
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 714 KiB |
|
After Width: | Height: | Size: 248 KiB |
|
After Width: | Height: | Size: 3.7 MiB |
|
After Width: | Height: | Size: 3.7 MiB |
|
After Width: | Height: | Size: 4 MiB |
|
After Width: | Height: | Size: 3.9 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 828 KiB |
|
After Width: | Height: | Size: 827 KiB |
|
After Width: | Height: | Size: 223 KiB |
|
After Width: | Height: | Size: 221 KiB |
|
After Width: | Height: | Size: 220 KiB |
|
After Width: | Height: | Size: 218 KiB |
|
After Width: | Height: | Size: 194 KiB |
|
After Width: | Height: | Size: 192 KiB |
|
After Width: | Height: | Size: 218 KiB |
|
After Width: | Height: | Size: 215 KiB |
|
After Width: | Height: | Size: 382 KiB |
|
After Width: | Height: | Size: 379 KiB |
|
After Width: | Height: | Size: 249 KiB |
|
After Width: | Height: | Size: 248 KiB |
141
plugins/ms-ai-architect/scripts/build-demo-state.mjs
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
#!/usr/bin/env node
|
||||
// Build demo state for playground v3.
|
||||
//
|
||||
// Reads all fixtures from playground/test-fixtures/*.md and inlines them as a
|
||||
// <script type="application/json" id="demo-state-v1"> block in the playground
|
||||
// HTML. The "Last inn demo-data" button on the onboarding surface reads this
|
||||
// block and bootstraps a complete demo: filled organization, one demo project,
|
||||
// all 17 reports pre-imported as raw_markdown.
|
||||
//
|
||||
// Idempotent: detects existing block by id and replaces it; otherwise injects
|
||||
// after </main>. Run from plugin root (or anywhere — uses script-relative paths).
|
||||
//
|
||||
// Usage: node scripts/build-demo-state.mjs
|
||||
|
||||
import { readFileSync, writeFileSync, readdirSync } from 'node:fs';
|
||||
import { join, dirname, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const PLUGIN_ROOT = resolve(__dirname, '..');
|
||||
const PLAYGROUND_HTML = join(PLUGIN_ROOT, 'playground', 'ms-ai-architect-playground.html');
|
||||
const FIXTURES_DIR = join(PLUGIN_ROOT, 'playground', 'test-fixtures');
|
||||
|
||||
// 17 commands that produce reports (must match CATALOG.commands order in playground).
|
||||
const REPORT_COMMANDS = [
|
||||
'classify', 'requirements', 'transparency', 'frimpact', 'conformity', 'dpia',
|
||||
'security', 'ros', 'review',
|
||||
'cost', 'license',
|
||||
'migrate', 'adr', 'summary', 'poc', 'utredning', 'compare'
|
||||
];
|
||||
|
||||
function readFixture(cmdId) {
|
||||
const path = join(FIXTURES_DIR, cmdId + '.md');
|
||||
try {
|
||||
return readFileSync(path, 'utf8');
|
||||
} catch (e) {
|
||||
console.warn('[build-demo-state] skipped fixture (missing): ' + cmdId);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function buildDemoState() {
|
||||
const reports = {};
|
||||
let count = 0;
|
||||
REPORT_COMMANDS.forEach(function (cmdId) {
|
||||
const md = readFixture(cmdId);
|
||||
if (md == null) return;
|
||||
reports[cmdId] = { input: {}, raw_markdown: md };
|
||||
count++;
|
||||
});
|
||||
console.log('[build-demo-state] inlined ' + count + ' fixtures of ' + REPORT_COMMANDS.length);
|
||||
|
||||
return {
|
||||
schemaVersion: 1,
|
||||
dataVersion: 2,
|
||||
shared: {
|
||||
organization: {
|
||||
name: 'Demo kommune',
|
||||
description: 'Mellomstor norsk kommune med ~8 000 ansatte. Ansvar for skole, helse, byggesak og digitalisering. Bruker pluginen for å vurdere AI-tjenester før innføring.',
|
||||
sector: 'Kommunal',
|
||||
size: '8 000'
|
||||
},
|
||||
regulatory: {
|
||||
regulatory_requirements: 'GDPR/Personopplysningsloven, Sikkerhetsloven, Forvaltningsloven, Arkivloven, Helseregisterloven (for helsetjenestene)',
|
||||
ai_act_role: 'deployer',
|
||||
risk_level: 'high'
|
||||
},
|
||||
technology: {
|
||||
cloud_platform: 'Azure (Norge Øst), M365 E5, on-prem datasenter for kommunale fagsystem',
|
||||
license_type: 'M365 E5 (alle ansatte) + Azure Enterprise Agreement + Power Platform per app',
|
||||
ai_services_in_use: 'Azure OpenAI (GPT-4o), Azure AI Search, Copilot for M365 (pilot 50 brukere), Power Automate AI Builder'
|
||||
},
|
||||
security: {
|
||||
data_classification: ['Åpen', 'Intern', 'Fortrolig'],
|
||||
data_residency: 'EU/EØS — fortrinnsvis Norge',
|
||||
dpia_practice: 'Sentralt personvernombud + kommune-DPO. Mal etter Datatilsynet. DPIA er obligatorisk for alle nye AI-tjenester som behandler personopplysninger.',
|
||||
certifications: 'ISO 27001, NSM grunnprinsipper for IKT-sikkerhet, Digdir Trygg-pilot'
|
||||
},
|
||||
architecture: {
|
||||
preferred_platform: 'Azure AI Foundry (for nye løsninger), Copilot Studio (for low-code agenter)',
|
||||
integration_needs: 'M365, Public 360 (sak/arkiv), KOMTEK (byggesak), Visma Enterprise HRM, REST API mot folkeregister og matrikkel',
|
||||
annual_ai_budget: '3 MNOK (2026), forventet 5 MNOK (2027)'
|
||||
},
|
||||
business: {
|
||||
governance_model: 'Sentralt AI-råd ledes av digitaliseringsdirektør. Beslutninger over 500 kNOK eskalerer til CIO. Tillitsvalgt og personvernombud inkluderes i alle høyrisiko-vurderinger.',
|
||||
doc_format_preferences: 'Markdown for tekniske dokumenter, PDF for styringsdokumenter, Confluence for arbeidsdokumenter',
|
||||
reference_architecture: 'TOGAF-tilpasset, Digdir arkitekturprinsipper, intern Confluence /arkitektur'
|
||||
}
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
id: 'demo-chatbot',
|
||||
name: 'Demo: Innbygger-chatbot for byggesak',
|
||||
description: 'AI-chatbot som hjelper innbyggere med byggesak-spørsmål. Trenger DPIA, ROS, EU AI Act-klassifisering og kostnadsestimat før beslutning. Alle 17 rapport-typer er pre-importert med eksempel-data.',
|
||||
scenarios: ['Chatbot/agent', 'Beslutningsstøtte'],
|
||||
createdAt: '2026-05-04T08:00:00.000Z',
|
||||
reports: reports
|
||||
}
|
||||
],
|
||||
activeProjectId: 'demo-chatbot',
|
||||
activeSurface: 'project',
|
||||
preferences: { theme: 'dark' }
|
||||
};
|
||||
}
|
||||
|
||||
function injectIntoHtml(html, jsonString) {
|
||||
const blockOpen = '<script type="application/json" id="demo-state-v1">';
|
||||
const blockClose = '</script>';
|
||||
const fullBlock = ' ' + blockOpen + '\n' + jsonString + '\n ' + blockClose;
|
||||
|
||||
// Detect existing block (idempotent replace).
|
||||
const re = /[ \t]*<script type="application\/json" id="demo-state-v1">[\s\S]*?<\/script>/;
|
||||
if (re.test(html)) {
|
||||
return html.replace(re, fullBlock);
|
||||
}
|
||||
// Inject after </main>.
|
||||
const mainClose = '</main>';
|
||||
const idx = html.indexOf(mainClose);
|
||||
if (idx === -1) {
|
||||
throw new Error('[build-demo-state] could not find </main> in playground HTML');
|
||||
}
|
||||
const insertAt = idx + mainClose.length;
|
||||
return html.slice(0, insertAt) + '\n\n <!-- Inlined demo-state for "Last inn demo-data"-knapp. Bygges av\n scripts/build-demo-state.mjs fra playground/test-fixtures/*.md.\n IKKE rediger manuelt — kjør skriptet på nytt. -->\n' + fullBlock + html.slice(insertAt);
|
||||
}
|
||||
|
||||
function main() {
|
||||
const state = buildDemoState();
|
||||
const json = JSON.stringify(state, null, 2);
|
||||
const html = readFileSync(PLAYGROUND_HTML, 'utf8');
|
||||
const out = injectIntoHtml(html, json);
|
||||
if (out === html) {
|
||||
console.log('[build-demo-state] no change (already up-to-date)');
|
||||
return;
|
||||
}
|
||||
writeFileSync(PLAYGROUND_HTML, out, 'utf8');
|
||||
console.log('[build-demo-state] wrote demo-state-v1 block to ' + PLAYGROUND_HTML);
|
||||
console.log('[build-demo-state] block size: ' + (json.length / 1024).toFixed(1) + ' KB');
|
||||
}
|
||||
|
||||
main();
|
||||
2
plugins/ms-ai-architect/tests/screenshot/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
node_modules/
|
||||
package-lock.json
|
||||
56
plugins/ms-ai-architect/tests/screenshot/README.md
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# Playground screenshot tooling
|
||||
|
||||
Standalone Playwright runner that captures playground screenshots for documentation.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
cd tests/screenshot
|
||||
npm install
|
||||
npx playwright install chromium # one-time, ~150 MB
|
||||
node run.mjs
|
||||
```
|
||||
|
||||
Output goes to `../../playground/screenshots/v1.10.0/`.
|
||||
|
||||
## What it captures
|
||||
|
||||
For each theme (dark, light):
|
||||
|
||||
| # | Surface | Screen / tab |
|
||||
|---|---------|--------------|
|
||||
| 01 | Onboarding | Empty state |
|
||||
| 02 | Project | Rapporter / Regulatory (default) |
|
||||
| 03 | Project | Rapporter / each of 4 other tabs |
|
||||
| 04-06 | Project | Oversikt / Kontekst / Eksport |
|
||||
| 07 | Home | Project list with demo-prosjekt |
|
||||
| 08 | Catalog | All 5 expansion-grupper |
|
||||
| 09 | Onboarding | Prefilled from demo-state |
|
||||
|
||||
= ~18 PNGs, captured with `deviceScaleFactor: 2` (retina-crisp), `fullPage: true`.
|
||||
|
||||
## How the demo state works
|
||||
|
||||
The screenshot script clicks `[data-action="load-demo"]` which reads the
|
||||
inline `<script type="application/json" id="demo-state-v1">` block from the
|
||||
playground HTML. That block is generated by `scripts/build-demo-state.mjs`
|
||||
and includes one demo project ("Demo: Innbygger-chatbot for byggesak") with
|
||||
all 17 fixture markdowns pre-loaded as `raw_markdown`. After load, the
|
||||
project surface re-runs `handlePasteImport` for each report so the
|
||||
visualizations render automatically.
|
||||
|
||||
## Regenerating demo state
|
||||
|
||||
If `playground/test-fixtures/*.md` changes:
|
||||
|
||||
```bash
|
||||
node scripts/build-demo-state.mjs
|
||||
```
|
||||
|
||||
This rewrites the `<script id="demo-state-v1">` block in the playground HTML.
|
||||
|
||||
## Commit policy
|
||||
|
||||
- Commit `playground/screenshots/v1.10.0/*.png` so forkers see what the
|
||||
plugin looks like without running anything.
|
||||
- Don't commit `node_modules/` (gitignored).
|
||||
14
plugins/ms-ai-architect/tests/screenshot/package.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "ms-ai-architect-screenshot",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"description": "Playwright tooling for capturing playground screenshots. Standalone — no relation to plugin runtime.",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"install-browser": "playwright install chromium",
|
||||
"shoot": "node run.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"playwright": "^1.49.0"
|
||||
}
|
||||
}
|
||||
186
plugins/ms-ai-architect/tests/screenshot/run.mjs
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
#!/usr/bin/env node
|
||||
// Capture playground screenshots for v1.10.0 documentation.
|
||||
//
|
||||
// Opens the single-file playground HTML via file://, drives it through:
|
||||
// - Initial onboarding (empty state)
|
||||
// - "Last inn demo-data" → project surface with all 17 reports rehydrated
|
||||
// - All 4 project screen-tabs (oversikt / rapporter / kontekst / eksport)
|
||||
// - Each rapport-tab category (regulatory / security / economy / docs / tool)
|
||||
// - Both themes (dark + light)
|
||||
//
|
||||
// Output: playground/screenshots/v1.10.0/<surface>-<theme>.png
|
||||
//
|
||||
// Usage:
|
||||
// cd tests/screenshot
|
||||
// npm install
|
||||
// npx playwright install chromium # ~150MB download, one-time
|
||||
// node run.mjs
|
||||
|
||||
import { chromium } from 'playwright';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, resolve, join } from 'node:path';
|
||||
import { mkdirSync, existsSync } from 'node:fs';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const PLUGIN_ROOT = resolve(__dirname, '..', '..');
|
||||
const HTML_PATH = join(PLUGIN_ROOT, 'playground', 'ms-ai-architect-playground.html');
|
||||
const OUT_DIR = join(PLUGIN_ROOT, 'playground', 'screenshots', 'v1.10.0');
|
||||
const HTML_URL = 'file://' + HTML_PATH;
|
||||
|
||||
const VIEWPORT = { width: 1440, height: 900 };
|
||||
const FULL_PAGE = true;
|
||||
|
||||
function ensureOutDir() {
|
||||
if (!existsSync(OUT_DIR)) mkdirSync(OUT_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
async function setTheme(page, theme) {
|
||||
await page.evaluate((t) => {
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
try { localStorage.setItem('ms-ai-architect-theme', t); } catch (e) {}
|
||||
const labels = document.querySelectorAll('[data-theme-label]');
|
||||
for (const l of labels) l.textContent = t === 'dark' ? 'Mørk' : 'Lys';
|
||||
}, theme);
|
||||
await page.waitForTimeout(150);
|
||||
}
|
||||
|
||||
async function clearState(page) {
|
||||
await page.evaluate(() => {
|
||||
try { localStorage.clear(); } catch (e) {}
|
||||
try {
|
||||
// Best-effort: clear IndexedDB databases.
|
||||
const dbs = ['ms-ai-architect-state-v1', 'ms-ai-architect-playground'];
|
||||
dbs.forEach((n) => indexedDB.deleteDatabase(n));
|
||||
} catch (e) {}
|
||||
});
|
||||
}
|
||||
|
||||
async function loadDemo(page) {
|
||||
await page.evaluate(() => {
|
||||
const action = document.querySelector('[data-action="load-demo"]');
|
||||
if (action) action.click();
|
||||
});
|
||||
// Wait for project surface to render + rehydrate paste-imports.
|
||||
await page.waitForSelector('[data-surface="project"]:not([hidden])', { timeout: 5000 });
|
||||
await page.waitForTimeout(800); // settle rehydrate microtasks
|
||||
}
|
||||
|
||||
async function clickAction(page, action) {
|
||||
await page.evaluate((a) => {
|
||||
const el = document.querySelector('[data-action="' + a + '"]');
|
||||
if (el) el.click();
|
||||
}, action);
|
||||
await page.waitForTimeout(300);
|
||||
}
|
||||
|
||||
async function clickProjectTab(page, tabId) {
|
||||
await page.evaluate((t) => {
|
||||
const el = document.querySelector('[data-action="project-tab"][data-tab="' + t + '"]');
|
||||
if (el) el.click();
|
||||
}, tabId);
|
||||
await page.waitForTimeout(400);
|
||||
}
|
||||
|
||||
async function clickProjectScreen(page, screenId) {
|
||||
await page.evaluate((s) => {
|
||||
const el = document.querySelector('[data-action="project-screen"][data-screen="' + s + '"]');
|
||||
if (el) el.click();
|
||||
}, screenId);
|
||||
await page.waitForTimeout(400);
|
||||
}
|
||||
|
||||
async function shoot(page, name) {
|
||||
const path = join(OUT_DIR, name + '.png');
|
||||
await page.screenshot({ path, fullPage: FULL_PAGE });
|
||||
console.log(' → ' + name + '.png');
|
||||
}
|
||||
|
||||
async function captureAllSurfaces(page, theme) {
|
||||
console.log('\n[' + theme + ' theme]');
|
||||
|
||||
// 1. Onboarding (empty state)
|
||||
await clearState(page);
|
||||
await page.goto(HTML_URL);
|
||||
await page.waitForSelector('[data-surface="onboarding"]:not([hidden])', { timeout: 5000 });
|
||||
await setTheme(page, theme);
|
||||
await shoot(page, '01-onboarding-empty-' + theme);
|
||||
|
||||
// 2. Load demo → project surface (rapporter screen, regulatory tab default)
|
||||
await loadDemo(page);
|
||||
await setTheme(page, theme);
|
||||
await shoot(page, '02-project-rapporter-regulatory-' + theme);
|
||||
|
||||
// 3. Project tab cycle (5 categories)
|
||||
const TABS = [
|
||||
{ id: 'security', label: 'security' },
|
||||
{ id: 'economy', label: 'economy' },
|
||||
{ id: 'documentation', label: 'documentation' },
|
||||
{ id: 'tool', label: 'tool' }
|
||||
];
|
||||
for (const tab of TABS) {
|
||||
await clickProjectTab(page, tab.id);
|
||||
await page.waitForTimeout(500);
|
||||
await shoot(page, '03-project-rapporter-' + tab.label + '-' + theme);
|
||||
}
|
||||
|
||||
// 4. Project screen-tabs (oversikt / kontekst / eksport)
|
||||
await clickProjectScreen(page, 'oversikt');
|
||||
await shoot(page, '04-project-oversikt-' + theme);
|
||||
await clickProjectScreen(page, 'kontekst');
|
||||
await shoot(page, '05-project-kontekst-' + theme);
|
||||
await clickProjectScreen(page, 'eksport');
|
||||
await shoot(page, '06-project-eksport-' + theme);
|
||||
|
||||
// Back to rapporter for nav screenshots
|
||||
await clickProjectScreen(page, 'rapporter');
|
||||
|
||||
// 5. Home surface
|
||||
await clickAction(page, 'goto-home');
|
||||
await page.waitForSelector('[data-surface="home"]:not([hidden])');
|
||||
await page.waitForTimeout(300);
|
||||
await shoot(page, '07-home-' + theme);
|
||||
|
||||
// 6. Catalog surface
|
||||
await clickAction(page, 'goto-catalog');
|
||||
await page.waitForSelector('[data-surface="catalog"]:not([hidden])');
|
||||
await page.waitForTimeout(300);
|
||||
await shoot(page, '08-catalog-' + theme);
|
||||
|
||||
// 7. Onboarding (with prefilled state from demo)
|
||||
await clickAction(page, 'goto-onboarding');
|
||||
await page.waitForSelector('[data-surface="onboarding"]:not([hidden])');
|
||||
await page.waitForTimeout(300);
|
||||
await shoot(page, '09-onboarding-prefilled-' + theme);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
ensureOutDir();
|
||||
console.log('[screenshot] launching Chromium…');
|
||||
const browser = await chromium.launch();
|
||||
const context = await browser.newContext({
|
||||
viewport: VIEWPORT,
|
||||
deviceScaleFactor: 2 // crisper screenshots for retina
|
||||
});
|
||||
const page = await context.newPage();
|
||||
page.on('console', (msg) => {
|
||||
const t = msg.type();
|
||||
if (t === 'error' || t === 'warning') {
|
||||
console.warn(' [browser ' + t + '] ' + msg.text());
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
for (const theme of ['dark', 'light']) {
|
||||
await captureAllSurfaces(page, theme);
|
||||
}
|
||||
console.log('\n[screenshot] done — output: ' + OUT_DIR);
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('[screenshot] FAILED:', err);
|
||||
process.exit(1);
|
||||
});
|
||||