Files
boc/workcamp/VOL6-Lessons-Learned.md
T

489 lines
28 KiB
Markdown
Raw Normal View History

# AMOS Development Workcamp 2026
# Volume 6: Lessons Learned and Continuous Improvement
# Period: 2026-06-04 2026-06-07 (intensiv fas)
# Genererat: 2026-06-07 | Klassifikation: INTERN KONFIDENTIELL
---
## INLEDNING
Denna volym dokumenterar incidenter, rotorsaksanalyser (5 Why), förbättringar (Kaizen-register) och
lärdomar från AMOS Workcamp 2026. Målet är att nästa workcamp inte upprepar samma misstag.
Claude × Siemens-linsen gäller för detta dokument: var incident dokumenteras ärligt, inklusive
obekväma fynd. "Surface:a verkliga fynd (även obekväma)" Claude-sidan av beslutslinsen.
---
## AVSNITT 1: INCIDENTANALYS 5 WHY
### INCIDENT 1: LandveX = bostad-incidenten
**Symptom:** ESLM (ALETHEIA i test) och produktionschatten (`/api/aamos/chat`) svarade att LandveX
säljer bostäder. Gravt faktafel med potentiell kundpåverkan om det gått live.
**Tidpunkt:** Upptäckt 2026-06-06 under systematisk systemkunskaps-härdning.
**5 Why-analys:**
| Nivå | Varför? | Svar |
|------|---------|------|
| 1 | Varför svarade AI att LandveX säljer bostäder? | Produktionschatten hade ingen aktuell LandveX-definition. |
| 2 | Varför saknade chatten korrekt definition? | `/api/aamos/chat` anropade `getEnrichedPrompt()``getFactsContext()` → hårdkodad `wavult-facts.mjs`. Den filen hade LandveX-def som proptech/fastighet. |
| 3 | Varför hade `wavult-facts.mjs` fel definition? | Ingen process för att hålla filen synkad med kanonisk AAMOS_CANON.md. Filen skrevs manuellt vid ett tidigt skede och uppdaterades aldrig. |
| 4 | Varför fanns det 39 konkurrerande truth-filer? | Ingen utsedd kanonisk sanningskälla. Varje session/feature kunde skapa en ny "truth"-fil. |
| 5 | Varför saknade RAG en kanonisk källa? | RAG-index skapades ad-hoc, läste bara 3 filer, och RAG-stubs svarade `ok:true` även när index var tomt felet doldes. |
**Rotorsak:** Avsaknad av en enda kanonisk sanningskälla + stubs som dolde att systemet var trasigt.
**Åtgärder vidtagna:**
- Skapade `/opt/amos/data/AAMOS_CANON.md` (ENDA kanoniska sanningskällan, E4-klassad)
- Patchade `rag.mjs` (CANON tier-1, alltid läst)
- Byggde om RAG-index (94 chunks)
- Rättade `wavult-facts.mjs` med korrekt LandveX-definition
- Ändrade `LOCKED RULES` i produktionschatten (fakta alltid-injicerad)
- Neutraliserade bostad-orphan (`landvex-landing.html` → redirect)
- Arkiverade 8 dubblett-truth-filer
**Verifierat resultat:** "Säljer LandveX bostäder?" → AI: "Nej... infrastrukturkontroll." HTTP 200.
**Lärdom för nästa workcamp:**
> En enda CANON-fil är bättre än tio semi-korrekta truth-filer. Stubs ska ALDRIG svara `ok:true` på
> tomma svar det döljer att systemet är trasigt.
---
### INCIDENT 2: OOM-kraschen via SocialAuto restart-storm (2026-06-05)
**Symptom:** Alla domäner mot port 3100 gav timeout (000). amos-core nådde 5.2GB/6.0GB RAM,
1850 aktiva tasks, NATS 503-flood. Systemet var i praktiken nere.
**Tidpunkt:** 2026-06-05 (exakt tid ej loggad i dagbok, men under nattens arbete).
**5 Why-analys:**
| Nivå | Varför? | Svar |
|------|---------|------|
| 1 | Varför kraschade amos-core med OOM? | 5.2GB RAM → 6.0GB limit. Systemet hade 1850 tasks. |
| 2 | Varför var det 1850 tasks? | 137 parallella Chromium-instanser (stealth-mode) körde simultaneously, vardera ~100MB. |
| 3 | Varför körde 137 Chromium-instanser? | SocialAuto (apifly job-posting, `social-account-automation.mjs`) relanserade ALLA queued/failed-jobb vid varje omstart utan concurrency-tak. |
| 4 | Varför relanserades alla jobb vid omstart? | Kod saknade global semafor/concurrency-limit. Vid restart = ny storm av parallella Chromium-launches. |
| 5 | Varför fanns ingen concurrency-limit? | Funktionen byggdes utan att ta hänsyn till restart-scenariot. Ingen review av resursförbrukning per job. |
**Rotorsak:** SocialAuto's restart-beteende (amplifiering: varje omstart = ny storm) kombinerat
med avsaknad av global concurrency-begränsning.
**Åtgärder vidtagna:**
1. Cancellerade 274 skenande jobb i `/opt/amos/data/social-account-jobs.json`
2. PATCH: global semafor `SOCIALAUTO_MAX_CONCURRENT=3` runt `runAutomation()`, wrapper `_runAutomationCore`
**Verifierat resultat:** amos-core 200, 1.7GB RAM, load 2.0. Stabilt.
**Diagnostisk lärdom:**
> Vid amos-core-strul: kolla ALLTID `pgrep -fc chrome` och `social-account-jobs.json` status-counts FÖRST.
> Restart utan att cancellera jobb förvärrar situationen.
---
### INCIDENT 3: Provider-kredithaveri (xAI/Grok, 2026-06-04)
**Symptom:** Grok/xAI tog slut på krediter mitt i en orkestrering. Erik beskrev det som "generalhaveri".
Orkestreringen kunde inte slutföras. Allt som förlitade sig på Grok som provider blockerades.
**Tidpunkt:** 2026-06-04 under dagsarbete.
**5 Why-analys:**
| Nivå | Varför? | Svar |
|------|---------|------|
| 1 | Varför havererade orkestreringen? | Grok/xAI-kontot var tomt på krediter. |
| 2 | Varför var kontot tomt utan förvarning? | Ingen kredit-monitor för xAI-kontot. |
| 3 | Varför saknades kredit-monitor? | Varje provider behandlades manuellt. Ingen systemisk kreditövervakning. |
| 4 | Varför saknades systemisk kreditövervakning? | AI-gateway (som byggdes natten efter) existerade inte ännu. |
| 5 | Varför byggdes inte AI-gateway tidigare? | Multi-provider failover var inte prioriterat tills haveriet bevisade behovet. |
**Rotorsak:** Avsaknad av proaktiv kreditövervakning och automatisk failover.
**Åtgärder vidtagna (natten 2026-06-04 → 06-05):**
- Byggde AI-gateway (`/opt/amos/data/ai-gateway/gateway.mjs`, port 3270, PM2)
- 6 providers med auto-failover + circuit-breaker
- FAILOVER BEVISAD LIVE (trasig provider → groq, 1 hopp)
- Provider-monitor (`monitor.mjs`, PM2): pollar 7 providers var 5:e min
- Auto-larm CRITICAL till Winston (kredit) och Johan (nedtid) via HomoDeus
- Tickets utfärdade: Johan PROV-001..006, Winston PROV-W1..6
- Grok exkluderades från gateway tills påfylld
**Absolut regel (Erik, CAPS):**
> "ALDRIG I PRODUKTION. VARJE PROVIDER: PRIMÄRT REVOLUT + FALLBACK ANNAN BANK + AUTO-TOPUP + BUFFERT."
**Ansvarig framåt:**
- Johan/Sven: teknisk setup/monitor/failover
- Winston/Rufus: kort/konton/påfyllning
---
### INCIDENT 4: Leon/Vincento-kontaminering av träningsdata (2026-06-06)
**Symptom:** v3 och v4 av ESLM-träningsdata innehöll 90+129 Leon/Vincento-referenser (train) och
17+18 (validation). Modellen lärde sig en simulerad persona som aldrig existerat. Träningen stoppades.
**Tidpunkt:** Upptäckt 2026-06-06 22:18 efter Eriks klargörande att Leon = simulering.
**5 Why-analys:**
| Nivå | Varför? | Svar |
|------|---------|------|
| 1 | Varför var träningsdata kontaminerad med Leon/Vincento? | Varje träningsexempel hade AAMOS-systemets kontext i system-prompten, inklusive team-mappning med Leon. |
| 2 | Varför fanns Leon i system-prompten? | Leon behandlades som verklig anställd i alla systemfiler. Ingen markering som simulering. |
| 3 | Varför behandlades Leon som verklig? | Ingen kontroll av personas mot HR-register. Leon hade e-post, agent-mappning, payroll-post (EMP-004) och kodade roller. |
| 4 | Varför hade en simulering alla verkliga attribut? | Simuleringen designades för realism men ingen distinktion skapades mellan "simulerad test-persona" och "verklig anställd". |
| 5 | Varför saknades distinktionen? | Systemet hade ingen metadata-tagg för simulerade vs. verkliga entiteter. |
**Rotorsak:** Avsaknad av entitetstyp-distinktion (simulerad vs. verklig) i systemet, kombinerat med
att Leon hade alla attribut av en verklig anställd (e-post, payroll, kod-routing, agent).
**Åtgärder vidtagna:**
- v3 och v4 kasserades omedelbart
- v5 skapades: droppade 12 371 train + 1 357 val företagsspecifika exempel
- ALLA system-prompts byttes mot neutral generell ("evidensbaserad assistent för verksamhetsdrift")
- 3 parallella purge-agenter kördes (purge1_api, purge2_data, purge3_scripts)
- EMP-004 "Leon Magnusson" (alias för Leon Russo, samma syntetiska pnr) raderades ur payroll/HR
- Slutkoll: Leon Russo=0, Leon Magnusson=0, vincento=0, 900510-3456=0 i aktiv kod
**Effekt på arkitektur:**
Incidenten ledde direkt till principen **Separation of weights & facts** (SD-003):
> "Modellen bär ALDRIG företagsdetalj. Fakta injiceras via MNEMOSYNE vid runtime."
---
### INCIDENT 5: JWT Algorithm Confusion (CVSS 10.0) Identifierad och åtgärdad 2026-05-08
**Symptom:** Alla `authMiddleware`-instanser använde `jwt.decode()` istället för `jwt.verify()`.
Vem som helst kunde förfalska admin-JWT utan att känna till secret.
**Tidpunkt:** 2026-05-08 under red-team/hardening-arbete.
**5 Why-analys:**
| Nivå | Varför? | Svar |
|------|---------|------|
| 1 | Varför kunde JWT:er förfalskas? | `jwt.decode()` verifierar INTE signaturen bara decodes base64. |
| 2 | Varför användes `jwt.decode()` istället för `jwt.verify()`? | Förväxling av metodnamn/syfte vid initial implementation. |
| 3 | Varför spreds felet till 6 filer? | Copy-paste av auth-middleware utan review. Ingen centraliserad auth-hjälpfunktion. |
| 4 | Varför fångades det inte i review? | Ingen security review-process eller automatiserad SAST (static analysis). |
| 5 | Varför saknades security review? | Arbetstempon under byggfasen prioriterade features före säkerhetsreviews. |
**Rotorsak:** Copy-paste + avsaknad av centraliserad auth-hjälpfunktion + ingen security review.
**Åtgärder:** Fixad i 6 filer. `alg:none`-attack blockerad. Rate limiting, security headers, input validation tillagda.
---
### INCIDENT 6: Kafka-backbone degraderad i 8 dagar (2026-06-07)
**Symptom:** Kafka-klustret (3-broker KRaft StatefulSet) körde i degraderat läge med 2/3 brokers i
8 dagar utan att det uppmärksammades. kafka-1 saknades.
**Tidpunkt:** Upptäckt 2026-06-07 14:45 under infrastrukturinventering.
**5 Why-analys:**
| Nivå | Varför? | Svar |
|------|---------|------|
| 1 | Varför körde Kafka med 2/3 brokers? | kafka-1 kunde ej skapas pga ResourceQuota-blockering och borttagen EBS-volym. |
| 2 | Varför blockerade ResourceQuota? | init-container `fix-volume` saknade resource limits → `wavult-quota` blockerade (FailedCreate ×721 över 8 dagar). |
| 3 | Varför var EBS-volymen borttagen? | kafka-1:s PVC var bunden till vol-0891ca1531dc90def som raderats (InvalidVolume.NotFound). |
| 4 | Varför uppmärksammades det inte? | Ingen monitoring av Kafka broker-hälsa. Degraderat läge genererade inga larm. |
| 5 | Varför saknades Kafka-monitoring? | Observability-gap. Fokus på app-hälsa, ej backbone-hälsa. |
**Rotorsak:** Avsaknad av Kafka broker-hälsoövervakning. 8 dagar = oacceptabelt för produktionsbackbone.
**Åtgärder:**
- Patchade init-container med resource limits (25m/64Mi requests, 100m/128Mi limits)
- Raderade orphaned PVC → EBS-CSI provisionerade ny 20Gi gp3
- Broker rejoinade via replikation (RF=3 tålde det)
- Rolling restart av hela STS
- **RESULTAT:** 3/3 brokers Running, 0 under-replicated partitions, ISR fullständig
---
### INCIDENT 7: host-2 DNS-beroende på Tailscale MagicDNS
**Symptom:** host-2 (AMI-klon av server-2) kunde inte resolva RDS-DNS och gav ENOTFOUND.
`/health/ready` = DEGRADED. Hade registrerats i target group (tur att djup health-check stoppade det).
**Tidpunkt:** 2026-06-05 02:3803:09 UTC.
**5 Why-analys:**
| Nivå | Varför? | Svar |
|------|---------|------|
| 1 | Varför kunde inte host-2 resolva RDS? | `/etc/resolv.conf` pekade på 100.100.100.100 (Tailscale MagicDNS). host-2 hade ingen Tailscale. |
| 2 | Varför pekade resolv.conf på Tailscale? | AMI skapades från server-2 som kör Tailscale. Statisk resolv.conf kopierades. |
| 3 | Varför använder server-2 Tailscale som primär DNS? | Tailscale MagicDNS installerades tidigt för dev-convenience och ersatte VPC-resolver. |
| 4 | Varför byggdes ingen DNS-resiliens in? | Ingen policy för DNS-konfiguration på prod-hostar. |
| 5 | Varför saknades DNS-policy? | Det fungerade på server-2 problemet syntes bara vid skalning till ytterligare host. |
**Rotorsak:** Prod-DB-resolution beroende av Tailscale. Ej synligt på en host, kritiskt på två.
**Åtgärder:**
- host-2 v2: user-data skriver `/etc/resolv.conf` → nameserver 172.31.0.2 (VPC-resolver) + `chattr +i`
- server-2: systemd-resolved drop-in `/etc/systemd/resolved.conf.d/99-vpc-fallback.conf` (FallbackDNS=172.31.0.2)
- **ALB-lärdom:** Deep health-check (`/health/ready` med DB-check) förhindrade att degraderad host fick trafik.
---
## AVSNITT 2: KAIZEN-REGISTER
Kaizen = kontinuerliga förbättringar som identifierades och genomfördes under workcampet.
### K-001: env-preload.mjs löser ESM-import-ordningsproblematik
**Problem:** Stripe och APNS lästes vid ESM-import-tid (rad 11) FÖRE env-loadern (rad 34+) → låstes i MOCK_MODE.
**Förbättring:** `env-preload.mjs` importeras som ALLRA FÖRSTA rad i `index.mjs` laddas hela env-filen innan någon route-import.
**Effekt:** End-to-end Stripe-session skapad (cs_test_…). Inga kodändringar vid sk_live_-switch.
### K-002: ALB health-check → /health/ready (djup, DB-check)
**Problem:** ALB health-check mot `/health` (liveness) = process up men ej DB. En degraderad host fick trafik.
**Förbättring:** Health-check ändrad till `/health/ready` som gör faktisk DB-round-trip.
**Effekt:** host-2 (ENOTFOUND på RDS) hölls automatiskt utanför rotation. Self-protecting arkitektur.
### K-003: Idempotent Stripe-webhook med processed_stripe_events-tabell
**Problem:** Dubbel webhook (Stripe-retry ELLER 2 hosts) → dubbel kreditering möjlig.
**Förbättring:** Ny tabell `quixzoom.processed_stripe_events` (event_id PK), `INSERT ON CONFLICT DO NOTHING` + atomisk `balance = balance + credits`.
**Effekt:** Dubbel-kreditering matematiskt omöjlig oavsett antal hostar eller Stripe-retries.
### K-004: Concurrent-tak för SocialAuto (SOCIALAUTO_MAX_CONCURRENT=3)
**Problem:** SocialAuto relanserade alla queued jobs vid restart utan tak → OOM.
**Förbättring:** Global semafor runt `runAutomation()`, wrapper `_runAutomationCore`.
**Effekt:** Max 3 Chromium-instanser simultant. Restart = ingen storm.
### K-005: AI-gateway med auto-failover (circuit-breaker)
**Problem:** En provider (Grok) tar slut → hela orkestreringen havererar.
**Förbättring:** AI-gateway med 6 providers, task-kedjor (reasoning/fast/search/creative/financial/default), circuit-breaker.
**Effekt:** FAILOVER BEVISAD LIVE: trasig provider → groq, 1 hopp, 0 avbrott i orkestrering.
### K-006: Provider-monitor var 5:e minut med auto-larm
**Problem:** Ingen visste att xAI/Grok var tomt förrän orkestrering havererade.
**Förbättring:** `monitor.mjs` (PM2) pollar 7 providers var 5:e min. Auto-larm CRITICAL till Winston (kredit) och Johan (nedtid) via HomoDeus.
**Effekt:** Reaktiv → proaktiv kreditövervakning.
### K-007: AAMOS_CANON.md som enda kanonisk sanningskälla
**Problem:** 39 konkurrerande truth-filer → LandveX=bostad-incidenten.
**Förbättring:** En enda CANON-fil (E4), tier-1 i RAG, alltid-injicerad i produktionschat.
**Effekt:** Systemet svarar korrekt om LandveX. Fakta uppdateras på ett ställe.
### K-008: Stub-transparens (X-AAMOS-Stub header + Warning + _stub:true)
**Problem:** 432 stubs svarade `ok:true` på tomma svar → dolde att subsystem var döda.
**Förbättring:** Varje stub-träff loggas + `X-AAMOS-Stub:true` + `Warning`-header + `_stub:true` i body + ny `/api/_stub-report`.
**Effekt:** Konfigurerad förmåga som ej är ansluten syns nu i instrumenteringen.
### K-009: SSM Run Command för root-operationer (nginx/systemd utan sudo-beroende)
**Problem:** nginx-filer ägdes av root/ec2-user → bernt kunde ej skriva → blockerade nginx-tickets till Johan.
**Förbättring:** AWS SSM Run Command via IAM-roll `platform-ec2-ssm-role`. Mönster: `aws ssm send-command --document AWS-RunShellScript`, base64-encoda komplexa script.
**Effekt:** Kan nu ändra nginx, systemd, certs via SSM. Inga fler "väntar på Johan för root"-blockeringar.
### K-010: LLM-as-judge med 4-lagers fallback
**Problem:** Keyword-matchning för svenska för trubbig. Qwen-32B som domare för svag (trodde "PASS" = EU-direktiv).
**Förbättring:** Judge-v2: Bedrock-Opus-4-6 → Sonnet-4-5 → direkt-Opus-4-8 → Qwen-235B. LLM-schema-agnostisk parser.
**Effekt:** En poliskontroll är nu aldrig svagare än det den vaktar.
### K-011: Separation of weights & facts (arkitekturprincip)
**Problem:** Företagsdetaljer inbränt i modellvikter = säkerhetsrisk, kräver omträning vid ändring.
**Förbättring:** ALETHEIA (modellvikter) = generell evidensmotor. MNEMOSYNE (CANON/RAG) = runtime-fakta.
**Effekt:** Ingen faktaläcka via vikter. Fakta ändras utan omträning. ESLM säljbar generellt.
### K-012: POS→Ledger automatisk bokföring (idempotent)
**Problem:** Restaurangförsäljning postades ej automatiskt till aamos-ledger → SIE4 var tom.
**Förbättring:** `POST /pos/ledger/post-day {fecha}` + cron 03:15 Europe/Madrid. Tracking-tabell `restaurant_ledger_postings` (UNIQUE tenant+datum). Idempotent.
**Effekt:** "Säljer jag en paella, hamnar den i böckerna?" = JA. Automatiskt, utan handpåläggning.
### K-013: Ticket-system för felrapportering (aamos-restaurant-tickets:3318)
**Problem:** Ingen strukturerad väg för restaurangtjänster att rapportera integrationsproblem.
**Förbättring:** Ny Rust/axum-tjänst med severity (low/medium/high/critical), status-flöde, källa (staff/system/customer/agent), HTML-dashboard.
**Effekt:** POS auto-skapar high-severity accounting-ticket när ledger-postning failar. Systemintelligens istället för stum kraschtystnad.
### K-014: Webhook-idempotens som förutsättning för multi-host
**Problem:** Multi-host (host-2) blockerades av att Stripe-webhooks ej var idempotenta.
**Förbättring:** Löstes som prerequisite för RES-004. Multi-host + idempotens = sann redundans.
**Effekt:** Systemet är nu multi-host-redo utan risk för ekonomisk data-korruption.
### K-015: Jurisdiktionsmedveten onboarding (ES/SE och fler)
**Problem:** Onboarding-tjänst hårdkodad för Sverige → spansk CIF och IVA-satser avvisades.
**Förbättring:** `country` (ISO-3166, default "SE") i register + DB-kolumn. ES→CIF/NIF + IVA {4,10,21}, SE→orgnr + moms {12,25}.
**Effekt:** Spansk chiringuito kan slutföra alla 7 onboarding-steg. Global skalning möjlig.
### K-016: Gravation arm64/Graviton-only för EKS (deterministisk flotta)
**Problem:** Preferred (80/20 arm64/x86-fallback) lämnar en variabel som kan överraska i prod.
**Förbättring:** Required arm64-only (nodeSelector + requiredDuringScheduling). Alla images: `--platform linux/arm64`.
**Effekt:** Homogen flotta, reproducerbart beteende, ~20% billigare. Inga edge-cases från mixed architectures.
### K-017: Django E2E-simuleringen (986 orders, €146.5k, 24/24 OK)
**Problem:** Restaurang-stacken hade 6 oupptäckta integrationsbuggar (VAT overflow, analytics-paths, decimal-parsing, etc.).
**Förbättring:** Fullständig månads-driftsimulering med 986 orders, 15 tjänster, ~130 endpoints, 14 verifieringsfaser.
**Effekt:** Alla 6 buggar hittades och fixades. SIE4-kedjeavstämning POS→Modelo303→Ledger→SIE4 perfekt.
---
## AVSNITT 3: TEKNISKA LÄRDOMAR
### TL-001: Verifiera ALLTID den körande filen, inte filen på disk
**Källa:** Produktionschat-fix (2026-06-06)
> Körande `amos-core` = `services/amos-core/server.mjs`. `scripts/server.mjs` KÖRS INTE.
> Hade nära håll på att fixa fel fil. Kontrollera alltid med `ps aux` eller `systemctl status`.
### TL-002: Stubs som svarar ok:true döljer döda subsystem
**Källa:** LandveX-incidenten + 432 stubs-audit (2026-06-06)
> Instrumentering ska visa sanningen, inte dölja den. En stub som svarar `ok:true` på tom respons är
> aktivt skadlig det ger en falsk bild av systemhälsan.
### TL-003: ESM import-ordning är deterministisk och kan bita
**Källa:** Stripe env-preload.mjs fix (2026-06-05)
> I ES modules körs importerade moduler vid import-tid, inte vid runtime. Variabler som läses tidigt
> (t.ex. env-variabler) måste finnas INNAN importen. Lösning: preload-modul som allra första import.
### TL-004: AMI-kloning kopierar statisk konfiguration inklusive resolver
**Källa:** host-2 DNS-incidenten (2026-06-05)
> AMI-snapshot fryser in all konfiguration inklusive `/etc/resolv.conf`. Om produktionsmiljön beror
> på ett sidoverktyg (Tailscale) som inte finns på alla hostar, sprids beroendet vid kloning.
> Lösning: user-data-script som skriver DNS-konfiguration vid boot.
### TL-005: `pgrep -fc chrome` är första diagnostiksteg vid amos-core-strul
**Källa:** OOM-incidenten (2026-06-05)
> Kolla antalet Chromium-instanser och social-account-jobs.json status-counts INNAN restart.
> Restart utan job-avbrottning förvärrar storm-beteende exponentiellt.
### TL-006: LLM-as-judge måste vara starkare än det den poliskontrollerar
**Källa:** ESLM red-team, judge-evolution (2026-06-06)
> Qwen-32B som domare klassade "PASS" som ett EU-direktiv och godkände felaktiga svar.
> En poliskontroll som är svagare än systemet den granskar ger falsk säkerhet.
> Regel: judge-modellen ska ALLTID vara starkare än production-modellen.
### TL-007: Keyword-matchning för svenska är för trubbig som red-team
**Källa:** ESLM red-team v1 vs v2 (2026-06-06)
> Keyword-matchning fångade inte subtila felaktigheter i svenska svar. Ersattes av LLM-as-judge (v2).
> Lärdom: för komplexa domäner krävs semantisk bedömning, inte mönstermatchning.
### TL-008: `gpt-5.5-pro` kräver `/v1/responses`, ej `/chat/completions`
**Källa:** Infra-fakta 2026-06-05
> OpenAI:s nya API-endpoint är inte bakåtkompatibel. Mycket långsam (>20 min öppna promptar).
> Undvik för tidskänsliga körningar.
### TL-009: sqlx compile-time-makron (`query!`) kräver live DATABASE_URL vid build-tid
**Källa:** EKS-migration compliance-tjänst (2026-06-07)
> 14/15 Rust-tjänster byggde direkt. Compliance: enda med `query!`-makron → krasch utan DATABASE_URL.
> Lösning: `--build-arg DATABASE_URL` vid Docker build. Alternativt: använd `query()` (runtime) istället.
### TL-010: ResourceQuota blockerar pod-skapande tyst (FailedCreate-events)
**Källa:** Kafka-degraderingen (2026-06-07)
> kafka-1 fick FailedCreate ×721 utan larm. ResourceQuota stoppade init-containern pga saknade resource limits.
> Lärdom: Resource limits ska finnas på ALLA init-containers. Övervaka FailedCreate-events.
### TL-011: RDS SSL-konfiguration krävs i Node.js-connections mot AWS RDS
**Källa:** tool-registry SSL-fix (2026-06-05)
> `new Pool({connectionString: AMOS_DB_URL})` utan SSL-config → RDS avvisade med "no pg_hba.conf entry".
> Lösning: `ssl: {rejectUnauthorized: false}` i Pool-konfiguration.
### TL-012: Providermodellnamn förändras håll dem uppdaterade
**Källa:** Gemini 2.0→2.5 fix (2026-06-05)
> Gamla modellnamn (Gemini 2.0, gammal Haiku) kraschade tyst. Orsakade dold instabilitet i orkestrering.
> Lärdom: API-modellnamn är ej stabila håll en provider-modell-förteckning uppdaterad.
---
## AVSNITT 4: PROCESSLÄRDOMAR
### PL-001: Parallellisering med tickets och subagenter är kraftfullt
**Källa:** 2026-06-06 parallellbygge (14 tickets, 4 epics, 8 subagenter)
> 90/100 tickets lösta på en session. Erikmönstret: "gör tickets, starta agenter." Fungerar för
> parallella epics som inte delar state. Kräver tydlig tickets-struktur och agent-scope.
### PL-002: Red-team FÖRE promotion är inte valfritt
**Källa:** ESLM-processen (2026-06-06)
> ALETHEIA-baslinjen: 33% passerade, 5 kritiska brister. Utan red-team hade modellen gått live med
> LandveX=bostad och hallucinerande org-nr. Red-team är minimikravet, inte ett bonus-steg.
### PL-003: Ekonomifunktionen måste ha proaktiv förvarning
**Källa:** xAI/Grok-haveriet (2026-06-04)
> Reaktiv hantering (Erik ringer Winston när Grok är tomt) är oacceptabelt. Systemet måste larma
> INNAN kontot är tomt. Auto-topup + buffert + 5-min kreditkoll är miniminivå.
### PL-004: Kör simuleringen INNAN du berättar för kunden att det är redo
**Källa:** Restaurang-plattformens 6-buggars-fynd (2026-06-07)
> Erik trodde restaurang-stacken var "100% redo för onboarding". E2E-test avslöjade BLOCKER (spansk CIF).
> Lärdom: "100% redo" valideras av systemet, inte av en persons uppskattning. Kör alltid simulering.
### PL-005: Behörighetshierarkier ska tydliggöras i agentmailboxen
**Källa:** Beroende av Johan för nginx (2026-06-04/05)
> Bernt (bernt-user) kan ej skriva nginx-filer (root/ec2-user). Blockade i veckor tills SSM-mönstret
> upptäcktes. Lärdom: dokumentera åtkomstgränser och eskaleringsvägar tydligt från start.
### PL-006: Kanoniska namn ska låsas tidigt, inte sent
**Källa:** Hermes→Hephaistos-omdöpning (2026-06-07)
> Hermes behövde döpas om (76 filer) pga namnkollision med externa bibliotek i träningsdata.
> Lärdom: namnkonflikter med populära bibliotek är dyrare att fixa sent. Välj ovanliga egennamn.
---
## AVSNITT 5: ARKITEKTURLÄRDOMAR
### AL-001: Separation of concerns gäller även AI-modeller
**Källa:** ESLM-arkitektur, SD-003 (2026-06-06)
> Modellvikter (ALETHEIA) och faktabas (MNEMOSYNE) är separata ansvarsområden, precis som
> kod och konfiguration. En modell som bär konfiguration (företagsfakta) är svår att uppdatera.
### AL-002: Event-backbone (Kafka) ska väljas och övervaka från dag 1
**Källa:** Kafka-degraderingen 8 dagar (2026-06-07)
> Tre parallella event-mekanismer (Kafka, aamos-event-bus, NATS/Redis) skapade oklarheter.
> Kafka var productionstanken men 2/3 brokers utan larm i 8 dagar. Välj en backbone, övervaka den.
### AL-003: Gitops + EKS + ExternalSecrets är rätt mönster (Siemens-standard)
**Källa:** EKS-migration referensmönster (2026-06-07)
> ArgoCD + external-secrets + ClusterSecretStore + AWS SSM = reproducerbar, auditbar deploy.
> Varje workload: ExternalSecret → Deployment → Service → Kong-route. Mönstret verifierades end-to-end.
### AL-004: Single point of truth gäller all systemkunskap
**Källa:** LandveX-incidenten (2026-06-06)
> 39 competing truth-filer → inkonsistens. AAMOS_CANON.md som enda E4-fil löste grundproblemet.
> Samma princip gäller all systemkunskap: en CANON, alla vet var de hittar sanningen.
### AL-005: Health-check-djup avgör om redundansen fungerar på riktigt
**Källa:** host-2 DNS-incidenten (2026-06-05)
> `/health` (liveness) = process up, men ej nödvändigtvis fungerande. `/health/ready` (readiness) med
> faktisk DB-round-trip är minimikravet för ALB-integrering. Ytlig health = falsk trygghet.
### AL-006: Multi-AZ är grundkrav, inte lyx
**Källa:** RES-001/003 (2026-06-05)
> Single-AZ RDS: RTO = timmar. Multi-AZ: RTO 60120s. Diff = $700/mån. Erik: "Vi har inte alternativ."
> Lärdom: bygg multi-AZ från start. Eftermontage är dyrare (maintenance window, DNS-propagation).
### AL-007: Idempotens är förutsättning för horisontell skalning
**Källa:** Stripe-webhook-idempotens som Fas-2-prerequisite (2026-06-05)
> Kan inte lägga till fler hostar utan idempotenta webhooks. Idempotens är inte ett nice-to-have
> det är det som gör horisontell skalning säker.
---
## AVSNITT 6: ERKÄNDANDEN
### Vad gick riktigt bra?
1. **Parallellisering med subagenter** 90/100 tickets på en session bevisar att multi-agent-koordination fungerar.
2. **Deep health-check räddade produktionen** host-2 med trasig DNS-resolution fick aldrig trafik tack vare `/health/ready`.
3. **Red-team-grinden fångade kritiska brister** utan red-team hade LandveX=bostad gått live.
4. **SSM-mönstret löste root-beroendet** månaders blockering av nginx-filer löst på en timme.
5. **EKS-migrationen gick smidigt** 17 tjänster, 34 pods, alla på Graviton/arm64, alla friska.
6. **DDP-träningen fungerade** från ~8h på A10G till ~1h på 8x A100. Ny hastighetstandard.
7. **Restaurang E2E-simulering** hittade 6 riktiga integrationsbuggar och kvantifierade dem till öret.
### Vad var svårast?
1. **Leon/Vincento-purgen** kräver precision (behåll andra Leons, radera bara rätt entiteter). 3 agenter parallellt krävdes.
2. **Kafka-degraderingen** 8 dagar utan larm är ett allvarligt observability-gap. Fixades men borde ha fångats dag 1.
3. **Judge-modell-valet** det tog tre iterationer (keyword → Qwen-32B → Opus-direkt) för att hitta rätt domar-nivå.
4. **Providermodell-avvecklingen** gamla modellnamn kraschade tyst. Svårt att spåra utan centraliserad provider-förteckning.
---
*Volym 6 av 7 | AMOS Workcamp 2026 | Klassifikation: INTERN KONFIDENTIELL*
*Nästa: VOL7-AMOS-Operating-System.md*