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
125 lines
6.7 KiB
Markdown
125 lines
6.7 KiB
Markdown
# 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`:
|
|
|
|
```json
|
|
{"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:
|
|
|
|
```json
|
|
{"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`; `dependencyResolution` er
|
|
> `bundled` eller `remote_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.
|