Generic, open framework on Microsoft Agent Framework (MAF): multi-agent cost-saving proposals gated by a mandatory deterministic validator, with HITL learning.
Find a file
Kjell Tore Guttormsen 4ec778c855 feat(fase3): make the maker-checker checker actually gate the reasoning
Closes gap #3 (maalbilde §5): the GroupChat checker critiqued into the void —
output_from=[proposer] surfaced only the proposer, so an explicit checker
rejection was ignored and the deterministic validator was the sole gate. Two
falsifiers now act on the same candidate: the validator gates the NUMBERS
(blocking, unchanged), the checker gates the REASONING (maalbilde §2/§6).

- workflow.py: output_from=agents surfaces both participants; the checker
  instruction ends with a VERDICT: APPROVE / VERDICT: REJECT - <reason> line.
- run.py: _authored_texts() reads author_name through out.messages (MAF 1.9.0
  puts it there, not on the AgentResponse); _debate_text() now selects the
  PROPOSER-authored output (fixes a latent texts[-1] regression that would feed
  the checker's verdict to generation at even round counts); _checker_verdict()
  parses the gate decision. An explicit REJECT overrides an otherwise-validated
  outcome to a checker-sourced Rejection. Opt-in-reject (fail-open on a missing
  marker). RunResult gains checker_verdict; provenance.validator_decision is
  stamped from the validator outcome BEFORE the override, so it never conflates
  the two falsifiers (provenance honesty).

Load-bearing (maalbilde §7): tests/test_checker_gate_loadbearing.py is a PAIR —
an explicit checker REJECT on a VALIDATOR-VALID proposal yields a Rejection whose
reason carries the checker's reason while validator_decision stays "validated";
the causality control (checker APPROVE, same proposer) validates normally. Proven
RED on BOTH detach points (revert output_from, or drop the override).

Suite 134->136 passed, 4 skipped; mypy + ruff check clean. Pre-existing
ruff-format drift (backends/budget/verdicts/test_contracts) left untouched for a
surgical diff.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MHR8iKxJRxDiDfNw8HZmWE
2026-06-30 07:24:30 +02:00
.claude/projects docs(fase3): remediation plan for the 2 /trekreview MAJOR findings (F1+F2) 2026-06-26 15:07:48 +02:00
docs docs(maalbilde): konsolidert agentisk-loop baseline + OKF-kontekstarkitektur 2026-06-26 20:56:14 +02:00
shared docs(shared): conform bygg-energi-mikro to the shared OKF spec (okf_version 0.1) 2026-06-29 14:50:04 +02:00
spikes fix(fase1): spike B fan-out measures real conversation bleed, not a counter 2026-06-24 11:09:55 +02:00
src/portfolio_optimiser feat(fase3): make the maker-checker checker actually gate the reasoning 2026-06-30 07:24:30 +02:00
tests feat(fase3): make the maker-checker checker actually gate the reasoning 2026-06-30 07:24:30 +02:00
.gitignore docs(fase2): /trekbrief — gated MVP vertical-slice brief (6/6) [skip-docs] 2026-06-24 11:56:57 +02:00
.python-version feat: initial scaffold (Python framework on Microsoft Agent Framework) 2026-06-23 22:01:22 +02:00
CHANGELOG.md feat: initial scaffold (Python framework on Microsoft Agent Framework) 2026-06-23 22:01:22 +02:00
CLAUDE.md feat(fase3): make the maker-checker checker actually gate the reasoning 2026-06-30 07:24:30 +02:00
env.template docs(fase2): add env.template documenting both profiles + no-egress notes 2026-06-26 00:43:26 +02:00
pyproject.toml docs(fase2): record PEP 735 dependency-groups as intentional Step 1 deviation 2026-06-26 00:43:46 +02:00
README.md feat(fase3): make the maker-checker checker actually gate the reasoning 2026-06-30 07:24:30 +02:00
uv.lock build(fase2): promote orchestrations + pulp to core deps 2026-06-24 13:22:04 +02:00

portfolio-optimiser

Generic, open framework on Microsoft Agent Framework (MAF) for finding cost-savings / efficiency proposals within each project of a portfolio of independent projects. Multiple agents collaborate to generate candidate proposals; a mandatory deterministic validator (solver + Monte Carlo) decides the numbers; domain experts review via human-in-the-loop, and the system learns from their verdicts.

Status: Early development. The deterministic backbone is solid; the agentic learning loop is being wired one load-bearing seam at a time — Step 1 (OKF-navigated context → hypothesis) is wired, with the verdict layer kept out of the read-context (see below). Not yet end-to-end usable.

Disclaimer — technical framework only. This project is a technical framework. Organizations that deploy it are themselves responsible for ensuring a valid processing purpose and for any required assessments (DPIA, risk/ROS, security reviews, etc.). The framework ships technical affordances (local-only mode, provenance/audit logging, no silent data egress) to enable compliant use, but makes no compliance guarantees.

Design philosophy

The result will never fit any single customer 100%. The goal is a ~90% genuinely generic core plus clear extension points, so competent people can configure the last mile per customer. We deliberately do not chase the final 10%.

Agentic loop — wiring status

The mandatory deterministic backbone (validator + budget meter + provenance) is solid and load-bearing. The agentic learning loop (see the target picture §11) is wired one seam at a time:

  • Step 1 — OKF context → hypothesis (wired). run_project(..., bundle_dir=...) wires the first agentic seam in two halves:
    • Context by navigation, not stuffing. The agent read-context is built by navigating the project's OKF bundle (index.md + frontmatter + cross-links, progressive disclosure) — never keyword chunk-stuffing (target picture §2/§4).
    • Verdict layer gated out of context. The type: verdict layer is excluded from that context; the candidate's prior expert verdicts reach the hypothesis prompt only through the gated ExpeL fold (folded in before generation), so a prior verdict provably — and exclusively — influences the next hypothesis.
    • Two load-bearing tests fail when the seam is detached: the realization signal must reach the prompt via the fold (tests/test_step1_expel_loadbearing.py), and must never leak via context (tests/test_okf.py::test_bundle_context_excludes_verdict_layer).
  • Steps 3/4 — checker gates the reasoning (wired). Two falsifiers now act on the same candidate: the deterministic validator gates the numbers (blocking, as before), and the maker-checker's checker gates the reasoning (target picture §2/§6). The checker ends its turn with a VERDICT: APPROVE / VERDICT: REJECT — <reason> line; an explicit reject blocks an otherwise-validated proposal (run_project surfaces both debate participants via output_from=agents and overrides the outcome to a checker-sourced Rejection). The gate is opt-in-reject (fail-open on a missing marker), and provenance.validator_decision stays honest — it reflects the validator only, never the checker. Load-bearing: tests/test_checker_gate_loadbearing.py goes red on either detach (revert output_from, or drop the override).
  • Steps 58 (informed refinement, async file feedback, gated wiki promotion) — not yet wired.

Docs

Stack

Python ≥3.10 · MAF (agent-framework) · uv. Backend profiles: Azure/Foundry (full) + local (fallback).

Develop

uv sync
uv run pytest
uv run ruff check .