# portfolio-optimiser ## Kontekst Generisk, åpent Python-rammeverk på **Microsoft Agent Framework (MAF)** som finner kostnadsbesparelser INNI hvert prosjekt i en portefølje av uavhengige prosjekter. Multi-agent samarbeid genererer kandidat-tiltak; en obligatorisk deterministisk validator avgjør verdiene; fageksperter vurderer via HITL, og systemet lærer av dommene. Publiseres på Forgejo for alle som har MAF. Bakgrunn og beslutninger: [research](docs/research/2026-06-23-prior-art-platform.md) (§15 implementeringsregister), [plan](docs/plan/2026-06-23-incremental-plan.md). Løpende state: `STATE.md` (local-only). ## Stack Python ≥3.10. MAF (`agent-framework-core` 1.9.0). Pakkehåndtering: `uv`. To backend-profiler: Azure/Foundry (full) + lokal (fallback). ## Konvensjoner - Type hints overalt (`mypy` der mulig). Pydantic for validering/IR. - `ruff` for lint+format. `pytest` for test. - Modell-valg som konfig (modell-map rolle→Foundry-deployment), ikke spredt i kode. - Metode kodifiseres som **Agent Skill** (`agentskills.io`: `SKILL.md` + `scripts/` + `references/`). - Datatilgang via **MCP**-servere; data-source-konfig JSON-Schema-validert, fail-fast. ## Kommandoer - Sync: `uv sync` - Test: `uv run pytest` - Lint: `uv run ruff check .` + `uv run ruff format .` - Type: `uv run mypy src` ## Arbeidsflyt (invarianter) - **Rent teknisk rammeverk:** deployer eier DPIA/ROS/behandlingsformål. Bygg IKKE compliance-funksjoner — kun tekniske forutsetninger (lokal-only, provenance, ingen stille egress) + disclaimer. - **90%-prinsipp:** bygg den generiske kjernen + tydelige extension points; jakt IKKE de siste 10 %. - **Deterministisk validator er obligatorisk og blokkerende** — aldri valgfri plugin. - **Framework-nøytral kontekst-søm:** OKF-bundle-navigasjon (`okf.py`) og den delte `shared/`-kjernen er ren stdlib — null `agent_framework`/`mcp`-import, så samme bundles konsumeres uendret av begge stacker (D7-portabel). Håndhevet av `tests/test_okf.py::test_okf_is_maf_free`; importér aldri MAF inn i kontekst-laget. - **OKF-navigert bundle-kontekst (ikke stuffing):** på bundle-stien bygges agent-lese-konteksten ved å NAVIGERE bundelen (`okf.bundle_context`: index + frontmatter + cross-links, progressiv disclosure) — aldri keyword-chunk-stuffing (målbilde §2/§4). `type: verdict`-laget ekskluderes fra denne konteksten: tidligere dommer når hypotese-prompten KUN via den gatede ExpeL-folden. Load-bearing: `test_bundle_context_excludes_verdict_layer` + empty-store-kontrollen i `test_step1_expel_loadbearing.py` (realiseringssignalet lekker aldri inn via kontekst). - **Stoppkriterier + budsjett-tak påkrevd ved oppstart** (fail-fast, aldri ubegrenset loop). - **Group Chat maker-checker** som debatt-default (IKKE Magentic, som er eksperimentell). - **To falsifiserere, samme kandidat (Steg 3/4, målbilde §2/§6):** den deterministiske validatoren gater *tallene* (blokkerende), checkeren gater *resonnementet*. Checkeren avslutter turen med en `VERDICT: APPROVE` / `VERDICT: REJECT — `-linje; et eksplisitt avslag blokkerer et ellers validert forslag (`run_project` overflater begge debatt-deltakere via `output_from=agents` og overstyrer utfallet til en checker-kilde-`Rejection`). Gaten er opt-in-reject (fail-open ved manglende markør), og `provenance.validator_decision` forblir ærlig — den speiler KUN validatoren, aldri checkeren (de to falsifisererne blandes aldri). Load-bearing: `tests/test_checker_gate_loadbearing.py` blir rød ved BEGGE detach-punkt (revert `output_from`, eller fjern override). Checkeren «må faktisk gate, ELLER vi slutter å kalle det maker-checker». - **Kostnadsdisiplin:** utvikle primært på lokal profil (gratis); Foundry/Azure (privat tenant finnes) kun til målrettet, minimal verifisering; billigste modeller + små syntetiske data + harde token-tak. Ingen tunge test-kjøringer. - **STATE.md er local-only** (gitignored). Voyage session-state er efemert; STATE.md er kanonisk kontinuitet. - Prosess: Voyage-plugin (`/trekbrief → /trekplan → /trekexecute → /trekreview`) per større fase. ## Communication patterns When linking to local files in responses, use named markdown links — `[Human-friendly name](file:///absolute/path)`, never bare `file://` URLs or autolinks ``, always absolute paths (never `~/` or relative), one bullet per file when there are several. (Bare `file://` URLs render only the first as clickable across multiple lines; named links stay independently clickable.)