# F16 — MAF-pinnen løftet 1.16.0 → 1.18.0, og tre 1.17/1.18-funksjoner målt mot U-radene > **Ordre:** `20260912T144902Z-9152424098-from-.claude` (operatørbeslutning 12.09: ja til F16 før > stresstesten; veivalg **D = d1**). **NOK 0 — ingen betalt kjøring, ingen modellkall.** > **Grunnlag:** [F15](2026-09-02-f15-maf-pinnen.md) (prosedyren denne økten gjentar) og > [P12 — MAF-gjelden](2026-09-11-p12-maf-gjeld.md) (rad-for-rad-tellingen den bygger på). > Hvert tall under kommer fra en kommando kjørt i denne økten. **Konformans er gulvet, aldri > beviset.** ## 0. Resultat | | | |---|---| | `agent-framework-core` | **1.16.0 → 1.18.0** (gulv `>=1.16.0,<2` → `>=1.18.0,<2`) | | `agent-framework-foundry` | **1.8.2 → 1.13.0** (gulv `>=1.8.2` → `>=1.13.0`) | | `agent-framework-openai` | **1.8.2 → 1.14.3** (gulv `>=1.8.2` → `>=1.14.3`) | | `agent-framework-orchestrations` | **1.1.1 → 1.1.1 — UENDRET**, fordi 1.1.1 fortsatt er siste utgivelse (gulv `>=1.1.1` urørt) | | Nye/endrede transitive | **ingen nye pakker** — `uv lock` rapporterte kun de tre oppdateringene, 84 pakker før og etter | | Vakten FØR bumpen | **2 failed, 2 passed** (Iron Law — rød først) | | Vakten ETTER bumpen | **4 passed** | | Private/ugaranterte former | **16 former · 19 sjekker mekanisk · 0 endret** (+ form 17 re-målt ved KJØRING: uendret) — se § 2 | | Testsuite | **1577 passed / 5 skipped** — identisk med basislinjen målt på DENNE HEAD før bumpen; 0 tester tapt, 0 lagt til | | `tests/test_async_plan_review_loadbearing.py` | **19 passed** (park → spørsmålsfil → svarfil → resume, egen interpreter) | | Golden `demo-transcript.stdout` | **BYTE-UENDRET**, `ea8c534773acdbe41ae68f2c55724d69aaf8be4f` | | Golden `demo-transcript.stderr` | **BYTE-UENDRET**, `ede3e2f685ce6a14ad9888e9de421d1a66f6c611` — fortsatt TO linjer | | `uv run ruff check .` | **All checks passed!** (ekskl. `scratchpad/`, se § 6) | | `uv run ruff format --check .` | **211 files already formatted** (ekskl. `scratchpad/`) | | `uv run mypy src` | **Success: no issues found in 37 source files** | | De tre funksjonene | **MÅLT, IKKE BYGGET** — § 4 (a)/(b)/(c)/(d) | **`shasum -a 1` over fil-INNHOLDET, aldri `git hash-object`.** De to er ulike av konstruksjon (git hasher over `blob \0` + innhold); se CLAUDE.mds egen rad om dette. ## 1. PyPI-målingen, som avgjorde hvilke gulv som KUNNE flyttes Målt med PyPIs JSON-API (`curl`), `info.version` + `info.requires_dist`, og for de pinnede versjonene `…/pypi///json`: | pakke | låst før | siste på PyPI | publisert | egne `agent-framework`-krav (siste) | krav i den PINNEDE 1.8.2 | |---|---|---|---|---|---| | `agent-framework-core` | 1.16.0 | **1.18.0** | 2026-09-10T09:28:54Z | — | — | | `agent-framework-foundry` | 1.8.2 | **1.13.0** | 2026-09-10T09:28:59Z | `core<2,>=1.17.0`, `openai<2,>=1.14.2` | `core<2,>=1.9.0`, `openai<2,>=1.8.2` | | `agent-framework-openai` | 1.8.2 | **1.14.3** | 2026-09-10T09:29:06Z | `core<2,>=1.17.0` | `core<2,>=1.9.0` | | `agent-framework-orchestrations` | 1.1.1 | **1.1.1** | 2026-08-21T23:22:41Z | `core<2,>=1.15.0` | (samme) | Core 1.17.0 ble publisert 2026-09-03T09:53:33Z. PMs tall er reprodusert **eksakt** på alle fire pakker; ingen avvik. **TO av ordrens egne premisser ble FELT av målingen, og målingen vinner.** **(i) `orchestrations` kan ikke løftes — det finnes ingenting å løfte det til.** 1.1.1 (2026-08-21) er fortsatt hodet på PyPI, og kravet `core<2,>=1.15.0` er tilfredsstilt av 1.18.0. F15s `pyproject`-kommentar sa «de to gulvene løftes SAMMEN (F15) — det finnes ingen delvis bump». Det var sant om F15s bump. Etter F16 er det **målt svakere**: core kan løftes uten at orchestrations kan, og kommentaren sier nå det. Konsekvensen er strukturell for § 2: åtte av de nitten sjekkene bor i `agent_framework_orchestrations`, altså i en pakke som **ikke flyttet**, og de kan derfor ikke avvike over denne bumpen. Det står som en egenskap ved nevneren, ikke som en styrke ved proben. **(ii) `foundry` og `openai` ble IKKE tvunget opp.** Ordren leste koblingen av de SISTE utgivelsene (begge krever `core>=1.17.0`), men den PINNEDE 1.8.2 krever bare `core<2,>=1.9.0` — målt. Resolveren beholdt derfor 1.8.2 mot core 1.18.0 og løste rent. **Konfigurasjon A** (core 1.18.0 + foundry/openai 1.8.2) ble faktisk kjørt, og var grønn på vakten (4), de 19 async-plan-review-testene og golden-transkriptet (4) — 27 tester pluss en ren `backends`-import. Det står her i stedet for å bli skjult. **De ble likevel løftet, av en annen og målt grunn:** to av 1.17/1.18s BREAKING-punkter navngir **core OG foundry i SAMME punkt** (`#7918` sequence-only middleware-inputer, `#8127` `SecretString`). Et 1.9.0-æra foundry mot en 1.18.0 core er da halvparten av en koordinert endring — nøyaktig «importerer fortsatt, men semantikken har flyttet i stillhet»-klassen F15 § 4 målte og som er hele grunnen til at denne pinnen er en tripwire. Gulvene er satt til det `uv sync` **faktisk installerte**, målt etter synken med `importlib.metadata.version`, aldri gjettet før: ``` core 1.18.0 · foundry 1.13.0 · openai 1.14.3 · orchestrations 1.1.1 ``` (`agent_framework.__version__` er en `0.0.0`-plassholder og er ikke brukt noe sted — guardens egen docstring sier hvorfor.) ## 2. Nevner-disiplin — fire tall, aldri «19/19» **16 distinkte private/ugaranterte MAF-former leaner po på · 19 sjekker mekanisk av proben · 0 av de 19 endret seg · form 17 (checkpoint-antallet per park) er IKKE i proben og ble re-målt ved KJØRING, også uendret.** Formen er F15 § 2s, og den er gjentatt med vilje. `pyproject`-kommentaren sa tidligere «de 19 private formene»; **19 er SJEKKE-tallet, ikke FORM-tallet**, og en setning som sier «19/19» uten å navngi nevneren gjentar nøyaktig feilen F15 § 2 rettet. Inventaret er F15s, derivert fra repoets egne siteringer (`grep -rnoE "_[a-z_]+\.py:[0-9-]+" src/` pluss hver MAF-form en søm overstyrer eller konstruerer). Instrumentet er efemert og bor i privat scratch, aldri i repoet; det kjørte mot **BEGGE** versjoner (core-wheelene 1.16.0 og 1.18.0 lastet ned og pakket ut side om side), så «før»-kolonnen er **re-kjørt, ikke sitert**. | Form | eier | 1.16.0 | 1.18.0 | |---|---|---|---| | P1 `BaseChatClient._inner_get_response` kw-only (messages/stream/options) | core | OK | OK | | P2 `BaseChatClient._build_response_stream` | core | OK | OK | | P3 `MagenticPlanReviewRequest` (allowlist-streng) | orch 1.1.1 | OK | OK | | P4 `MagenticPlanReviewResponse` (allowlist-streng) | orch 1.1.1 | OK | OK | | P5 strengt stall-sjekk `stall_count > …max_stall_count` | orch 1.1.1 | OK | OK | | P6 reset-sjekk `reset_count >= …max_reset_count` | orch 1.1.1 | OK | OK | | P7 `next_speaker not in …participants`-fallback | orch 1.1.1 | OK | OK | | P8 nøyaktig ÉN `ctx.request_info` i `_magentic.py` | orch 1.1.1 | OK (1) | OK (1) | | P9 `is_request_satisfied` på ledgeren | orch 1.1.1 | OK (8) | OK (8) | | P10 `FileCheckpointStorage.list_checkpoints` svelger blokkert type → `logger.warning` | core | OK | OK | | P11 `get_latest` velger på timestamp · P11b `allowed_checkpoint_types=` | core | OK | OK | | P12 runner nekter restore ved graf-signatur-avvik | core | OK (2 steder) | OK (2 steder) | | P13 `reached max_rounds`-meldingen i group-chat-orkestratoren | orch 1.1.1 | OK | OK | | P14 `extend_instructions` to-arg GA-signatur (`_sessions.py`) | core | OK | OK | | P15 console-exportere gatet på flagget · P15b `ENABLE_INSTRUMENTATION` | core | OK | OK | | P16 `ExperimentalWarning` emitteres ved FØRSTE BRUK (`_add_runtime_warning`) | core | OK | OK | | *(støtte)* `WorkflowCheckpoint.pending_request_info_events` deklarert — feltet F15s fiks flyttet vakten over på | core | OK | OK | | **Form 17 — checkpoint-filer per park, målt ved KJØRING** | core | 2 (F15) | **2, og nøyaktig ÉN bærer forespørselen** | **P12 fortjener en presisering:** po siterer `_runner.py:275-279` (`explore.py:1374` og `:1996`). **Linjenumrene har flyttet seg fire linjer** i 1.18.0 — sitatet er ikke lenger presist — men FORMEN proben sjekker (`self._graph_signature_hash != checkpoint.graph_signature_hash`) står på to steder i begge versjoner. Det er grunnen til at proben sjekker formen og ikke linja; siteringene i `explore.py` er BEVISST ikke rettet, fordi de er kommentarer om hvor premisset ble lest, og en oppdatering ville krevd at hver framtidig bump redigerte prosa i stedet for å måle. **Min egen probe var FEIL FØRST, og det er nevner-disiplin anvendt på instrumentet.** Første versjon rapporterte **CHANGED/MISSING i BEGGE versjoner** på fem sjekker (P5, P6, P10, P11, P14). Ingen av dem hadde endret seg: spørringene mine var gale. - **P10/P11:** regexen sliced `CheckpointStorage`-PROTOKOLLEN, hvis kropp er en bar `...`. Formen bor i `FileCheckpointStorage` — klassen po faktisk konstruerer. - **P14:** «to-arg» i F15 betyr to argumenter BESIDES `self`. Min versjon telte `self` og fikk 3. - **P5/P6:** komparasjonen leser `self._magentic_context.stall_count > self._manager.max_stall_count`; regexen min krevde at de to navnene var naboer. Et «fant ingenting» fra feil spørring er ikke et faktum (Verifiseringsloven ansikt 4). Hadde kolonnene blitt lest som funn, ville F16 rapportert fem falske endringer; hadde bare «før»-kolonnen blitt kjørt, ville de vært usynlige. **Å kjøre proben mot BEGGE versjoner er dét som gjorde instrumentfeilen synlig** — fem rader like i begge kolonner er et instrument som ikke måler, ikke en form som forsvant. **Kjent-positiv er OBLIGATORISK, og denne bumpen har en sterk en.** Proben må kunne oppdage en endring, ellers måler den ingenting: | kontroll | 1.16.0 | 1.18.0 | diskriminerer? | |---|---|---|---| | **KP1** `max_duration`/`stop_reason`-tokens i `_tools.py` (`#7772`, ny i 1.18.0) | **0** | **24** | **JA — 0 → 24** | | **KP2** antall `Sequence[` i `_middleware.py` (`#7918`) | 36 | 39 | ja (svakere: en telling, ikke en form) | | KP3 `_agent_hooks.py` finnes (ekstraen fjernet i 1.17.0) | present | present | nei | | KP4 `@experimental`-markører i `_skills.py` | 3 | 3 | nei | | KP5 `SkillsProvider` uten `@experimental` | no-marker | no-marker | nei | | KP6 `MiddlewareFailure` (F15s kjent-positiv) | YES | YES | **nei lenger** | | KP7 `FileSkillsSource` finnes | YES | YES | nei | **KP1 er F16s kjent-positiv.** **KP6 er F15s, og den er FORKASTET her på samme grunnlag F15 forkastet `_compaction.py`:** `MiddlewareFailure` kom i 1.15.0, altså før begge kolonnene, og teller YES i BEGGE — den diskriminerer ingenting over DENNE bumpen. En kontroll som var gyldig i forrige bump er ikke automatisk en kontroll i denne. KP3–KP5 og KP7 er stabilitets-observasjoner, ikke kontroller, og er merket som det. **Ærlighets-grensen fra F15 gjelder uendret:** proben sjekker **FORMER** — statiske egenskaper ved kilden. F15s mest konsekvensrike funn var en egenskap ved **KJØRINGEN** (hvor mange checkpoints en park skriver), og det var usynlig for enhver form-probe uansett hvor mange former den teller. **En form-probe er gulvet, aldri beviset — suiten er beviset.** Nevneren skal leses som «19 sjekker over 16 former», ikke «alt som kunne endre seg er sjekket»; ingenting her påstår at 16 er uttømmende. **Og åtte av de nitten sjekkene bor i en pakke som ikke flyttet** (§ 1 (i)), så den reelle mekaniske nevneren for core-deltaet er **11 sjekker**. ## 3. Goldenene og de fire risikoradene — målt, ikke antatt Release-notatene er hentet i denne økten via GitHubs release-API og siteres med URL og versjon: - — publisert `2026-09-03T09:49:35Z` (målt; matcher PM) - — publisert `2026-09-10T09:23:52Z` (målt; matcher PM) **ÉN AVSKRIFT AVVEK, og avviket rapporteres:** ordren tilskrev lazy-loading-punktet (`#8219`) til **core + foundry + openai**. Kilden sier **`agent-framework-foundry`, `agent-framework-foundry-hosting`, `agent-framework-openai`** — **core er IKKE på lista**. Det er ikke pedanteri: hadde `foundry`/`openai` blitt stående på 1.8.2 (konfigurasjon A, § 1 (ii)), ville endringen ordren utpekte som hovedmistenkt for golden `stderr` **ikke nådd po i det hele tatt**. Den nådde po kun fordi gulvene ble løftet. To andre småavvik, uten konsekvens: `#8127` navngir **ti** pakker (ordren sa «core+foundry+openai m.fl.»), og checkpoint-punktet er ÉTT punkt med **tre** PR-numre (`#7798`, `#7948`, `#8215`), ikke ett. ### Rad 1 — `SecretString` (1.18.0, BREAKING) > «**agent-framework-anthropic**, **agent-framework-azure-ai-search**, **agent-framework-azure-cosmos**, > **agent-framework-bedrock**, **agent-framework-copilotstudio**, **agent-framework-core**, > **agent-framework-foundry**, **agent-framework-gemini**, **agent-framework-mem0**, > **agent-framework-openai**: [BREAKING] Make `SecretString` a masked value wrapper rather than a > `str` subclass and align provider credential handling ([#8127])» **Treffer IKKE po, og det er målt.** `SecretString` = **0** treff i `src/` + `tests/`; **27** i installert core, **4** i installert foundry 1.13.0 — og alle fire foundry-treffene er i `_embedding_client.py`, på `api_key`-typingen. `FoundryChatClient.credential` er typet `AzureCredentialTypes | AzureTokenProvider | None` (`_chat_client.py:168`), altså et credential-OBJEKT fra `azure.core.credentials`. po sender nettopp et objekt (`backends.py:150`: `ManagedIdentityCredential() if _is_hosted() else AzureCliCredential()`) og aldri en api-nøkkel-streng. `import portfolio_optimiser.backends` → rc 0; witness `tests/test_hosted_backend_loadbearing.py` → **8 passed**. ### Rad 2 — lazy loading av Foundry/OpenAI (1.18.0) > «**agent-framework-foundry**, **agent-framework-foundry-hosting**, **agent-framework-openai**: > Lazily load Foundry and OpenAI integrations to avoid unnecessary import-time dependencies > ([#8219])» Dette er klassen endring som flyttet golden `stderr` i F15 (der sluttet MAF å sende `ExperimentalWarning` ved import). **Målt: den flyttet ingenting.** Demoen kjørt live etter bumpen skriver **to** linjer på stderr (blanklinje + `arbeidskopi:`), byte-for-byte det goldenen bærer gjennom den **UENDREDE** normalisereren, og `stdout` er **61 linjer** — F15s tall. ``` shasum -a 1 tests/golden/demo-transcript.stdout → ea8c534773acdbe41ae68f2c55724d69aaf8be4f (FØR og ETTER) shasum -a 1 tests/golden/demo-transcript.stderr → ede3e2f685ce6a14ad9888e9de421d1a66f6c611 (FØR og ETTER) ``` **Ingen regenerering, altså ingen beslutning å ta.** `test_normalisation_does_not_mask_a_new_warning` er grønn, og `tests/test_golden_transcript_loadbearing.py` → **4 passed**. Span 1 (`site-packages`-maskeringen) er fortsatt beholdt og fortsatt ubebodd. ### Rad 3 — checkpoint-validering ved lagring (1.18.0) > «**agent-framework-core**: Finalize abandoned functional-workflow streams, restore fan-in edge > buffers, and validate checkpoint state when saving ([#7798], [#7948], [#8215])» **Form 17 er re-målt ved KJØRING, ikke ved import**, fordi det er en egenskap ved kjøringen: en ekte CLI-park (scriptet, offline, **null modellkall**) skriver **2** checkpoint-filer, og **nøyaktig ÉN** nevner forespørselens `request_id` — identisk med F15s måling under 1.16.0. F15s fiks (`str(request.request_id) not in latest.pending_request_info_events`) hviler derfor på en egenskap som fortsatt holder, og `#8215` endret ikke antallet. ``` park rc: 0 · checkpoint-filer: 2 · request_id: bd2a03b7-… 1973dcc2-… bytes=10809 mentions_request_id=1 5f89e535-… bytes=2039 mentions_request_id=0 ``` Witness: `tests/test_async_plan_review_loadbearing.py` → **19 passed** (park → spørsmålsfil → svarfil → resume i en **fersk interpreter**). Det er den kjøringen ordren ba om. ### Rad 4 — sti-normalisering og skill-revalidering (1.18.0, BREAKING-experimental) > «**agent-framework-core**: [BREAKING - experimental] Centralize file, memory, session, and skill > path normalization ([#8123])» > «**agent-framework-core**: Revalidate discovered skill paths immediately before use ([#8151])» **Treffer IKKE po målbart.** P14 (`extend_instructions` to-arg GA-signatur i `_sessions.py`) er **uendret** (§ 2), og MAFs `FileSkillsSource` laster fortsatt po sine to skills **2 av 2** (`shared/skills/expert-reviewer`, `shared/skills/falsification-reviewer`), med `get_skills(context: SkillsSourceContext)`-signaturen **identisk** i begge versjoner. Det er premisset § 5 (d1) hviler på, og det står. ### Rad 5 og 6 — funnet i denne økten, og hvordan **Metoden:** release-notatene ble gruppert mot po sitt EGET invariant-vokabular (`grep -niE "mcp init|initialization|event.loop|concurren|checkpoint|middleware|credential|lazily|skill path"` over begge notatene), i stedet for å lese dem for hva som ser viktig ut generelt. To punkter traff navngitte po-invarianter som ingen av ordrens fire rader dekket: **(5) 1.17.0:** «**agent-framework-core**: Surface the underlying MCP initialization error when cancellation masks a connection failure ([#7704])». Treffer kø-(x)-raden i CLAUDE.md ordrett — `_unwrap_ingest_error` finnes fordi anyio pakker alt som forlater en task group i en `BaseExceptionGroup`, og «detach `initialize()`» er én av de fem mutasjonene som gater den. En oppstrøms endring i hvordan en maskert init-feil overflates kan flytte hva som når vår unwrapper. **Målt: ingen endring i utfall** — `tests/test_ingest_golden_mcp.py` + `tests/test_hosting_loadbearing.py` → **22 passed**. **(6) 1.17.0:** «**agent-framework-core**, **agent-framework-foundry**, **agent-framework-openai**: Document the same-event-loop concurrency contract for shared chat clients ([#7680])». Treffer Fase 4d-raden (NG1-guarden: hostet inngang er koroutiner på ÉN asyncio-løkke, **aldri** tråder). Dette er **dokumentasjon**, ikke atferd, og retningen er bekreftende: MAF skriver nå ned den kontrakten po sin egen rad resonnerte seg til. Ingen endring bestilt; witness som over. ## 4. Vurderingen — MÅLT, IKKE BYGGET Ingen av funksjonene under er bygget. Ingen ny middleware, ingen timeout-søm, intet vektorlager, ingen ny CLI-flate, ingen ny U-rad. U-radene siteres ORDRETT fra [§ 15.1](research/2026-06-23-prior-art-platform.md) (l. 271–289) og BUILD/GUARD-radene fra § 15.2/§ 15.3. ### (a) Tidsgrense og stoppårsak i verktøy-løkka — 1.18.0 > «**agent-framework-core**: Add a maximum-duration bound and stop-reason signal to the tool > invocation loop ([#7772](https://github.com/microsoft/agent-framework/pull/7772))» — > [python-1.18.0](https://github.com/microsoft/agent-framework/releases/tag/python-1.18.0) **ORDRENS SPØRSMÅL BÆRER ET FEIL PREMISS, og det rettes her: ingen U-rad ville flytte seg.** Det finnes ingen U-rad for en verktøy-løkke-timeout blant U1–U19. Raden dette treffer er en **BUILD**-rad: > «B4 | **Termineringskontrakt + budsjett-circuit-breakers** | Magentic-limits defaulter til `None` > (ubegrenset); ingen kost-tak by default | Krev eksplisitte verdier ved oppstart (fail-fast hvis > mangler): `max_iterations`, `max_stall`, `cost_budget_tokens`, **wall-clock-timeout**. Alle brudd > → strukturert event (aldri stille stopp).» pluss «G1 | Magentic-limits = `None` (ubegrenset) | B4: krev eksplisitte verdier, fail-fast». **wall-clock-timeout står ORDRETT i B4s skisse, og er den ENE av B4s fire som po aldri bygde.** **Hva po gjør i dag:** `Budget`/`TokenMeter` per kjøring og `PortfolioBudget`/`PortfolioMeter` over passet (`ledger.py`), håndhevet i `BudgetMiddleware` med pre-call-guard; `max_rounds` via `meter.tick_round`; brudd → `BudgetExceeded(kind, limit, observed)`, og på den hostede flaten `429` med trippelen som STRUKTUR (`hosting.py:44`, `:254`). **Ingen wall-clock-grense noe sted.** STATE forbyr eksplisitt å bygge den («**IKKE BYGG:** timeout-sømmen fra 1a», STATE.md l. 34), og **dette forbudet er URØRT.** **Hva primitiven faktisk er (målt i installert kode, ikke lest av notatet):** `max_duration` 0 treff i `src/`, **21** i installert core. Det publiserte navnet er **`max_duration_seconds`**, en nøkkel i `FunctionInvocationConfiguration` (`_tools.py:1487`), satt per klient (`client.function_invocation_configuration["max_duration_seconds"] = 30.0`). **Og «stop-reason signal» er IKKE en typet verdi en kaller får:** literalen `stop_reason` har **0** treff i installert core (`stopReason` finnes ett sted, i `_mcp.py`, en MCP-feltnavn). Mekanismen er `_apply_batch_limit_decision` (`_tools.py:3078`): ved overskridelse settes `options["tool_choice"] = "none"` og `budget_state["truncated"] = True`, pluss en `logger.info`. Altså **graceful degradation** — modellen tvinges til et tekstsvar — dokumentert som **«best-effort»**: klokka sjekkes ETTER hver batch, aldri før. **Hva den ville koste, og anbefalingen:** primitiven gjør **ikke** den håndrullede sømmen unødvendig, og det er en forskjell i KANAL, ikke i dekning. po sitt budsjettregime er typede nekter med tre felt om ÉN ledger; `max_duration_seconds` gir et logglinje-varsel og en intern dict-flagg, og **degraderer stille inn i et vellykket svar**. En kjøring som traff taket ville altså sett ut som en kjøring som konkluderte — nøyaktig det `budget_stop` er et EGET felt (aldri `stop_reason`) for å forhindre, og nøyaktig det 429-raden finnes for. B4s «alle brudd → strukturert event (aldri stille stopp)» er derfor **ikke** oppfylt av primitiven. **Anbefaling: ikke adopter den som B4s wall-clock-halvdel.** Skal en wall-clock-grense en gang bygges, er primitiven likevel verdt å bruke som et **ytre**, billig nett under vår egen typede nekt (den er gratis, den er per klient, og den stopper en løpsk verktøy-løkke vi ellers bare ser i tokenregnskapet) — men det er en egen ordre, og STATEs forbud står til operatøren flytter det. ### (b) Godkjenninger bundet til stabile funksjonskall-forekomster — 1.17.0 > «**agent-framework-ag-ui**, **agent-framework-core**, **agent-framework-devui**, > **agent-framework-openai**: Bind approvals to stable function-call occurrences while preserving > legacy approval compatibility ([#7988](https://github.com/microsoft/agent-framework/pull/7988))» — > [python-1.17.0](https://github.com/microsoft/agent-framework/releases/tag/python-1.17.0) **U-raden, ordrett:** > «U13 | HITL-gates | Tool approval (`@tool(approval_mode='always_require')` Py / > `ApprovalRequiredAIFunction` C#); `RequestPort`/`request_info()`; > `MagenticPlanReviewRequest`/`.approve()`/`.revise()` | …/workflows/human-in-the-loop | ✅ (se F2)» **Svaret er kallsted-tellingen:** | konstrukt | `src/` | `tests/` | installert core 1.18.0 | |---|---|---|---| | `approval_mode` | **0** | **0** | 102 | | `FunctionApprovalRequest` | **0** | **0** | — | **U13 flytter seg IKKE.** po bruker U13 gjennom `MagenticPlanReviewRequest`/`.approve()`/`.revise()` (F4s synkrone `--plan-review` og U12s asynkrone `--checkpoint-dir`/`--resume`, gatet av de 19 async-testene) og gjennom sin EGEN forslagsgate (`--proposal-review`, MAJOR-2). **Tool-approval-stien er den halvdelen po aldri tok**, og det er en eksplisitt beslutning eldre enn denne bumpen: > «G4 | `ApprovalRequiredAIFunction` er **kooperativ markør**, ikke hard enforcement | Håndhev > godkjenning i invoker-koden, ikke stol på markøren» `#7988` gjør nettopp den markør-stien mer robust — en approval bindes nå til en stabil funksjonskall-forekomst i stedet for å kunne feilmatches over avbrudd og resume. **Det er en forbedring av en sti po ikke bruker.** P12 hadde U13 som «delvis» og forblir «delvis» — statusen er uendret, og det er premisset (`approval_mode` = 0 i `src`) som er re-målt, ikke statusen som er revurdert. **Anbefaling: ingen endring.** G4s resonnement (håndhev i vår egen kode) er uberørt av at markøren er blitt stabilere; det som ville flyttet U13 er en beslutning om å gate `emit_savings_proposal` på MAFs tool-approval i stedet for på vår egen `--proposal-review`, og det er en misjonsbeslutning, ikke en pinne-konsekvens. ### (c) BREAKING: sequence-only middleware-inputer — 1.17.0 — MÅLT, IKKE VURDERT > «**agent-framework-core**, **agent-framework-foundry**: [BREAKING] Restore sequence-only agent > middleware inputs and remove the experimental `agent-hooks` core extra > ([#7918](https://github.com/microsoft/agent-framework/pull/7918))» — > [python-1.17.0](https://github.com/microsoft/agent-framework/releases/tag/python-1.17.0) **U-raden, ordrett:** > «U8 | Intercept av tool-calls (blokkerende validator) | Middleware-pipeline `.Use()`; > `FunctionMiddleware` (`InvokingAsync`/`InvokedAsync`) | …/agents/agent-pipeline | ✅» **PMs eksponeringsmåling er reprodusert eksakt:** to `FunctionMiddleware`-subklasser (`mcp_tools.py:197` `ToolCallRecorder`, `explore.py:352` `ExplorationToolRecorder`) og **sju** `middleware=`-kallsteder (`run.py:1270`, `workflow.py:68` og `:93`, `explore.py:1346`, `:1358`, `:1741`, `:2033`). `agent-hooks`/`agent_hooks` = **0** treff i `src/`, `tests/`, `pyproject.toml` og `uv.lock` — po deklarerer ikke den ekstraen som ble fjernet. **DEN BREKKER IKKE, og grunnen er STRUKTUREL — ikke flaks.** po sine egne parametre er typet `Sequence[Any] | None` (`workflow.py:54` og `:80`), og hvert av de sju kallstedene sender en LISTE: `explore.py:1741`/`:2033` literale lister, `run.py:1262-1270` `debate_middleware: list[Any]`, `workflow.py`/`explore.py:1346`/`:1358` videresender en `Sequence`. En sequence-only inngang er altså allerede den eneste formen po kan produsere. **Dette er ikke PMs lesning av kilden lenger — det er suiten:** | witness | tall | |---|---| | Full suite | **1577 passed / 5 skipped** — identisk med basislinjen | | `test_explore_loadbearing` + `test_budget` + `test_scripted_explore_door_loadbearing` + `test_debate_navigation_cost_loadbearing` + `test_tool_call_path_loadbearing` | **74 passed** | **Hvilken test ville fanget det:** de fem over konstruerer agenter MED middleware og asserterer på det middlewaren produserer. Skarpest er `test_tool_call_path_loadbearing.py` (5 armer) og `test_debate_navigation_cost_loadbearing.py` (11 armer) — begge leser `RunResult.debate_tool_calls`/`ExplorationTrace.tool_calls`, altså sinken recorderen appender til, så en middleware som ikke ble **montert** gir et tomt spor og en rød arm. `tests/test_budget.py` er den tredje: `BudgetMiddleware`s pre-call-guard er dét som gjør S3.4-taket håndhevet, og en umontert budsjett-middleware ville brutt guard-testene direkte. **Ingen fiks var nødvendig, og ingen ble laget** — F16 er landet med suiten grønn på 1.18.0. ### (d) Vektorlager-abstraksjonen — 1.18.0, IKKE tatt i bruk > «**agent-framework-core**: Add shared vector-store abstractions, portable filters, and an > in-memory vector store ([#8014], [#8115])» · «**agent-framework-qdrant**: Add the alpha Qdrant > vector-store connector ([#8154])» · «**agent-framework-postgres**: Add the alpha PostgreSQL/pgvector > connector ([#8155])» — [python-1.18.0](https://github.com/microsoft/agent-framework/releases/tag/python-1.18.0) U10 leser ordrett «Vektorlagre | Azure AI Search, Cosmos, Qdrant, Redis, Postgres (innebygde abstraksjoner)», og **den tas fortsatt ikke i bruk: gjenfinningen er OKFs jobb og ikke MAFs, og et vektorlager inne i MAF ville flyttet D7-portabiliteten — `shared/`-kjernen og `okf.py` er ren stdlib nettopp så begge stacker konsumerer samme bundles uendret — uten å flytte misjonen ett skritt.** ## 5. d1 — SkillsProvider-avvisningen står, med en begrunnelse som er sann mot 1.18.0 Operatøren valgte **d1** fra P12 § 7 (D). Setningen i `docs/plan/2026-08-23-magentic-utforskningssloeyfe.md` § D.2 l. 370 leste: > «NEI — `ExperimentalFeature.SKILLS`; egen loader virker; commons eier innholdet» **Den første av de tre grunnene var død allerede i 1.16.0** (P12 § 2: `SkillsProvider` har ingen `@experimental`-markør; de tre markørene i `_skills.py` gjelder MCP-formene). **Re-målt mot 1.18.0 er det uendret:** de tre markørene er alle `ExperimentalFeature.MCP_SKILLS`, på `MCPSkillResource`, `MCPSkill` og `MCPSkillsSource`, og `SkillsProvider`/`FileSkillsSource` bærer ingen. ÉN setning er erstattet — tabellen er ikke skrevet om, U5 er ikke gjenåpnet, ingenting er bygget. ## 6. Fant IKKE, og bygde IKKE - **Ingen av de tre funksjonene er bygget.** Ingen ny middleware, ingen timeout-søm, intet vektorlager, ingen ny CLI-flate, ingen ny U-rad. STATEs «IKKE BYGG: timeout-sømmen fra 1a» står. - **Ingen push, ingen tagg, ingen versjonsbump av po** (`pyproject` `version = "1.1.0"` urørt). - **CHANGELOG: det finnes INGEN levende `## [Unreleased]`-seksjon.** Øverste post er `## [1.1.0] - 2026-08-14`. Én er ikke laget, fordi po sin versjon ikke er bumpet: å åpne en Unreleased-seksjon for en avhengighets-pinne ville vært å opprette en utgivelsesflate ordren eksplisitt forbyr å røre. Pinnen er dokumentert der den er håndhevet (`pyproject`-kommentarene og guardens docstring) pluss dette notatet. - **`docs/2026-09-12-f16-maf-1180.md` trenger INGEN `_LIVE_DOCS`-oppføring, og regelen er verifisert mot KODEN, ikke mot prosa:** `tests/test_doc_constant_sync_loadbearing.py:59` har `_DATED = re.compile(r"\d{4}-\d{2}")`, og `_is_archive()` klassifiserer enhver datert sti som et point-in-time-opptak. Denne stien matcher. - **De tre portene måles med `scratchpad/` EKSKLUDERT, og det sies høyt.** Bart kjørt gir `ruff check .` **121 errors** og `ruff format --check .` **82 files would be reformatted** — og **alle** ligger i `scratchpad/` (47 distinkte filer, alle under den ene katalogen; målt). `scratchpad/` er utracket og eies av en **parallell sesjon**; den er ikke øktens, og den er aldri `git add`-et. Ekskludert: `All checks passed!` / `211 files already formatted`. - **`docs/presentasjon-portfolio-optimiser.html` og `scratchpad/` er ikke committet.** `git add -A` og `git add docs` er ikke brukt; hver fil er navngitt. - **STATEs «⚠️ UPUSHET = 1 (`6eb58e5`; `ls-remote` = `ce22b0e`)» var STALE.** Målt ved øktstart: `git rev-parse HEAD` = `6eb58e5`, `git ls-remote origin refs/heads/main` = `6eb58e5` — **UPUSHET = 0**. Rettet i STATE. - **`explore.py`s `_runner.py:275-279`-siteringer er BEVISST ikke rettet** selv om linjene flyttet fire hakk (§ 2). De sier hvor et premiss ble lest; formen de siterer er gatet av proben. - **Modul-docstringen i guarden sier fortsatt «verified `1.9.0`»** om at distribusjonsversjonen er lesbar mens `__version__` er `0.0.0`. Det er et historisk måleresultat om KONTRASTEN, ikke om hvilken versjon som er installert, og det er latt stå heller enn å produsere en kosmetisk diff. ## 7. Honesty limits - **Form-proben er gulvet, aldri beviset.** Den sjekker statiske egenskaper ved kilden. F15s farligste funn var en egenskap ved kjøringen og var usynlig for enhver form-probe. Suiten er beviset; form 17 er re-målt ved kjøring nettopp fordi proben ikke kan se den. - **Åtte av de nitten sjekkene bor i `agent_framework_orchestrations` 1.1.1, som ikke flyttet.** De kan ikke avvike over denne bumpen, og «0 av 19 endret» skal leses med det. - **16 er ikke en uttømmende liste** over hva som kunne endre seg — det er hva repoets egne siteringer og sømmer gjorde synlig. - **Konfigurasjon A er målt på 27 tester, ikke på hele suiten.** Påstanden «resolverens eget valg er også grønt» har den nevneren, ikke 1577. - **Ingen betalt kjøring, NOK 0.** Ingen modellkall mot Azure eller en lokal backend. Alt som krever en levende modell er derfor **ikke målt**, inkludert: om `max_duration_seconds` faktisk degraderer som dokumentert mot et ekte endepunkt, om `#7988`s approval-binding endrer noe observerbart, og om `#8127`s «align provider credential handling» endrer en ekte token-henting (po sin credential-konstruksjon henter ingen token — `az login` er operatørens manuelle steg — så det ligger utenfor det en gratis kjøring kan se). - **`ref`-en for de 1.17/1.18-punktene som treffer pakker po ikke installerer** (`ag-ui`, `devui`, `foundry-hosting`, `lab`, vektorlager-konnektorene) er lest, men ikke målt mot po: pakkene er ikke i treet, så det finnes ingen kallsted-telling å gjøre. - **`#8045`** («foundry-hosting: [BREAKING - beta] Restrict checkpoint deserialization by default») ser ut som en treffer på po sin `_ALLOWED_CHECKPOINT_TYPES`, men **`agent-framework-foundry-hosting` er ikke installert** (po kjører stdlib-serveren, Fase 4d) — ingen eksponering, og det er derfor ikke en rad. ## 8. Verifiseringslogg — én kommando per påstand | # | Påstand | Kommando | |---|---|---| | 1 | Ordrekøen hadde ÉN ordre (min), innboksen 3 meldinger | `find ~/.claude/coord/portfolio-optimiser/{orders,inbox} -type f \| wc -l` → 1 / 3, rc 0 | | 2 | HEAD = remote, UPUSHET = 0 | `git rev-parse HEAD` + `git ls-remote origin refs/heads/main` → begge `6eb58e5` | | 3 | Fire PyPI-versjoner + krav | `curl -s https://pypi.org/pypi//json` → `info.version` + `info.requires_dist` | | 4 | Den PINNEDE 1.8.2 krever bare `core>=1.9.0` | `curl -s https://pypi.org/pypi/agent-framework-foundry/1.8.2/json` | | 5 | Basislinje på DENNE HEAD, før bumpen | `uv run pytest -q` → 1577 passed / 5 skipped | | 6 | Goldenene FØR | `shasum -a 1 tests/golden/demo-transcript.{stdout,stderr}` → `ea8c534…` / `ede3e2f…` | | 7 | Vakten RØD først | `uv run pytest tests/test_maf_version_guard.py -q` → **2 failed, 2 passed** | | 8 | Låsen flyttet kun core i første trinn | `uv lock` → «Updated agent-framework-core v1.16.0 -> v1.18.0» | | 9 | Konfigurasjon A grønn på 27 tester | `uv run pytest tests/test_maf_version_guard.py tests/test_async_plan_review_loadbearing.py tests/test_golden_transcript_loadbearing.py -q` → 4 + 19 + 4 | | 10 | Installerte versjoner ETTER | `uv run python -c "import importlib.metadata as m; …"` → 1.18.0 / 1.13.0 / 1.14.3 / 1.1.1 | | 11 | Vakten GRØNN | `uv run pytest tests/test_maf_version_guard.py -q` → 4 passed | | 12 | 19 sjekker / 16 former, BEGGE versjoner | `probe.py` mot utpakkede wheels 1.16.0 og 1.18.0 → `diff` = kun KP1/KP2 | | 13 | Kjent-positiv diskriminerer | KP1 `max_duration`/`stop_reason` i `_tools.py`: **0 → 24** | | 14 | F15s kjent-positiv gjelder ikke her | KP6 `MiddlewareFailure`: YES i BEGGE → forkastet | | 15 | Form 17 ved KJØRING | ekte CLI-park → 2 checkpoints, 1 nevner `request_id` | | 16 | Checkpoint-stien grønn i egen interpreter | `uv run pytest tests/test_async_plan_review_loadbearing.py -q` → **19 passed** | | 17 | `SecretString` treffer ikke po | `grep -rF SecretString src/ tests/` → 0; `…/agent_framework_foundry/` → 4, alle i `_embedding_client.py` | | 18 | `credential` er et objekt, ikke en streng | `_chat_client.py:168` → `AzureCredentialTypes \| AzureTokenProvider \| None` | | 19 | Lazy loading flyttet ikke stderr | `uv run python -m portfolio_optimiser.simulation` → stderr 2 linjer, stdout 61 | | 20 | Goldenene ETTER | `shasum -a 1 …` → uendret `ea8c534…` / `ede3e2f…` | | 21 | `approval_mode` = 0 i po | `grep -rF approval_mode src/ tests/` → 0 / 0 (venv 102) | | 22 | Middleware-eksponeringen | `grep -rn "class .*FunctionMiddleware" src/` → 2; `grep -rn "middleware=" src/` → 7 | | 23 | `agent-hooks` ikke deklarert | `grep -rF -e agent-hooks -e agent_hooks src/ tests/ pyproject.toml uv.lock` → 0 | | 24 | (c) brekker ikke — witnesses | 5 middleware-bærende suiter → **74 passed** | | 25 | (a) primitivens ekte navn og kanal | `grep -rn max_duration_seconds .venv/…/_tools.py` → `FunctionInvocationConfiguration`; `_tools.py:3078` `budget_state["truncated"]` | | 26 | (a) «stop_reason» er ikke en typet verdi | `grep -rniE "stop_?reason" .venv/…/agent_framework/` → 1 treff (`_mcp.py`, `stopReason`) | | 27 | Rad 4: skills lastes 2/2 | `FileSkillsSource("shared/skills").get_skills(ctx)` → **2 av 2** | | 28 | Rad 4: de tre markørene er MCP-formene | `grep -n -A2 "@experimental" .venv/…/_skills.py` → 3 × `MCP_SKILLS` | | 29 | Rad 5/6 witnesses | `uv run pytest tests/test_ingest_golden_mcp.py tests/test_hosting_loadbearing.py -q` → **22 passed** | | 30 | Release-notatene, ordrett + dato | GitHub release-API for `python-1.17.0` / `python-1.18.0` | | 31 | Full suite ETTER, på committet tre | `uv run pytest -q` → 1577 passed / 5 skipped | | 32 | Tre porter, `scratchpad/` ekskludert | `ruff check . --exclude scratchpad` · `ruff format --check . --exclude scratchpad` · `mypy src` | | 33 | Lint-støyen ligger UTELUKKENDE i `scratchpad/` | `ruff check . --output-format=concise \| cut -d/ -f1 \| sort \| uniq -c` → 47 × `scratchpad` | | 34 | `_LIVE_DOCS`-regelen | `tests/test_doc_constant_sync_loadbearing.py:59` `_DATED = re.compile(r"\d{4}-\d{2}")` | | 35 | NOK 0 | ingen `--profile azure`-kjøring; parken er scriptet offline med banneret «NO MODEL WAS CALLED» |