Endepunktet løses som første ikke-tomme av vårt eget PORTFOLIO_FOUNDRY_PROJECT_ENDPOINT og Foundrys injiserte FOUNDRY_PROJECT_ENDPOINT — vårt vinner, fallbacken lar samme image kjøre hostet uten ekstra wiring. Presedensen gjelder verdier, ikke deklarasjoner. Credential velges av samme miljø: AzureCliCredential lokalt, ManagedIdentityCredential når FOUNDRY_HOSTING_ENVIRONMENT er satt, fordi containeren ikke har noen Azure CLI. Ikke DefaultAzureCredential — Learns MAF-veiledning navngir den spesifikke credentialen for å unngå probing. Load-bearing målt mot hele suiten, fire mutasjoner alle røde + grønn kontroll: detach credential-valget · presence i stedet for truthiness · detach fallbacken · snu presedensen. Fail-fast-testen var vakuøs først — vårt variabelnavn inneholder det injiserte som delstreng. De fire åpne azure.yaml-valgene lukket mot de to JSON-skjemaene og ført i docs/2026-08-13-fase4-azure-yaml-valg.md. Ingen azure.yaml skrevet (4d). 821 passed / 4 skipped. Ruff + format + mypy rene. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jk8tauXXAojNKC7Tzq7ziF
6.7 KiB
Fase 4· — de fire åpne azure.yaml-valgene, lukket mot skjemaet
Dato: 2026-08-13 · Metode: de to autoritative JSON-skjemaene hentet og lest, ikke referert
fra Learn-prosa · Status: beslutninger, ingen fil skrevet. azure.yaml skrives i 4d.
Spiken (docs/2026-08-13-fase4-research-spike.md) etterlot fire valg under «Ikke verifisert», med
begrunnelsen at Learn og Microsofts eget sample er uenige og at autoriteten —
schemas/v1.0/azure.yaml.json — ikke var lest. Den er lest nå.
0. Funnet som endrer hvordan de andre skal leses
Skjemaet er PERMISSIVT, og kan derfor ikke avgjøre tre av de fire valgene. Målt:
| Felt | Hva skjemaet faktisk sier |
|---|---|
host |
type: string, ingen enum — kun examples, der azure.ai.agent står |
language |
type: string, ingen enum — examples inneholder BÅDE python og docker |
| service-objektet | additionalProperties: **true** |
Et ukjent felt blir altså ikke avvist — det blir ignorert. Å skrive environmentVariables: ville
ikke gitt en valideringsfeil; det ville gitt en fil som ser konfigurert ut og ikke er det. Det er en
skarpere failure-mode enn den planen fryktet, og den er grunnen til at «samplet er fasit» ikke er
godt nok som regel her.
Den ekte autoriteten lå ett hopp videre. azure.yaml.json delegerer agent-formen via $ref:
"if": { "properties": { "host": { "const": "azure.ai.agent" } } },
"then": { "required": ["project"],
"allOf": [ { "$ref": ".../extensions/azure.ai.agents/schemas/azure.ai.agent.json" } ],
"properties": { "config": { "deprecated": true, ... },
"k8s": false, "apiVersion": false, "network": false } }
Hentet: azure.ai.agent.json (http 200, 16 385 bytes). Den bærer kind, protocols,
codeConfiguration, container, startupCommand — feltene Learn omtaler, og som hovedskjemaet
ikke kjenner. To ting følger direkte: project er påkrevd for en hosted agent, og
config: er deprekert (agent-innstillingene er flyttet opp på service-nivå).
1. Protokollversjon: 2.0.0
Skjemaet lukker ikke valget, men det avgrenser det. ProtocolVersionRecord:
{"properties": {"protocol": {"type": "string"}, "version": {"type": "string"}},
"required": ["protocol"], "additionalProperties": false}
version er en fri streng uten enum og uten default, og er valgfri. Valget er altså vårt,
og det er et valg mellom å pinne og å la plattformen bestemme.
Vi pinner 2.0.0, uttalt. Grunnen er ikke at skjemaet sier det — det gjør det ikke — men at
spikens §1.5 dokumenterer headere (x-agent-user-id, x-agent-foundry-call-id, og en gateway som
dropper alt utenfor en allowlist) som er egenskaper ved 2.0.0. Kjører plattformen oss under en
annen versjon enn den vi har lest kontrakten for, brytes antakelsene stille. Learn oppgir dessuten
at 1.0.0 er deprekert med blokkering etter fristen. En utelatt versjon ville gjort dette til noe vi
oppdager i drift; en pinnet gjør det til noe vi ser i diffen.
Skrives som protocols: [{protocol: invocations, version: "2.0.0"}] — Invocations, ikke
Responses, som spikens §5 allerede avgjorde: run_project er ett kall med strukturert inn og ut,
ikke en samtale.
2. Miljøvariabler: env:-map — dette lukkes AV skjemaet
MÅLT, i begge filer: grep -c environmentVariables → 0 og 0. Ordet finnes ikke i noen av dem.
env derimot er en deklarert service-property:
{"type": "object", "title": "Environment variables for the service",
"description": "Optional. A map of environment variable names to values.
Supports environment variable substitution.", "additionalProperties": {"type": "string"}}
env: er den eneste formen skjemaet kjenner. environmentVariables: er ikke ulovlig (jf. §0),
men ingenting validerer den og ingenting leser den. Dette er det ene av de fire valgene som er
avgjort av autoriteten selv, ikke av vår vurdering.
Konsekvens for innholdet: FOUNDRY_PROJECT_ENDPOINT skal ikke redeklareres (spiken pkt. 2 —
det risikerer å skygge plattformens egen verdi). Modelldeployment-navnet må derimot deklareres, det
injiseres ikke.
3. language: docker — ikke python
Skjemaet tillater begge (ingen enum). Men azure.ai.agent.json gjør dem til to gjensidig
utelukkende deploy-modi, og sier det rett ut i CodeConfiguration:
«Code deploy configuration. When present, the agent is deployed from source (ZIP) instead of a container image.» — påkrevd:
runtime+entryPoint;dependencyResolutionerbundledellerremote_build.
Vi velger container, og grunnen er vår egen avhengighetsform: de to sikkerhetskomponentene er
git-pinnet via [tool.uv.sources], ikke publisert på PyPI (spikens §3 og §7.2). En
source-ZIP-deploy overlater resolusjonen til en byggetjeneste vi ikke kontrollerer og som må nå
git.fromaitochitta.com — og den formen bærer heller ikke git i base-imaget, som spikens §3
målte at pip-veien trenger. Vår Dockerfile er nettopp det stedet den kunnskapen kan bo.
Altså: language: docker, ingen codeConfiguration. entryPoint-uenigheten i spikens tabell
(main.py vs ["python", "main.py"]) faller bort med den — feltet tilhører kun ZIP-modusen, og er
type: string, ikke en liste, i skjemaet.
4. Wrapper-form: IKKE avgjort her — og det er en måling, ikke en utsettelse
Skjemaet har ingenting å si om dette; det er et kodespørsmål. Men det ene alternativet er MÅLT utilgjengelig i dag:
agent_framework_foundry_hosting -> ModuleNotFoundError
agent_framework.foundry -> IMPORT OK, 27 eksporter, 0 med "Host"/"Server" i navnet
agent_framework_foundry -> 1.8.2, 0 host-klasser
InvocationsHostServer finnes altså ikke i det installerte treet, og pakka som skal bære den har
ingen stabil release (spikens pkt. 8). Valget kan ikke tas før pakka er installert og målt, og
det hører uansett til 4c — som spikens §5 allerede har vist er et signaturproblem
(run_project tar project_id + to påkrevde keyword-argumenter og gir en frozen RunResult),
ikke et grafproblem. Ført videre som åpent, med en kjørbar grunn.
Sidefunn, ikke handlet på
agent_framework.foundry eksporterer AnthropicFoundryClient og RawAnthropicFoundryClient.
STATEs 1b-blokk slår fast at FoundryChatClient ikke kan binde en Claude-deployment fordi Claude på
Foundry er en tredje klientflate (/anthropic/v1/messages, målt 13.08). Det står ved lag — men MAF
ser altså ut til å shippe en egen klient for nettopp den flaten. Det endrer potensielt 1b-valget
«Microsoft-solgt modell → ren konfig», og bør måles før 1b, ikke under. Ikke verifisert: at
klassen faktisk virker mot en Claude-deployment, og at den komponerer med backends.py-sømmen.