feat(5): overleveringspakka er KUN kjørbar Python — container-innpakningen fjernet
Operatørdirektiv 14.08 etter ekstern test: mottakeren skal få kjørbar Python, ikke en Docker-innpakking. `Dockerfile` og `azure.yaml` er SLETTET fra treet. Sømmen er valgt av den eksisterende invarianten, ikke av smak: pakka ER `git archive HEAD`, så å ekskludere filene fra arkivet ville krevd en kurerings-mekanisme — den andre kopien av «hva mottakeren får», fri til å drifte fra HEAD (kø-(p)). Fjerning holder arkivet ukurert og gjør fraværet til en egenskap ved HEAD, som er det eneste en gate kan måle. De to gatene som pinnet flaten er håndtert bevisst: - 4e-rå-tekst-gaten (`--platform linux/amd64` + ÉN kopi av startkommandoen) er SLETTET, med et notat der den sto. En gate som pinner en fjernet flate kan bare bli grønn. - handover-gatens `_REQUIRED_MEMBERS` er ikke bare fratatt de to navnene, men erstattet av en POSITIV fraværs-assert pluss en dokument-gate. Å kun slutte å KREVE dem ville gitt en gate som ikke kan skille «fjernet» fra «shippes fortsatt». Startkommandoen har nå ÉN kopi igjen: DEPLOY.md-ens `python main.py`, som navngir inngangen subprosess-testen faktisk kjører.
This commit is contained in:
parent
642ce8ae9a
commit
605c02aa62
10 changed files with 215 additions and 205 deletions
51
README.md
51
README.md
|
|
@ -459,35 +459,38 @@ only an expert has:
|
|||
- **Vendor-neutral knowledge** — the same bundles drive two different agent stacks; switching
|
||||
frameworks does not orphan the organization's curated knowledge.
|
||||
|
||||
## Hosted on Foundry Agent Service
|
||||
## The task API — runnable Python, no wrapper
|
||||
|
||||
The repo ships the three files a hosted-agent deployment needs. All three are measured —
|
||||
schema-validated and container-built — but an actual `azd` deploy has **not** been run; that
|
||||
step is the operator's.
|
||||
`main.py` is the ONE process entry. It serves the hosted-agent runtime contract (port 8088 /
|
||||
`PORT`, `GET /readiness`, `POST /invocations`, clean SIGTERM exit) from
|
||||
`portfolio_optimiser.hosting`, wrapping `run_project` — never `Workflow.as_agent()`, which
|
||||
would bypass the deterministic validator and the rest of the gate chain. No protocol library
|
||||
is used: the prerelease `agent-framework-foundry-hosting` requires
|
||||
`agent-framework-core>=1.13.0` while this tree locks 1.9.0, so the contract is a small
|
||||
stdlib-asyncio server instead (single event loop, no threads — the same concurrency model as
|
||||
the portfolio waves).
|
||||
|
||||
- `main.py` — the ONE process entry. It serves the hosted-agent runtime contract (port 8088 /
|
||||
`PORT`, `GET /readiness`, `POST /invocations`, clean SIGTERM exit) from
|
||||
`portfolio_optimiser.hosting`, wrapping `run_project` — never `Workflow.as_agent()`, which
|
||||
would bypass the deterministic validator and the rest of the gate chain. No protocol library
|
||||
is used: the prerelease `agent-framework-foundry-hosting` requires
|
||||
`agent-framework-core>=1.13.0` while this tree locks 1.9.0, so the contract is a small
|
||||
stdlib-asyncio server instead (single event loop, no threads — the same concurrency model as
|
||||
the portfolio waves).
|
||||
- `Dockerfile` — `python:3.12-slim-bookworm` + git (the two security components are
|
||||
git-tag-pinned direct references; wheel metadata alone cannot install them) +
|
||||
`uv sync --frozen --no-dev` (the exact locked resolution every measurement ran against).
|
||||
Build it the way a stranger would:
|
||||
`git archive HEAD | docker build --platform linux/amd64 -t portfolio-optimiser -`
|
||||
- `azure.yaml` — closed against the two authoritative JSON schemas (see
|
||||
`docs/2026-08-13-fase4-azure-yaml-valg.md`): `language: docker`, invocations protocol pinned
|
||||
to `2.0.0`, no `env:` block (the platform injects `FOUNDRY_PROJECT_ENDPOINT`; model choice is
|
||||
config, not environment), no `startupCommand` (the image `CMD` is the one copy).
|
||||
```bash
|
||||
uv sync --frozen --no-dev # the exact locked resolution every measurement ran against
|
||||
uv run python main.py # serves the task API
|
||||
```
|
||||
|
||||
`git` must be on PATH for the install: two dependencies are git-tag-pinned direct references,
|
||||
and wheel metadata alone cannot fetch them.
|
||||
|
||||
A `Dockerfile` and an `azure.yaml` shipped here until **14 August 2026** and were removed on an
|
||||
operator directive after an external trial: what is delivered is runnable Python, and how the
|
||||
process is containerised, supervised or deployed belongs to whoever runs it. Git history keeps
|
||||
both files. The raw-text gate that pinned them (`--platform linux/amd64`, one copy of the start
|
||||
command) was **deleted with them** rather than weakened into a check that could only pass — the
|
||||
start command now has exactly one copy, in [`DEPLOY.md`](DEPLOY.md), and
|
||||
`tests/test_handover_package_loadbearing.py` is what keeps it there.
|
||||
|
||||
An invocation is a JSON object whitelisted onto `run_project`'s signature — `project_id`,
|
||||
`docs_dir` and `verdict_input` required; `bundle_dir`, `profile`, `max_rounds`, `max_tokens`
|
||||
and `top_k` optional. Unknown fields are refused by name (400), never silently dropped.
|
||||
`profile` defaults to `azure` on this surface: the AZURE profile reads its endpoint and
|
||||
credential from the environment at call time, so the same image runs hosted (managed identity)
|
||||
credential from the environment at call time, so the same process runs hosted (managed identity)
|
||||
and locally (`az login`) without rewiring.
|
||||
|
||||
### Handing it to someone else
|
||||
|
|
@ -499,8 +502,8 @@ cloning this repository or having an account here:
|
|||
scripts/make-handover-package.sh # → dist/portfolio-optimiser-foundry-<version>.zip
|
||||
```
|
||||
|
||||
The archive is `git archive HEAD` — tracked files only, which is the same tree the measured docker
|
||||
build context uses, and the reason local-only files cannot enter it. [`DEPLOY.md`](DEPLOY.md) rides
|
||||
The archive is `git archive HEAD` — tracked files only, which is why local-only files cannot enter
|
||||
it and why nothing curates what a receiver sees. [`DEPLOY.md`](DEPLOY.md) rides
|
||||
along inside it and answers the receiver's first questions: what the three roles do, what the
|
||||
process is end to end, why there is no chat interface, and the two environment variables that decide
|
||||
whether the first deployment works. Gated by `tests/test_handover_package_loadbearing.py`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue