PORTFOLIO_OTEL er eneste bryter, lest paa truthiness. Uten den kalles configure_otel_providers ikke i det hele tatt: spans lages fortsatt (ENABLE_INSTRUMENTATION defaulter True) og kastes, saa ingenting KAN forlate prosessen. `console` skriver spans til stderr - demoens stdout er byte-identisk med fasiten, maalt. `otlp` eksporterer over nett, og kun mot et endepunkt operatoeren selv har navngitt. To regler er MAALT, ikke valgt (observability.py:849 bygger exporter-lista i fast rekkefoelge): - enable_console_exporters sendes EKSPLISITT False i begge moduser. Overlatt til miljoeet faller den tilbake paa ENABLE_CONSOLE_EXPORTERS, hvis ConsoleSpanExporter skriver til STDOUT - nettopp det S6 maalte som oedeleggende for goldenen. - `console` NEKTER naar en OTEL_EXPORTER_OTLP_*_ENDPOINT finnes: env-avledede exportere bygges UBETINGET og FOER vaare, saa ordet "console" ville vaert en usann paastand om hvor kjoeringens innhold tok veien. Validering, ALDRI reparasjon - vi fjerner ikke operatoerens variabel bak ryggen paa dem. Tre kallsteder (run.main, simulation.main, hosting.main): demoen er et skriptet bevis, ikke produktet, og en soem bare demoen naar ville latt de to inngangene en virksomhet faktisk kjoerer vaere usporbare. tracing_notice er ENESTE renderer og returnerer None naar sporing er av - omisjon, aldri tom rad. IKKE bygget, med grunn: PLAN_CREATED/REPLANNED/PROGRESS_LEDGER_UPDATED hoerer til sloeyfa U4 bygger; en emitter uten kallsted er en form gjettet i stedet for maalt. OTLP-exporter-PAKKENE er bevisst ikke deklarert (egress + grpc/protobuf-vekt i et publisert wheel); uttalt i README/DEPLOY/env.template. Ny dep: opentelemetry-sdk>=1.42,<2 (operatoerbeslutning 2, 23.08). EN pakke, ikke to - ConsoleSpanExporter bor inne i sdk-en. opentelemetry-api fulgte med 1.42.1 -> 1.44.0, maalt uskadelig. Load-bearing MAALT (tests/test_tracing_loadbearing.py), ni mutasjoner alle roede mot HELE suiten + groenn kontroll 943/5. Tre av de roede bor i tester som fantes fra foer (golden-transkriptets fire-linjers stderr + portefoelje-CLI-ens stille pass), altsaa er omisjons-regelen gatet av uavhengige vitner. Golden ea8c534... uendret. mypy src + ruff rene. Ordren tar ogsaa de fire operatoerbeslutningene inn i planens paragraf F. Laasen paa orchestrations 1.0.1 er ENDELIG (operatoerbekreftelse 23.08), ikke midlertidig: spike-ordrens "revert hvis E7 staar" er overstyrt av den senere beslutningen, som betinget paa groenn suite - ikke paa E7. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
56 KiB
MAF-utnyttelsesrevisjon U1–U15 + plan for Magentic-basert utforskningssløyfe
Ordre
20260823T125528Z-1876024635-from-.claude· Økt 53, 2026-08-23 · Fable 5/xhigh uten advisor (operatør-overstyring). Planarbeid: ingen kode isrc/, ingen tester. Hvert tall i dette dokumentet kommer fra en kommando som ble kjørt denne økten (vedlegg V1–V3); alt som ikke ble målt er merket «ikke målt» eller «spike».
0. Sammendrag — de seks setningene som bærer resten
- Målingen: av
.claudes ni «null i src/»-påstander holder 7 ordrett; U5 og U11 trenger presisering (artefaktet/sitatbæringen finnes, MAF-konstruktet gjør det ikke). Nevner: 32 filer. - Magentic-status: hele Learn-siden hentet — ingen experimental-advarsel for Python
(eneste «experimental» er et C#-pragma), og installert kode har ingen
@experimental-markør på Magentic. F14-sitatet «untested … outside of the original Magentic-One design» står fortsatt. PyPI latest er 1.1.1 (Production/Stable), men bare 1.0.0/1.0.1 kjører på core 1.9.0. - Designet: Magentic legges OVER den normative 8-stegs-sløyfa, ikke inni Steg 3. Utforskningen
er en mandat-former: prompt + bundles (+ fagpersonens frø-hypoteser) →
Mandate→run_project(mandate=…)uendret. Validatoren gater hvert tall i nøyaktig samme gate som i dag. - Fire ting ble MÅLT på installert 1.0.0, ikke antatt: en Magentic-workflow er single-use
(høylytt
RuntimeError), men builder og manager-instans blør (4/4 kontaminering, worker hoppet over, fabrikkert sluttsvar); plan-review-rundturen virker, men har ingen revise-cap;max_round_countgir en kanonisk streng, aldri et typet signal;MagenticResetSignalnullstiller ikke deltakernes sesjon (orphan-attributt i 1.0.0). - U14 er ikke «én funksjon»:
setup_observabilityfinnes ikke; inngangen eragent_framework.observability.configure_otel_providers, ogopentelemetry-sdker ikke installert — kallet krasjer medModuleNotFoundError. U14 er en avhengighetsbeslutning. - Rekkefølgen: S0–S6-spikes (1 økt) → U14 (1) → U4+U13 synkron (2) → U12 + asynkron U13 (1) → U15 som egen sammenligning (1). U1/U2/U5/U11 avvises med begrunnelse. Seks økter.
A. U1–U15-måling (nevner: 32 .py-filer i src/; kontroll: 117 i tests/, 6 i spikes/)
Metode: grep -rEn --include='*.py' "<regex>" src per kapabilitet, samme regex mot tests/ og
spikes/ som kjent-positiv-kontroll, og — for hver regex som ga 0 i alle tre — en tredje kjøring
mot installert MAF (.venv/lib/python3.12/site-packages/agent_framework{,_orchestrations}) som
beviser at spørringen KAN finne (Verifiseringsloven ansikt 4). Skript og rå output: vedlegg V1.
En uavhengig andre sveip (Opus-agent, 35 tokens, samme nevner) ga identiske nuller (V3).
| ID | Kapabilitet (§15.1) | src | tests | spikes | venv-kontroll | Status | Belegg / spørring |
|---|---|---|---|---|---|---|---|
| U1 | ConcurrentBuilder fan-out |
0 | 4 | 4 | — (tests/spikes finner) | IKKE — erstattet av håndrullet bølge | run.py:1262 await asyncio.gather( (D-D). Regex ConcurrentBuilder|BuildConcurrent|FanIn |
| U2 | WorkflowBuilder graf |
0 | 0 | 0 | 21 filer | IKKE | Regex WorkflowBuilder|@executor|class .*\(Executor\)|WorkflowContext|SwitchCase|add_edge|add_fan_out |
| U3 | GroupChatBuilder debatt |
10 | 7 | 7 | — | LANDET | workflow.py:24 import · :104 GroupChatBuilder( · :108 termination_condition= · :113 .with_max_rounds(max_rounds) |
| U4 | Magentic | 0 | 4 | 9 | 4 filer | IKKE | tests-treff: tests/spikes/test_b_footguns.py, tests/spikes/test_imports.py, tests/test_method_spec_loadbearing.py:40 (framework-navn-svarteliste for spec-prosa — ikke bruk). .claudes «kun spikes/b_footguns.py» er riktig for BRUK |
| U5 | Agent Skills (SkillsProvider) |
0 | 0 | 0 | 3 filer | IKKE som MAF-konstrukt; DELVIS som artefakt | persona.py:3/:47 leser shared/skills/expert-reviewer/SKILL.md via EGEN load_persona_example, aldri SkillsProvider. Installert core: @experimental(feature_id=ExperimentalFeature.SKILLS) på SkillsProvider (_skills.py:1718) |
| U6 | MCP-tools | 6 | 6 | 0 | — | LANDET (opt-in) | mcp_tools.py:42-43 import · :154 MCPStdioTool( · :170 MCPStreamableHTTPTool(. Ingest-sømmen bruker rå mcp.ClientSession (ingest_mcp.py:144-179) |
| U7 | Function tools | 4 | 10 | 0 | — | LANDET | datasource.py:18 from agent_framework import FunctionTool, tool · :65 · :69 @tool( |
| U8 | Middleware | 16 | 20 | 0 | — | LANDET | budget.py:27 · :228 class BudgetMiddleware(ChatMiddleware) · run.py:635/:645 |
| U9 | ContextProvider |
8 | 11 | 4 | — | LANDET | verdicts.py:29 · :319 class ExpeLContextProvider(ContextProvider) · run.py:724/:843 |
| U10 | Vektorlager | 2 | 19 | 0 | — | DELVIS (egen, ikke MAF) | semretrieval.py:355 save_vector_store · :393 load_vector_store — numpy brute-force (D-C). 0 på AzureAISearch|cosmos|qdrant|redis|VectorStore |
| U11 | Citation-aware RAG | 26 | 35 | 0 | — | DELVIS (egen, med MAF-typer) | provenance.py:18 from agent_framework import Annotation, TextSpanRegion · :78 to_annotations() («display only, NOT the source of truth»); datasource.py:1 «citation-bearing data source». 0 på AIContextProvider|TextSearchProvider|agentic_retrieval|KnowledgeAgent |
| U12 | Checkpointing | 3 (kun prosa) | 0 | 0 | 14 filer | FRAVALGT — §A.1 | run.py:22, workflow.py:14, :115: «no checkpoint — research 01: durable resume is fragile». 0 kode-treff på checkpoint_storage|CheckpointStorage |
| U13 | HITL-gates | 3 | 0 | 0 | — | DELVIS, og UØVD | workflow.py:116 builder.with_request_info(agents=[agents[-1]]) bak enable_layer1_hitl=False (:78, run.py:524; ingen CLI-flagg). ENESTE test: tests/test_workflow.py:54 test_layer1_hitl_option_builds — bygger, kjører aldri gaten, sender aldri et svar. run.py awaiter debate.run til ferdig (:684-686) og leser aldri strømmen. 0 på RequestInfoEvent|approval_mode|MagenticPlanReview i src OG tests |
| U14 | OpenTelemetry | 0 | 0 | 1 | 4 filer | IKKE | Regex opentelemetry|setup_observability|OBSERVABILITY|get_tracer|start_as_current_span. uv pip list: KUN opentelemetry-api 1.42.1 (transitiv) — ingen sdk, ingen exporter |
| U15 | Evaluering | 0 | 0 | 0 | 2 filer | IKKE | Regex evaluate_workflow|LocalEvaluator|Evaluator|_evaluation. evaluate_workflow finnes (_evaluation.py:1833) under @experimental(feature_id=ExperimentalFeature.EVALS) (:1832); 20 @experimental i modulen |
Utenfor de 15 (samme kjøring): U16 CompactionProvider 0/0/0 (venv 4) · U17 as_tool( 0/0/0
(venv 1) · U18 FoundryChatClient LANDET backends.py:150 · U19 Harness 0/0/0 (venv 1).
Mot .claudes ni null-påstander: 7 av 9 holder ordrett (U1, U2, U4, U12, U13, U14, U15). 2 av 9
trenger presisering: U5 og U11. De 6 landet-påstandene holder (U3, U6, U7, U8, U9,
U10-delvis). Aliasing/re-eksport er utelukket: alle 14 agent_framework-importlinjer i src/ er
listet i V3 og hver er et direkte navn; from agent_framework_orchestrations import → 0 treff
(importstien i bruk er agent_framework.orchestrations, workflow.py:24).
A.1 U12 — fravalgt på et premiss som har råtnet, eller som holder?
Premisset i koden: «research 01: durable checkpoint resume is fragile» (workflow.py:14).
«research 01» finnes ikke som dokument i repoet (grep -rn -i "research.01" docs/ STATE*.md
→ 0). Nærmeste dokumenterte grunnlag: kapabilitetskartet
(docs/research/2026-06-24-maf-capability-map.md:54): «superstep-granular (not mid-LLM-call);
resume needs identical graph. Defer past MVP unless needed»; egnethetsplanen 08-09 P9/P10
(«pass-nivå-gjenopptakelse er levert via spend-fila; ingen checkpointing»); docs/extending.md:315
(«A run either completes or is re-run; the async verdict inbox is the resumable boundary»).
Vurdering: begrunnelsen holder for dagens debatt (sekunder–minutter; re-kjøring er billigere
enn gjenopptakelse). Den holder ikke for målbildet: en utforskning som stopper i
MagenticPlanReviewRequest og venter på en fagperson i dager kan ikke holde en prosess i live, og
«re-kjør» kaster planen fagpersonen skulle revidere. Premisset er ikke råttent — det er utenfor
sitt gyldighetsområde. Det som ble MÅLT i installert core 1.9.0 denne økten (V2 §7): mekanismen
FINNES og dekker Magentic-tilstand — FileCheckpointStorage (_checkpoint.py:239), «restore then
send» (run(responses=…, checkpoint_id=…) eksplisitt tillatt, _workflow.py:877), pending
request_info re-emitteres ved resume (_runner_context.py:414-426), og MagenticOrchestrator. on_checkpoint_save skriver kontekst (runde/stall/reset-tellere), ledgere og managerens hele sesjon
(_magentic.py:1266-1284, :746). «Skjør» er i dag konkret: base64-pickle av tilstand med
allow-list (_checkpoint.py:242-250), graf-signatur må matche (_runner.py:275-279), og
manager-state-feil ved lagring/gjenoppretting svelges med warning (_magentic.py:1281-1282,
:1320-1321). Ingen ende-til-ende-resume med pending plan review er kjørt → spike S4 (§D).
B. Magentic-status mot primærkilden (hele siden hentet 2026-08-23)
Kilde: microsoft_docs_fetch mot
learn.microsoft.com/en-us/agent-framework/workflows/orchestrations/magentic — hele siden.
- Ingen experimental-advarsel for Python. Eneste «experimental» på siden: C#-blokken
#pragma warning disable MAAIW001 // Magentic types are experimental(.NET-diagnostikk)..claudes fravær er bekreftet, ikke bare ikke-motbevist. - F14-sitatet står ordrett: «it is untested how well the Magentic orchestration will perform
outside of the original Magentic-One design», og tipset «consider using the Group Chat pattern
instead» for enklere koordinering. F14s VURDERING var riktig lest; operatøren har flyttet
PREMISSET (målbildet krever planlegging), ikke sitatet. G8 i §15.3 er halvt riktig: funksjonelle
workflows er fortsatt
ExperimentalFeature.FUNCTIONAL_WORKFLOWS; Magentic er ikke markert. - Installert kode:
agent_framework/_feature_stage.py:43-65—ExperimentalFeaturehar 13 medlemmer (DECLARATIVE_AGENTS, EVALS, FILE_HISTORY, FIDES, FOUNDRY_TOOLS, FOUNDRY_PREVIEW_TOOLS, FUNCTIONAL_WORKFLOWS, HARNESS, MCP_LONG_RUNNING_TASKS, MCP_SKILLS, PROGRESSIVE_TOOLS, SKILLS, TO_PROMPT_AGENT). Magentic er ikke der;grep -n -i "experimental\|feature_stage" agent_framework_orchestrations/*.py→ 0. - PyPI (
curl https://pypi.org/pypi/agent-framework-orchestrations/json): latest 1.1.1 (2026-08-21),Development Status :: 5 - Production/Stable, 26 utgivelser. Krav per versjon: 1.0.0/1.0.1 → core ≥1.9.0; 1.0.2/1.1.0 → ≥1.13.0; 1.1.1 → ≥1.15.0. Core latest 1.15.0 (21.08). - Installert = pinnet:
uv pip list→ orchestrations 1.0.0, core 1.9.0;uv.lock:61-63låser 1.0.0;pyproject.toml:17>=1.0.0,:12core>=1.9.0,<2(tests/test_maf_version_guard.py). - Learn-siden beskriver LATEST API (
manager_agent=,enable_plan_review=,intermediate_output_from=). Installert 1.0.0 har de samme konstruktør-navnene (V2 §2) — men builder-docstringen i 1.0.0 beskriver et HITL-API (MagenticHumanInterventionRequest,with_human_input_on_stall) som ikke finnes i koden (kun i docstrings,_magentic.py:1388-1559). Designet i §C er skrevet mot det som er målt installert, aldri mot docstring eller Learn. - Core 1.12.0-notatet (21.07, samme minutt som orchestrations 1.0.1): «Prevent the Magentic manager from duplicating conversation history (#6297)». Om 1.0.1 bærer fiksen er ikke verifisert — det er spike S0.
C. Design: den utforskende sløyfa
C.0 Beslutningen — Magentic OVER sløyfa, ikke INNI Steg 3
Kjernespørsmålet: Magentic gir manageren frihet til å velge vei; validatoren gater utfallet. Er de forenlige? Ja — på én betingelse: utforskningen produserer KANDIDATER, aldri FORSLAG.
Tre fakta avgjør formen:
- Metodespesifikasjonen er normativ og commons-eid (
shared/method-spec.md, pull-only). §3 Steg 3 KREVER en to-rolle maker-checker-debatt, rundetak og fersk tilstand per kjøring; Steg 2 krever «exactly one candidate measure» per proposer-kall; §8 «Never an unbounded loop, anywhere». En Magentic-sløyfe som ERSTATTER Steg 3 bryter spec-en og krever commons-amendment FØR bygging — og den ville flyttet validatoren INN i grafen. Sømkartet (V3) er entydig: alt som gjør et svar etterprøvbart ligger UTENFOR workflow-grafen og ETTERdebate.run— genereringrun.py:748-759, validatorgenerate.py:491, provenancerun.py:793, checker-override:816, dimensjonsgate:826, domfangst:849, outbox:857. Mandatefinnes og ER «en prompt om hva som skal gjøres» (mandate.py:55-88):objective+approaches[{id, label, description}]+allow_own_proposals+success_criteria. EnApproach.descriptioner «the expert's own prose reason … fed to the proposer VERBATIM» (mandate.py:44-49,generate.py:308-317) — altså «hypoteser fagpersoner kommer med»._evaluate_mandate(run.py:292-344) kjører hver approach gjennomgenerate_via_llm→validate_proposalunder SAMME meter, og rapporterernot_evaluatedfor det budsjettet ikke rakk (aldri utelatt).announce(mandate.py:130-183) sier høyt hva kjøringen skal gjøre FØR første betalte kall — repoets eksisterende før-kjøring-menneskesjekk.- Validatoren er ren og offline (
validate_proposal,validator.py:194-260; CBC via PuLP,_MC_SAMPLES = 512, ingenagent_framework-import) og kan eksponeres somFunctionTool(U7) uten å endre hva den er.
Derfor: utforskningen er en MANDAT-FORMER. Inn: operatørens prompt + tilgjengelige bundles
(+ valgfrie frø-approaches fra fagpersoner). Ut: en Mandate hvis approaches er hypotesene
utforskningen fant verdt å teste, med managerens begrunnelse som description, og bundle_id per
approach. Deretter run_project(bundle_dir=…, mandate=…) uendret: debatt (Steg 3) → generering
(Steg 2) → deterministisk validator (Steg 4, blokkerende, stempler validator_decision) →
checker-gate → outbox/HITL (Steg 6–8). Ingen linje i den kjeden endres. Manageren velger VEI i et
rom som ikke kan skrive til outbox eller wiki; validatoren gater hvert TALL som forlater rommet, i
samme gate som i dag.
Tre nivåer av garanti (uttalt, så ingen leser mer inn i det enn det er):
| Nivå | Hva | Hvor | Stempel? |
|---|---|---|---|
| 1 | quick_validate-verktøyet i utforskningen |
samme validate_proposal, samme baseline, kalt av hypothesiser-agenten |
NEI — rådgivende tall i en utforskningslogg, aldri provenance |
| 2 | Pipelinen per approach | run.py:748 _evaluate → validate_proposal |
JA — ProvenanceStamp.validator_decision |
| 3 | Skriverettigheter | kun pipelinen når outbox (outbox.write_outbox) og wiki (promote_verdict, gated) |
utforskningens sluttsvar er RÅ ({run_id}-exploration.json), aldri et forslag |
Ærlighetsregelen (§1) følger direkte: managerens «final answer» presenteres ALDRI som et resultat.
Resultatet er det _evaluate_mandate returnerer.
C.1 Manager + deltakersett (mot installert 1.0.0-API, V2 §2–3)
| Rolle | Type | Gjør | Verktøy / kanal |
|---|---|---|---|
| manager | MagenticBuilder(manager_agent_factory=…) → StandardMagenticManager(agent=…) med EGNE ledger-prompter (konstruktør-parametre task_ledger_*_prompt, progress_ledger_prompt, final_answer_prompt) |
planlegger, velger neste taler, fører progress ledger, replanlegger | ingen — men BudgetMiddleware PÅ manager-agenten (C.2) |
| navigator | Agent |
leser bundles PROGRESSIVT (§3 Steg 1) og svarer med sitater | list_bundles() · read_bundle(id) → okf.navigate_bundle + Bundle.index_summary()/bundle_context · read_file(id, path) innenfor retrieval.safe_resolve |
| hypothesiser | Agent |
former én kandidat om gangen som IR-JSON (gjenbruker generate._build_messages + proposal_response_format()) |
quick_validate(ir_json) → {decision, reason, p10, p50, p90} (nivå 1) |
| expert_liaison | menneske/persona | svarer på spørsmål, reviderer retning | plan review (MagenticPlanReviewRequest.approve()/.revise(feedback)) — og, etter spike S3b, AgentApprovalExecutor som deltaker for svar MIDT i kjøringen |
Hvorfor StandardMagenticManager, ikke egen subklasse: egen manager = egen ledger-parsing = egen
kopi av Magentic-One-logikken (kø-(p): den andre kopien drifter). Prompt-overstyring dekker behovet
(norsk domene, IR-disiplin, «aldri oppgi et tall uten quick_validate»). Målt grunn til å
overvåke: manageren parser ledgeren med en håndrullet JSON-skraper (_extract_json,
_magentic.py:406-449, ast.literal_eval-fallback), 3 forsøk (:588-590, :710-723) → RuntimeError;
MagenticProgressLedgerItem.answer er ikke typesjekket per felt (:300-302). Egen manager FØRST når en
målt mangel krever det.
Hvorfor manager_agent_factory= og ikke manager_agent=: målt E4 (V2 §6) — manager_agent=
konstruerer manageren eagerly (:1683) og gir SAMME instans til hvert build() (:1729-1730);
factory-varianten kalles per build (:1732-1738).
C.2 Progress ledger som styringssignal, koblet mot budget.py
Ledgeren (_magentic.py:310-314, navn verifisert): is_request_satisfied / is_in_loop /
is_progress_being_made / next_speaker / instruction_or_question. Stall-regelen (:1109-1118):
not is_progress_being_made or is_in_loop → stall_count += 1, ellers dekrementer (ikke
nullstill); stall_count > max_stall_count (strengt >) → _reset_and_replan (:1149): kontekst
nullstilles, reset_count += 1, replan, plan review på nytt med is_stalled=True hvis aktivert.
To signaler, to vakter, aldri slått sammen (S3.4-invarianten):
| Signal | Kilde | Vakt | Utfall |
|---|---|---|---|
| Semantisk — stall | ledger | max_stall_count → reset+replan → max_reset_count |
exploration_stop="stalled" — strukturert; IKKE krasj, IKKE suksess |
| Ressurs — tokens | BudgetMiddleware (budget.py:228) på HVER agent inkl. manager |
pre-call-guard :242-244 |
BudgetExceeded(kind="tokens") → 429-kanalen |
| Ressurs — runder | Magentic max_round_count (= Budget.max_rounds) |
intern (:1238) |
oversettes av vårt lag til BudgetExceeded(kind="exploration_rounds", limit, observed) |
Målt grunn til oversettelsen (E5, V2 §4): max_round_count/max_reset_count gir ingen
exception — en kanonisk assistent-melding «Workflow terminated due to reaching maximum round
count.» + _terminated=True (:1222-1256), uten prepare_final_answer. Ved transporten er det
uskillbart fra suksess. Vårt lag leser derfor round_count fra MagenticContext (eksponert via
PROGRESS_LEDGER_UPDATED-eventene, ett per runde) og orchestrator._terminated, og produserer det
typede stoppet SELV — slik BudgetExceeded/429 alt gjør for debatten. Strengen pinnes mot den
installerte konstanten (ROUND_CAP_LOGGER-presedensen), aldri fri-tekst-matchet.
tick_round er IKKE koblet til orkestreringsrunder i dag (sømkart: to kallere, begge i
generate.py:390/:455; run.py:632 gir meteret max(max_rounds*4, 4) for GENERERINGS-forsøk).
Utforskningen får derfor sin egen Budget (tokens + runder) i en egen TokenMeter, og run_project
sitt meter er urørt. Stall-telleren er IKKE en budsjettvakt og kobles ikke inn i TokenMeter.
Hver runde logges (ledger + next_speaker + instruction_or_question) til
{run_id}-exploration.json, så en stoppet utforskning er lesbar uansett hvilken vakt som fyrte.
⚠ Spike S2: manageren er et Agent (StandardMagenticManager(agent=…), :528; ett
create_session() i __init__, :572; alle kall via agent.run(…, session=…), :601), så
agent-nivå ChatMiddleware SKAL fyre — men det er ikke målt for manager-stien, og en feil her
gjør «harde token-tak» til en løgn for den mest pratsomme deltakeren. Kontroll: bar
BaseChatClient no-op-er middleware (simulation.py:373-375) — spiken bruker ScriptedChatClient.
C.3 Grensene — B4 bygges ikke bort
| Dagens | Magentic (installert) | Regel |
|---|---|---|
with_max_rounds(max_rounds) (workflow.py:113) |
max_round_count (ctor-kwarg; default None = ubegrenset, :542) |
PÅKREVD, positiv, fail-fast (G1/B4/A4) |
| — | max_stall_count (default 3, :540) |
PÅKREVD, positiv — ingen arv av defaulten |
| — | max_reset_count (default None, :541) |
PÅKREVD, ≥0 |
termination-safety-net (:108) |
manageren avslutter ved is_request_satisfied (:1104-1107) eller ved ukjent next_speaker (:1128-1131 — stille sluttsvar!) |
rundetaket ER nettet; ukjent taler logges som avvik |
| — | plan review: ingen revise-cap, revises telles ikke som runder (målt E6: 2 manager-kall per revise, 0 ledger-kall) | NY max_plan_revisions i kontrakten; hver revise tick_round()-es |
ExplorationContract (pydantic, fail-fast, speiler contracts.TerminationContract): max_rounds,
max_tokens, max_stall_count, max_reset_count, max_plan_revisions, enable_plan_review.
Ingen defaults: en utforskning uten uttalte grenser nekter å starte.
C.4 B7 — tilstandsisolasjon. MÅLT (V2 §6; skript i V1)
| Eksperiment | Resultat | Konsekvens |
|---|---|---|
E1 én bygget workflow, to .run() |
run 2 → RuntimeError: This Magentic workflow has already been completed… (_magentic.py:914-918), 0 modellkall |
single-use — STERKERE enn GroupChat 1.9.0s stille tomme kjøringer [2,0,0]; kan ikke korrumpere, for den kan ikke kjøre |
E2 to workflows, ÉN delt StandardMagenticManager |
run 2s manager-kall ser run 1s oppgave 4/4; meldingstall vokser 2→…→23→26→39 over kjøringsgrensen; run 2s første ledger svarte satisfied=True og workeren ble aldri kalt (0) — et fabrikkert sluttsvar |
ikke bare kost: en plausibel fasit produsert av null arbeid |
| E3 kontroll, fersk manager per build | 0/5 kontaminering, 5 kall inkl. ledger_UNSAT (workeren KALT) |
5-vs-4-kallformen er diskriminatoren |
E4 én MagenticBuilder, to .build() |
samme 4/4-blødning som E2 (:1683, :1729-1730) |
«ny workflow» er ikke nok — ny BUILDER per oppgave, eller manager_agent_factory= |
E7 MagenticResetSignal |
_magentic.py:1366 skriver self._agent_thread — lest av INGENTING (1 treff repo-vidt; den levende er AgentExecutor._session, 7 treff). Målt: cache/full_conversation tømt, sesjonsidentitet uendret |
stall-replan gir fersk manager-ledger men gamle deltakere; docstringens løfte (:1341-1344) holder ikke i 1.0.0 |
Regel: per utforskning ny builder → ny build → én kjøring, fersk klient per agent (som
fresh_workflow/_default_factory alt gjør, run.py:436-440). Stol aldri på stall-reset for å
tømme deltakerminne. fresh_exploration_workflow() speiler fresh_workflow() (workflow.py:74).
C.5 HITL-spranget: fra JA/NEI til «be om svar, bruke svarene»
Installert flyt (målt E6, V2 §5): with_plan_review()/enable_plan_review=True →
ctx.request_info(MagenticPlanReviewRequest{plan, current_progress, is_stalled}, MagenticPlanReviewResponse) (:1041-1048) → event type="request_info" med request_id →
kjøringen STOPPER uten output → workflow.run(responses={request_id: req.approve()}) eller
req.revise("…") (_workflow.py:899-908) → ved revise: feedback inn i historikken, manager.replan,
REPLANNED-event, ny review-forespørsel (:1014-1031) → ved approve: løkka kjører.
Dette er målbildets «be om svar, bruke svarene og jobbe videre» ordrett — og det virker på 1.0.0.
Ingen landingsplass i dag (sømkart §4): with_request_info bygges men ingenting konsumerer
strømmen; hitl.py er et offline inspeksjonsverktøy (id-join outbox − inbox, hitl.py:159), ikke
en forespørsel/svar-mekanisme. Koblingen mot den asynkrone køa gjenbruker formen, ikke filene:
| Eksisterende | Utforskningen |
|---|---|
outbox {run_id}-outcome.json med verdict_id |
NY artefaktklasse {run_id}-plan-review.json = {request_id, plan, current_progress, is_stalled, checkpoint_id} — samme RAW-lag, samme mappe, byte-deterministisk via outbox._dump |
inbox {id}.json (verdicts.write_verdict) |
{request_id}.json = {decision: approve|revise, feedback} — eksperten SKRIVER, systemet LESER (§3 Steg 7-rolledelingen) |
hitl.py pending (id-join) |
samme join over den nye klassen; python -m portfolio_optimiser.hitl pending viser begge |
FeedbackContract.decision ∈ {approved, rejected} |
IKKE gjenbrukt — en plan-revisjon er ikke en dom; eget lite pydantic-skjema |
simulation-personaen (load_persona_example) |
spiller eksperten SYNKRONT i demoen: revise("Test også …") én gang, så approve() |
To tidsskalaer, som Steg 7: synkron (persona/operatør i samme prosess — demoen og første
leveranse) og asynkron (fil-innboks over dager → krever U12: checkpoint_id i artefaktet,
run(responses=…, checkpoint_id=…, checkpoint_storage=…)). Det er DÉT som flytter U12 fra «NEI» til
«nå» — og spike S4 avgjør om 1.9.0 bærer det.
Svar MIDT i kjøringen (ikke bare ved plan): plan review er det ENESTE request_info
orkestratoren selv reiser (4 treff i _magentic.py, 0 i basen). Men AgentApprovalExecutor
(_orchestration_request_info.py:168, propagate_request=True :201) kan stå som DELTAKER:
når manageren velger expert_liaison, blir dens output en request_info, og mennesket svarer med
AgentRequestInfoResponse.approve()/.from_strings(…) (:55-79) — svaret blir deltakerens
output i historikken. Ikke målt → spike S3b. Lander den, er «stille spørsmål … be om svar»
dekket både ved plan og underveis.
C.6 «Hypoteser fagpersoner kommer med» — tre inngangsdører, i kostnadsrekkefølge
- I mandatet (finnes):
Approach{label, description}→ proposeren verbatim. Utforskningen tar frø-approaches som INPUT og MÅ bevare dem i output-mandatet (en hypotese fagpersonen ba om forsvinner aldri stille —not_evaluated-regelen anvendt på utforskning). - I plan review (U13):
revise("Test hypotesen at …")→ replan med teksten i task-ledgeren. - Underveis (S3b):
expert_liaison-deltakeren — manageren SPØR, fagpersonen svarer, svaret blir kontekst for neste runde. - I kunnskapsbasen (senere, commons-sak):
type: hypothesis-konseptfil navigatoren finner. Krever OKF-vokabular-beslutning hos commons — ikke i denne planen.
C.7 OKF-bundles som inngang — hva manageren må vite
Manageren planlegger mot en katalog, aldri innholdet (§3 Steg 1). Per bundle: id ·
Bundle.index_summary() (okf.py:154) · kandidat-features (verdicts.bundle_candidate_features,
:482) · om cost-baseline.json finnes (okf.load_optional_cost_baseline, :411) — avgjørende:
en uforankret bundle kan ikke quick-valideres mot stage 0, og manageren skal vite hvilke hypoteser
som KAN testes deterministisk · antall type: verdict-filer (Bundle.verdicts). Navigatoren åpner
én bundle om gangen på managerens instruks. Multi-bundle er NYTT: run_project tar ÉN
bundle_dir (run.py:514; bundle_dirs → 0 treff); utforskningen tar bundle_dirs, hver
approach bærer bundle_id, og pipelinen kjøres per bundle som i dag (run_portfolio-formen).
C.8 Modulplassering (for byggeøktene, ikke for denne)
src/portfolio_optimiser/explore.py (NY): ExplorationContract, ExplorationResult{mandate, ledger_log, stop, plan_reviews}, fresh_exploration_workflow(...), explore(...). Importerer
agent_framework.orchestrations — aldri fra okf.py/mandate.py/hitl.py (MAF-fri-guarden
test_okf_is_maf_free). Verktøyene (quick_validate, navigator-tools) bor i explore.py og
wrapper de rene modulene. run.py får ett nytt kallsted (--explore "<prompt>" → explore() →
run_project(mandate=…)), hosting.py ett nytt whitelistet felt (explore_prompt), og
simulation.py ett nytt scenario. Demo-transkriptet (tests/golden/demo-transcript.stdout) er
byte-uendret fordi utforskningen er opt-in.
D. Prioritert vei gjennom de ni gapene
D.0 Versjonsbeslutningen (FØR noe bygges — én avgjørelse, ikke en glidning)
Anbefaling: bygg mot 1.0.x (installert) i denne planen. (1) core-bumpen 1.9→1.15 er seks
minor-versjoner over privat-API-premisser test_maf_version_guard vokter, og tre målte
1.9-egenskaper (ExperimentalWarning-paret, single-use GroupChat [2,0,0], middleware-no-op på bar
klient) må re-måles; (2) en bump er en egen beslutning, ikke et biprodukt av sløyfa; (3) 1.0.1 er et
patch-hopp på samme core som kan tas gratis
hvis uv lock --upgrade-package agent-framework-orchestrations gir 1.0.1 og suiten er grønn — og
som KAN bære #6297 (§B pkt. 7) og/eller E7-fiksen. Det er spike S0. Bumpen til 1.1.x/core 1.15 er
en EGEN økt etter denne planen (bonus: InvocationsHostServer krever core ≥1.13) — ikke en forutsetning.
D.1 Spikes (økt 54 — alle i spikes/e_magentic.py + tests/spikes/, aldri src/)
| # | Spørsmål | Måling | Felles hvis |
|---|---|---|---|
| S0 | Gir 1.0.1 samme API og fjerner den E2/E4/E7? | uv lock --upgrade-package agent-framework-orchestrations → uv pip list; re-kjør V1-skriptene magentic_b7*.py + magentic_reset.py; uv run pytest -q |
E7 står → bli på 1.0.0, noter |
| S1 | B7 i repoets egen form | E1–E4 + E7 portert til spikes/ med ScriptedChatClient (ikke agentens FakeClient) |
4/4 på delt builder, 0/5 på fersk |
| S2 | Fyrer BudgetMiddleware på MANAGERENS kall? |
manager-Agent(middleware=[BudgetMiddleware(meter)]), Budget(max_tokens=1, …); assert BudgetExceeded propagerer ut av workflow.run OG at meter.tokens > 0 etter ett kall |
middleware fyrer ikke → egen klient-wrapper; plan-endring |
| S3 | Plan-review-rundtur i repoets form | E6 portert: request_info-event → run(responses=…) med revise så approve; tell manager-kall per revise (målt 2) |
rundturen feiler på 1.0.0 |
| S3b | AgentApprovalExecutor som deltaker |
svar injiseres via from_strings("svar"), assert svaret står i neste manager-prompt |
ikke nåbar → kun plan review (dør 1+2) |
| S4 | Resume med pending plan review | with_checkpointing(FileCheckpointStorage(tmp)), kjør til review, ny prosess (subprosess), run(responses=…, checkpoint_id=…, checkpoint_storage=…); assert request_info re-emittert + sluttsvar |
feiler → U12 synkron-først, asynkron etter planen |
| S5 | quick_validate-latens |
validate_proposal ×20 på bygg-energi-baseline-mikro med time.perf_counter |
> 2 s/kall → budsjettér kall i kontrakten |
| S6 | OTEL gratis? | uv add opentelemetry-sdk i scratch-venv; configure_otel_providers(enable_console_exporters=True); kjør demoen; tell spans |
ingen workflow.run-span → U14 er større enn én økt |
D.2 Rekkefølgen
| # | Hva | Gap | Load-bearing for målbildet? | Økt | Modell |
|---|---|---|---|---|---|
| 0 | Spikes S0–S6 | U4/U13/U12/U8/U14 | JA — hver er en antakelse planen ellers bygger blindt på | 54 | Opus 5/xhigh |
| 1 | U14 OpenTelemetry — opentelemetry-sdk som deklarert dep, configure_otel_providers bak PORTFOLIO_OTEL=… (console default; OTLP KUN med eksplisitt OTEL_EXPORTER_OTLP_ENDPOINT — «ingen stille egress»), spans på DAGENS pipeline først; egne events for PLAN_CREATED/REPLANNED/PROGRESS_LEDGER_UPDATED (målt: _magentic.py emitterer null spans selv) |
U14 | JA for «stole på» — og baselinen U15 måler mot | 55 | Opus 5/high |
| 2 | U4 + U13 synkron — explore.py (C.8), ExplorationContract, mandat-former, quick_validate, navigator-tools, plan review med persona; simulation-scenario; --explore i CLI |
U4, U13 | JA — dette ER målbildet | 56–57 | Opus 5/xhigh |
| 3 | U12 + asynkron U13 — FileCheckpointStorage, {run_id}-plan-review.json + innboks-svar, hitl.py pending utvidet, --resume <run_id> |
U12, U13 | JA for svar over dager — betinget av S4 | 58 | Opus 5/xhigh |
| 4 | U15 — EGEN sammenligning på golden-bundelen: utforskning vs. debatt på tre tall (validerte kandidater, tokens, runder), skrevet til docs/ som måling |
U15 | JA for «finner den bedre tiltak» — men MAF-evals AVVISES (eksperimentell i kode, «wrong shape», kapabilitetskart :58) | 59 | Opus 5/high |
| — | U1 ConcurrentBuilder |
U1 | NEI — bølgemodellen er målt, bærer budsjett-reservasjon (S3.4); Concurrent har ingen runder å reservere mot | etter planen, om noensinne | — |
| — | U2 WorkflowBuilder |
U2 | NEI — Magentic ER graf-laget; direkte adopsjon gir null ny kapabilitet | nei | — |
| — | U5 SkillsProvider |
U5 | NEI — ExperimentalFeature.SKILLS; egen loader virker; commons eier innholdet |
etter planen | — |
| — | U11 MAF RAG-providere | U11 | NEI — «navigate, never stuff» forbyr query-time retrieval; sitatbæring finnes | avvist med begrunnelse | — |
Seks økter (54–59); faller S4, sparer pkt. 3 én økt.
D.3 For og mot de fire kandidatene ordren navngir
U4 + U13 tidlig — FOR: selve målbildet; alt annet er instrumentering av status quo. MOT: hviler
på umålte antakelser (S2, S3b, S4) og på en request_info-sti repoet ALDRI har kjørt. Derfor spikes
først — ikke omvendt. Plass #2 og #3.
U14 tidlig — FOR: (1) repoets deploy-gate; (2) uten sporing er en utforskning en svart boks — og
Magentic-koden gir selv null spans, så ledger-eventene må vi logge; (3) LITE i kode: én funksjon +
env; (4) instrumentert FØR utforskningen gir U15 sin baseline. MOT (målt): det er ikke gratis i
avhengigheter — opentelemetry-sdk + exporter må deklareres (wheel-vekt, uv sync, handover-
pakka), og ENABLE_INSTRUMENTATION er default True (observability.py:697) så spans LAGES alt i
dag og kastes. OTLP-exporter er egress og må være opt-in bak eksplisitt endepunkt. Plass #1,
betinget av S6.
U15 — FOR: uten måling kan vi ikke påstå at sløyfa er bedre; ærlighetsregelen forbyr påstanden.
MOT evaluate_workflow: eksperimentell i kode (20 dekoratorer) og feil form (kvalitetsscore
offline, ikke domeneobjekt). Konklusjon: evaluering JA, som egen sammenligning; MAF-flaten
NEI inntil EVALS forlater ExperimentalFeature. Plass #4 — den trenger noe å måle.
U12 — FOR: asynkron plan review over dager er umulig uten; mekanismen dekker Magentic-tilstand (målt i kode, §A.1). MOT: ende-til-ende-resume på 1.9.0 er umålt, restore-feil svelges, og en synkron persona-variant leverer målbildet i demoen uten den. Konklusjon: S4 avgjør; bygg i #3 hvis grønn, ellers synkron-først og U12 etter planen, sammen med core-bumpen.
D.4 Det som IKKE gjøres (uttalt)
- Ingen endring i
shared/method-spec.md. Utforskningen er et lag OVER §3; en amendment («Step 0 — Explore, optional») foreslås til commons via coord (operatørbeslutning, §F) — planen avhenger ikke av svaret. - Ingen D7-speiling nå: po-claude er PARKERT (STATE); utforskningslaget meldes dit når parkeringen oppheves, på linje med Steg-5-returtypen og demo-innboksen som også venter.
- Ingen erstatning av GroupChat-debatten (Steg 3 står). Ingen
open/-push, versjonsbump, Azure. - Ingen egen
MagenticManagerBase-subklasse før en målt mangel krever det.
E. Verifisering — testbare kriterier (kommandoer, ikke «sjekk at det virker»)
Denne økten (planen selv):
| # | Kriterium | Kommando → forventet |
|---|---|---|
| E1 | Nevneren er 32 | find src -name '*.py' | wc -l → 32 |
| E2 | Hver null-spørring kan finne | bash scratchpad/u_measure.sh (V1) → venv_files ≥ 1 for hver av de 9 null-regexene |
| E3 | Magentic ikke kode-markert | grep -c -i "experimental" .venv/lib/python3.12/site-packages/agent_framework_orchestrations/_magentic.py → 0; grep -n "SKILLS|EVALS" …/agent_framework/_feature_stage.py → :54, :64 |
| E4 | Installert = lås | uv pip list | grep orchestrations → 1.0.0; sed -n '61,63p' uv.lock → version = "1.0.0" |
| E5 | Single-use + builder-blødning reproduserbar | uv run python scratchpad/magentic_b7.py → E1 run2 … RuntimeError, E2 VERDICT … 4/4, E3 VERDICT … 0/5 |
| E6 | Plan-review-rundtur reproduserbar | uv run python scratchpad/magentic_b7b.py → E6 after APPROVE outputs: ['FINAL: …'], E5 outputs: ['Workflow terminated due to reaching maximum round count.'] |
| E7 | OTEL-sdk mangler | .venv/bin/python -c "import opentelemetry.sdk" → ModuleNotFoundError |
| E8 | Planen er dok-gate-klassifisert | uv run pytest -q tests/test_doc_constant_sync_loadbearing.py → grønn (datert sti = arkiv-klasse) |
| E9 | Treet urørt utenom planen | git status --porcelain → kun docs/plan/2026-08-23-…md + den fremmede presentasjon-HTML-en |
Byggeøktene (kriterier som FELLES når sømmen detaches — load-bearing-metoden):
| Leveranse | Rødt-først-kriterium |
|---|---|
| S1/B7 | test som deler builder mellom to utforskninger er RØD (4/4); fresh_exploration_workflow gjør den grønn (0/N) |
| S2/budsjett | Budget(max_tokens=1) på manager-agenten → BudgetExceeded ut av explore(); detach middleware på manageren → testen rød |
| C.2/runder | max_rounds=1 → BudgetExceeded(kind="exploration_rounds", limit=1, observed=1); detach oversettelsen → kjøringen «lykkes» med den kanoniske strengen → rød |
| C.3/kontrakt | ExplorationContract(max_stall_count=None) → ValidationError ved konstruksjon |
| C.5/plan review | persona-revise én gang → REPLANNED i loggen og plan_reviews == 2; max_plan_revisions=1 + persona som alltid reviderer → typet stopp, aldri evig løkke |
| C.6/frø | frø-approach id="fagperson-1" finnes i output-Mandate.approaches uansett hva manageren fant; detach bevaringen → rød |
| C.0/nivå 3 | explore() skriver ingenting til outbox/wiki: ls outbox før/etter → kun {run_id}-exploration.json; git status shared/ ren |
| U12/S4 | subprosess-resume: pending request_info re-emittert + sluttsvar; detach checkpoint_storage → rød |
| U14 | demoen under PORTFOLIO_OTEL=console → ≥1 workflow.run-span på stderr; uten variabelen → stdout byte-identisk med tests/golden/demo-transcript.stdout |
| Golden | uv run pytest -q grønn; shasum tests/golden/demo-transcript.stdout uendret |
F. Nøkkelantakelser, risiko og åpne beslutninger
Alle åtte radene er MÅLT i økt 54 (ordre 20260823T162224Z, spikes S0–S6). Måleapparatet er
spikes/e_magentic.py + tests/spikes/test_e_magentic.py (16 tester), kjørt mot orchestrations
1.0.1 på core 1.9.0; hele suiten 920 passed / 5 skipped, golden-transkriptet uendret
(ea8c534773acdbe41ae68f2c55724d69aaf8be4f).
| # | Antakelse | Test | Status |
|---|---|---|---|
| A1 | Agent-nivå ChatMiddleware fyrer på managerens kall |
S2 | MÅLT GRØNN. BudgetMiddleware på manager-agenten krediterer meteret (meter.tokens == 8 etter ett kall) og stopper kjøringen. Detach-kontroll: uten middleware fullfører SAMME 1-token-budsjett. Planens budsjettgaranti står. |
| A2 | BudgetExceeded reist inni en Magentic-deltaker propagerer ut av workflow.run |
S2 | MÅLT GRØNN, og som repoets EGEN type — ikke pakket i en ExceptionGroup: isinstance(exc, BudgetExceeded), kind="tokens", limit=1, observed=8. Trippelen kø-(y) leser er intakt, så 429-kanalen kan brukes uendret. |
| A3 | request_info-rundtur |
S3 | MÅLT GRØNN på 1.0.1. Review stopper kjøringen uten output (manageren har da kun kalt facts+plan); revise koster nøyaktig 2 manager-kall (facts_update, plan_update), null ledger-kall og null runder, og spør på nytt; approve kjører løkka til sluttsvar. Bekrefter at max_plan_revisions MÅ inn i kontrakten — ellers er en alltid-reviderende ekspert et ubundet forbruk. |
| A4 | Resume med pending plan review i NY prosess | S4 | MÅLT GRØNN. Foreldreprosessen stopper på review og etterlater checkpoints; en subprosess (spikes/e_magentic_resume.py) som aldri så kjøringen svarer fra checkpointen alene og driver workflowen til sluttsvar. Pris, ikke forutsett: FileCheckpointStorage NEKTER å deserialisere MagenticPlanReviewRequest/…Response uten at begge navngis i allowed_checkpoint_types — uten det er checkpoint-fila uleselig og listingen TOM, altså en resume som feiler som et FRAVÆR. Begge prosesser må deklarere dem. |
| A5 | AgentApprovalExecutor som deltaker gir svar midt i kjøringen |
S3b | MÅLT GRØNN — dør 3 i C.6 står. Ekspertens ord når både liaisonen og en senere manager-prompt. To rundturer per menneskesvar: from_strings([svar]) mater svaret tilbake INN i liaisonen og gjenopptar IKKE manageren (målt: null manager-kall mellom de to forespørslene); først approve() sender liaisonens output videre. Kostnad: AgentApprovalExecutor er IKKE re-eksportert fra agent_framework.orchestrations (svartypen ER det) — døra koster i dag en privat-API-import. |
| A6 | Persona-manuset kan drive en Magentic-manager (ledger-JSON) offline | S1/S3 | MÅLT GRØNN med repoets ScriptedChatClient (ikke lenger en ad-hoc FakeClient). Ett forbehold funnet: selectoren får den SAMMENSLÅTTE prompten, så ett av fem manager-kall bærer to markører — rutingen må teste senere-stadium-markøren først. Og en next_speaker som ikke matcher en deltaker gir stille sluttsvar uten at noen ble spurt (_magentic.py:1128-1131), målt da liaison-spiken først het worker. |
| A7 | Utforskning som opt-in holder demo-transkriptet byte-uendret | shasum |
MÅLT uendret gjennom hele økten (ea8c534…). |
| A8 | 1.0.1 er API-identisk med 1.0.0 | S0 | MÅLT: API-identisk, ATFERD ikke. Diffen er upstream-regresjonsfiksen #4371: StandardMagenticManager.__init__ mistet self._session = agent.create_session(), og hvert manager-kall mynter nå en engangs-sesjon. Konsekvens: E2 OG E4 er BORTE (4/4 → 0/5 begge). E1 (single-use RuntimeError, null kall) og E7 (MagenticResetSignal skriver til orphan-attributtet _agent_thread, :1369, sesjonsidentitet uendret) står. Manager-sesjonen fjernet også fra checkpoint-state, konsistent med at manageren nå er tilstandsløs per kall. |
Målt korreksjon til E-tabellen (U12/S4): kriteriet «detach checkpoint_storage → rød» er
FEIL — å fjerne checkpoint_storage= fra run() lar HELE suiten stå grønn (920 passed), fordi
.with_checkpointing(...) på builderen allerede ga workflowen lageret. De to bærende punktene er
checkpoint_id= (fjernes → rød) og builderens .with_checkpointing(...) (fjernes → rød).
Load-bearing MÅLT (mot HELE suiten, grønn kontroll 920/5): manager_keeps_persistent_session
konstant True (2 røde — E2+E4 alene) · aldri fest BudgetMiddleware på manageren (3 røde, mens
detach-armen forblir grønn) · detach markør-registreringen (1 rød — S3b-positiven alene, kontrollen
grønn) · flipp _route-rekkefølgen så pre-survey testes først (4 røde) · resume uten
checkpoint_id= (1 rød) · builder uten .with_checkpointing() (1 rød) · tom
_ALLOWED_CHECKPOINT_TYPES (1 rød) · og den falsifiserte: resume uten checkpoint_storage= (0
røde — funnet over).
S5 — quick_validate-latens: median 13,6 ms over 20 kall på bygg-energi-baseline-mikro
(forankret baseline + assumption-bånd, så stage 0 + CBC + 512-sample Monte Carlo er alle med).
Langt under 2 s-terskelen: verktøyet kan kalles fritt i løkka, og kontrakten trenger ingen
egen latens-post. Båndet er med med vilje — uten det faller _monte_carlo tilbake på
item.unit_cost, alle draw blir identiske, og tallet ville underrapportert den ekte kostnaden.
S6 — OTEL er gratis, men IKKE via enable_console_exporters. I et scratch-venv pinnet til
samme stack (core 1.9.0 / orch 1.0.1 / opentelemetry-sdk 1.44.0; ingenting lagt til
pyproject.toml) gir configure_otel_providers(enable_console_exporters=True) 2
workflow.run-spans — pluss workflow.build, executor.process, edge_group.process,
message.send, invoke_agent, chat synthetic — men de skrives til stdout, som ville
ødelagt golden-transkriptet. Med exporters=[ConsoleSpanExporter(out=sys.stderr)] kommer de 2
workflow.run-spanene på stderr og demoens stdout er byte-identisk med fasiten (samme
shasum). U14 er altså én økts arbeid — forutsatt at exporteren konstrueres eksplisitt mot stderr,
aldri via flagget.
U14 er LANDET (økt 55, ordre 20260823T165757Z-6762213199). Operatøren tok alle fire
beslutningene som anbefalt 23.08, og bekreftet samme dag at låsen på orchestrations 1.0.1 er
ENDELIG, ikke midlertidig — spike-ordrens «revert hvis E7 står» er overstyrt av den senere
beslutningen, som betinget på grønn suite (920/5, målt) og ikke på E7. Levert:
opentelemetry-sdk>=1.42,<2som DEKLARERT dependency (beslutning 2). Én ny pakke, ikke to:ConsoleSpanExporterbor inne i sdk-en.opentelemetry-apifulgte med fra 1.42.1 til 1.44.0 — målt uskadelig (goldenea8c534…uendret før og etter).src/portfolio_optimiser/tracing.py—PORTFOLIO_OTELpå truthiness, moduseneconsole(spans → stderr) ogotlp(kun mot et navngitt endepunkt),tracing_noticesom eneste renderer.- Wiret i TRE inngangspunkter:
run.main,simulation.main,hosting.main. - S6-forbeholdet er implementert som skrevet:
ConsoleSpanExporter(out=…), aldrienable_console_exporters=True. Målt: demoen underPORTFOLIO_OTEL=consolegirworkflow.run- spans på stderr og stdout BYTE-IDENTISK med fasiten; uten variabelen null spans. - To ting E-tabellen ikke forutså, begge lukket: (i) MAF bygger env-avledede OTLP-exportere
UBETINGET, så
consoleNEKTER når enOTEL_EXPORTER_OTLP_*_ENDPOINTer satt — ellers var «console» en usann påstand om hvor kjøringens innhold tok veien; (ii)enable_console_exportersfaller tilbake påENABLE_CONSOLE_EXPORTERSi miljøet, så den pinnes eksplisittFalsei begge moduser. Begge er MÅLT som defektklasser, ikke antatt. - IKKE bygget, med grunn:
PLAN_CREATED/REPLANNED/PROGRESS_LEDGER_UPDATED— de hører til sløyfa U4 bygger, og en emitter uten kallsted er en form gjettet i stedet for målt. De landes i økt 56–57, på sømmen U14 nettopp la. OTLP-exporter-PAKKENE er bevisst ikke deklarert (egress + grpc/protobuf-vekt i et publisert wheel); uttalt ærlighets-grense i README/DEPLOY/env.template.
Suite etter U14: 943 passed / 5 skipped, golden ea8c534… uendret, mypy src + ruff rene.
Beslutninger som trenger operatøren (speiles i avslutningsblokken):
- Versjon — AVGJORT 23.08: låsen står på 1.0.1, ENDELIG. Bakgrunnen: ordrens «felles hvis» sa at hvis E7 står i 1.0.1, revert til 1.0.0. E7 STÅR — men 1.0.1 fikset noe større enn det som ble håpet (E2/E4, «en plausibel fasit produsert av null arbeid»). Operatøren aksepterte 23.08 at gevinsten veier tyngre enn ordrens bokstav, og at betingelsen som gjelder er «grønn suite» (målt 920/5), ikke E7. Ikke midlertidig, og ikke å gjenåpne uten en ny måling. Bumpen til 1.1.x / core 1.15 er fortsatt en EGEN økt etter denne planen.
- U14 som deklarert avhengighet — AVGJORT 23.08: ja. Landet i økt 55; se «U14 er LANDET»
over. Kostnaden ble ÉN pakke (
opentelemetry-sdk), ikke to. - HITL — AVGJORT 23.08: synkron-først. Merk at ordrens BEGRUNNELSE er utdatert mens konklusjonen står: den sier «A4 er umålt og kun kode-lest», men A4 ble MÅLT GRØNN i økt 54, så asynkron er teknisk mulig. Valget er dermed ren rekkefølge, ikke risiko — asynkron U13 forblir pkt. 3 i rekkefølgen, betinget av S4 som nå er grønn.
- Commons-amendment «Step 0 — Explore» — AVGJORT 23.08: sendt.
.claudesendte forslaget tilportfolio-optimiser-commonsvia coord. Vi venter IKKE: planen slår selv fast at ingen amendment er påkrevd, og «Step 0» er foreslått som VALGFRI. Kommer den, er den en tilføyelse.
Vedlegg V1 — målingsskript og rå output (U1–U19)
Skript (scratchpad/u_measure.sh, kjørt 2026-08-23; kopiert hit ordrett så målingen kan gjentas):
#!/bin/bash
cd "$(git rev-parse --show-toplevel)"
SRC_N=$(find src -name '*.py' | wc -l | tr -d ' ')
TST_N=$(find tests -name '*.py' | wc -l | tr -d ' ')
SPK_N=$(find spikes -name '*.py' | wc -l | tr -d ' ')
echo "DENOMINATOR src=$SRC_N tests=$TST_N spikes=$SPK_N"
m() { s=$(grep -rEn --include='*.py' "$2" src | wc -l | tr -d ' ')
t=$(grep -rEn --include='*.py' "$2" tests | wc -l | tr -d ' ')
k=$(grep -rEn --include='*.py' "$2" spikes | wc -l | tr -d ' ')
printf "%-4s %-60s src=%-4s tests=%-4s spikes=%s\n" "$1" "$2" "$s" "$t" "$k"
[ "$s" != "0" ] && grep -rEn --include='*.py' "$2" src | head -12; }
m U1 'ConcurrentBuilder|BuildConcurrent|FanIn'
m U1b 'asyncio\.gather|create_task\('
m U2 'WorkflowBuilder|@executor|class .*\(Executor\)|WorkflowContext|SwitchCase|add_edge|add_fan_out'
m U3 'GroupChatBuilder|with_max_rounds|termination_condition|RoundRobinGroupChatManager'
m U4 'Magentic'
m U5 'SkillsProvider|McpSkillsSource|AgentSkillsProvider|agent_framework.*skills'
m U6 'MCPStdioTool|MCPStreamableHTTPTool|MCPWebsocketTool|as_mcp_server'
m U7 'FunctionTool|ai_function|@tool|tools=\['
m U8 'Middleware|middleware='
m U9 'ContextProvider|HistoryProvider|context_providers='
m U10 'AzureAISearch|azure\.search|cosmos|qdrant|redis|VectorStore|vector_store|Qdrant|Chroma|chromadb'
m U11 'AIContextProvider|TextSearchProvider|citation|SourceName|SourceLink|agentic_retrieval|KnowledgeAgent'
m U12 'checkpoint|Checkpoint'
m U13 'approval_mode|request_info|RequestInfoEvent|RequestPort|MagenticPlanReview|ApprovalRequired'
m U14 'opentelemetry|setup_observability|OBSERVABILITY|get_tracer|start_as_current_span'
m U15 'evaluate_workflow|LocalEvaluator|Evaluator|_evaluation|agent_framework.*evaluation'
m U16 'CompactionProvider|SlidingWindow'
m U17 'as_tool\(|AsAIFunction'
m U18 'FoundryChatClient'
m U19 'HarnessAgent|ShellExecutor|FileMemoryStore|ToolApprovalAgent'
Rå tellinger: DENOMINATOR src=32 tests=117 spikes=6 · U1 0/4/4 · U1b 1/5/0 · U2 0/0/0 · U3 10/7/7 ·
U4 0/4/9 · U5 0/0/0 · U5b(SKILL\.md) 1/5/0 · U6 6/6/0 · U6b(rå mcp) 7/6/0 · U7 4/10/0 · U8 16/20/0 ·
U9 8/11/4 · U10 2/19/0 · U10b(numpy/cosine) 49/102/1 · U11 26/35/0 · U12 3/0/0 · U13 3/0/0 ·
U14 0/0/1 · U15 0/0/0 · U16 0/0/0 · U17 0/0/0 · U18 7/8/0 · U19 0/0/0.
Kjent-positiv-kontroll mot installert MAF (grep -rEl <regex> agent_framework agent_framework_orchestrations | wc -l):
U2 → 21 · U5 → 3 · U14 → 4 · U15 → 2 · U16 → 4 · U17 → 1 · U19 → 1 · checkpoint_storage|CheckpointStorage
→ 14 · MagenticBuilder|StandardMagenticManager → 4.
B7-/HITL-målingsskriptene (magentic_b7.py, magentic_b7b.py, magentic_reset.py) ligger i
øktens scratchpad og porteres til spikes/e_magentic.py i økt 54 (S1/S3) — de committes ikke
herfra, fordi de bruker en ad-hoc FakeClient og ikke repoets ScriptedChatClient.
Vedlegg V2 — installert Magentic-API (orchestrations 1.0.0, _magentic.py, 1802 linjer)
- Eksport (
agent_framework_orchestrations/__init__.py:43-62):MagenticBuilder,MagenticContext,MagenticManagerBase,MagenticOrchestrator,MagenticOrchestratorEvent/…EventType,MagenticPlanReviewRequest/…Response,MagenticProgressLedger/…Item,MagenticResetSignal,StandardMagenticManager,MagenticAgentExecutor. Ikke i koden:MagenticHumanIntervention*,with_human_input_on_stall(kun docstrings). MagenticBuilder(*, participants, manager=|manager_factory=|manager_agent=|manager_agent_factory= (nøyaktig én), task_ledger_*_prompt…, progress_ledger_prompt, final_answer_prompt, max_stall_count=UNSET→3, max_reset_count=None, max_round_count=None, enable_plan_review=False, checkpoint_storage=None, output_from, intermediate_output_from)(:1396-1422). Metoder:with_plan_review(enable=True)(:1516),with_checkpointing(storage)(:1564),build()(:1772; bidireksjonale kanter orkestrator↔deltaker:1796-1797). Grensene bor på MANAGEREN (:1693-1695, lest tilbake:905/:1115/:1240);manager=+ prompt/limit-argumenter → warning og stille ignorert (:1661-1677). Ikke-agent-Executorsom deltaker aksepteres (:1498-1499) men får placeholder-beskrivelse (_base_group_chat_orchestrator.py:115).StandardMagenticManager(agent, …, max_stall_count=3, max_reset_count=None, max_round_count=None, progress_ledger_retry_count=None→3)(:528-544). ÉnAgentSessioni__init__(:572), alle kallagent.run(…, session=…)(:601). Ledger-parsing: fri tekst +_extract_json(:406-449), dataklasser ikke pydantic (:288-333).- Løkke: runde-teller ×2 (
:1075-1076), grense-sjekk FØR inkrement på_round_index(:1238); stall:1109-1118; reset:1149-1185; grense → kanonisk streng +_terminated, ingen exception (:1222-1256); sluttsvar:1206-1220; ukjentnext_speaker→ stille sluttsvar (:1128-1131); single-use-guard:914-918. - Plan review: request
:829-853(plan,current_progress,is_stalled;.approve(),.revise(feedback)), response:800-826(review: list[Message], tom = approve:1010), reises:1041-1048, svaresworkflow.run(responses={id: …})(_workflow.py:899-908; ukjent id →ValueError:946), revise-håndtering:1014-1031(ingen cap, ingen runde-telling). Per-tur-HITL viaAgentApprovalExecutor(_orchestration_request_info.py:168). - Checkpoint:
CheckpointStorage-protokoll_checkpoint.py:119,InMemoryCheckpointStorage:192,FileCheckpointStorage(storage_path, *, allowed_checkpoint_types):239;WorkflowCheckpoint.pending_request_info_events:81;run(checkpoint_id=, checkpoint_storage=)_workflow.py:701-712,responses+checkpoint_idtillatt:877; superstep-granularitet_runner.py:143-144; re-emittering_runner_context.py:414-426; Magentic-state_magentic.py:1266-1284+ manager-sesjon:746; feil svelges:1281-1282/:1320-1321. - Observability:
_magentic.py→ 0 spans. Runtime-spansworkflow.build/workflow.run/executor.process/edge_group.process/message.send(observability.py:253-276). Inngangconfigure_otel_providers(*, enable_sensitive_data, enable_console_exporters, exporters, views, vs_code_extension_port, env_file_path, env_file_encoding)(:1168),enable_instrumentation(:1132); envENABLE_INSTRUMENTATION(default True,:697),ENABLE_SENSITIVE_DATA,ENABLE_CONSOLE_EXPORTERS,OTEL_EXPORTER_OTLP_ENDPOINT/_PROTOCOL/_HEADERS,OTEL_SERVICE_NAME. Ikke re-eksportert fraagent_framework(hasattr→ False).APPLICATIONINSIGHTS_CONNECTION_STRING→ ikke funnet.opentelemetry-sdk: ikke installert. - Evals/Skills:
evaluate_workflow(*, workflow, workflow_result|queries, evaluators, …)(_evaluation.py:1833,@experimental(EVALS):1832);SkillsProvider(ContextProvider)(_skills.py:1719,@experimental(SKILLS):1718;from_paths:1861).
Vedlegg V3 — kommandoer kjørt (utvalg; fullstendige lister i øktens agent-transkripter)
find src -name '*.py' | sort | wc -l # 32
uv pip list | grep -i -E "agent.framework|^mcp |opentelemetry|azure-ai|anyio"
sed -n '61,75p' uv.lock ; grep -n "agent-framework" pyproject.toml
curl -s https://pypi.org/pypi/agent-framework-orchestrations/json # + /1.0.0 … /1.1.1/json
sed -n '1,80p' .venv/.../agent_framework/_feature_stage.py
grep -rn "@experimental|@preview|feature_stage(" .venv/.../agent_framework/*.py .../_workflows/*.py
grep -n -i "experimental|feature_stage" .venv/.../agent_framework_orchestrations/*.py # 0
bash scratchpad/u_measure.sh # V1
grep -rEl <9 null-regexer> .venv/.../agent_framework .venv/.../agent_framework_orchestrations | wc -l
grep -rn -i "research.01" STATE.md STATE-arkiv-2026-08-21.local.md docs/ # 0
grep -rn "enable_layer1_hitl|layer1" src tests ; grep -rEn 'request_info|RequestInfoEvent' tests # 0
grep -rn "agent_framework" src/portfolio_optimiser/*.py # 14 importlinjer
microsoft_docs_fetch learn.microsoft.com/en-us/agent-framework/workflows/orchestrations/magentic
uv run python scratchpad/magentic_b7.py ; … magentic_b7b.py ; … magentic_reset.py # E1–E7
.venv/bin/python -c "import opentelemetry.sdk" # ModuleNotFoundError