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
40
DEPLOY.md
40
DEPLOY.md
|
|
@ -41,7 +41,7 @@ The package has three distinct audiences. Only the first one is technical.
|
|||
|
||||
| Role | What they do | Where it is documented |
|
||||
|---|---|---|
|
||||
| **Platform operator** | Deploys the container into Microsoft Foundry, sets two environment variables, verifies with the offline preflight. One-time work. | This document, sections 3–5. |
|
||||
| **Platform operator** | Installs the package, sets two environment variables, starts the service, verifies with the offline preflight. One-time work. | This document, sections 3–6. |
|
||||
| **Ordering domain expert** (*bestiller*) | Writes the mandate file: the objective, which approaches are worth trying, and why. The *why* is the part the system cannot read out of cost figures. | `docs/bestille-en-kjoring.md` |
|
||||
| **Reviewing domain expert** (*fagperson*) | Receives a validated proposal and answers `approved` or `rejected` with a written rationale. That verdict is what the system learns from. | `docs/ekspert-svar.md` |
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ back with its reason. That property is the point of the whole design; do not bui
|
|||
your own.
|
||||
2. **Order a run** with a mandate file (optional but recommended). See
|
||||
`docs/bestille-en-kjoring.md`.
|
||||
3. **Run it** — from the CLI, or by `POST /invocations` against the deployed container (section 5).
|
||||
3. **Run it** — from the CLI, or by `POST /invocations` against the running service (section 6).
|
||||
The run navigates the knowledge base, debates candidate measures, validates the numbers against
|
||||
the project's actual cost baseline, and returns either a **validated proposal** or a
|
||||
**rejection with a reason**. A rejection is a successful run: the negative outcome belongs to the
|
||||
|
|
@ -99,8 +99,8 @@ PORTFOLIO_FOUNDRY_PROJECT_ENDPOINT # yours; wins if set
|
|||
FOUNDRY_PROJECT_ENDPOINT # injected by the Foundry hosting platform
|
||||
```
|
||||
|
||||
Inside a hosted Foundry container the platform injects the second one and you need to set nothing.
|
||||
Outside it — a laptop, a pipeline, a container you run yourself — set the first. The value looks
|
||||
Where something injects the second one for you — the Foundry hosting platform does — you need to
|
||||
set nothing. Everywhere else (a laptop, a pipeline, your own runtime) set the first. The value looks
|
||||
like `https://<resource>.services.ai.azure.com/api/projects/<project>`.
|
||||
|
||||
**5.2 The model map — this is the one that catches people.** The packaged
|
||||
|
|
@ -125,7 +125,7 @@ own file:
|
|||
export PORTFOLIO_MODEL_MAP=/path/to/model_map.json
|
||||
```
|
||||
|
||||
If you skip this, the container starts and answers `/readiness` — and fails every invocation. That
|
||||
If you skip this, the service starts and answers `/readiness` — and fails every invocation. That
|
||||
is the single most likely first-deployment failure, which is why it has its own section.
|
||||
|
||||
**5.3 Verify before you pay for a model call:**
|
||||
|
|
@ -140,24 +140,32 @@ no placeholders left. It is **necessary but not sufficient** — RBAC (403), tok
|
|||
|
||||
---
|
||||
|
||||
## 6. Deploying
|
||||
## 6. Running it
|
||||
|
||||
The image must be built for x86_64 regardless of your workstation's architecture:
|
||||
**This package is Python and nothing else.** There is no image to build and no platform-specific
|
||||
deployment manifest — that was removed deliberately after an external trial, because it forced a
|
||||
container toolchain on receivers who only needed to run the code. How the process is supervised,
|
||||
packaged or placed in your environment is your decision, and this package does not pre-empt it.
|
||||
|
||||
Install the locked environment and start the service:
|
||||
|
||||
```bash
|
||||
git archive HEAD | docker build --platform linux/amd64 -t portfolio-optimiser -
|
||||
uv sync --frozen --no-dev
|
||||
uv run python main.py
|
||||
```
|
||||
|
||||
If you unzipped this package rather than cloning it, build from the directory instead:
|
||||
`uv sync --frozen` installs the exact resolution every measurement in this repository ran against —
|
||||
never a fresh resolve, which picks other versions. Two dependencies are git-tag-pinned direct
|
||||
references, so **`git` must be on PATH** for the install to work.
|
||||
|
||||
`main.py` serves port 8088 (override with `PORT`), answers `GET /readiness`, accepts
|
||||
`POST /invocations`, and exits cleanly on SIGTERM. For a single run without the service, the CLI is
|
||||
the same code path:
|
||||
|
||||
```bash
|
||||
docker build --platform linux/amd64 -t portfolio-optimiser .
|
||||
uv run portfolio-optimiser --help
|
||||
```
|
||||
|
||||
`azure.yaml` describes the hosted-agent deployment (`azd`). The container serves port 8088 (override
|
||||
with `PORT`), answers `GET /readiness`, accepts `POST /invocations`, and shuts down cleanly on
|
||||
SIGTERM.
|
||||
|
||||
**The invocations payload** is whitelisted against the run signature — unknown fields are refused by
|
||||
name with HTTP 400, never silently ignored:
|
||||
|
||||
|
|
@ -167,7 +175,7 @@ name with HTTP 400, never silently ignored:
|
|||
| `docs_dir` | yes | Source documents. |
|
||||
| `verdict_input` | yes | The expert verdict for this run. |
|
||||
| `bundle_dir` | no | Knowledge base to navigate. |
|
||||
| `profile` | no | Defaults to `azure` in the hosted container. |
|
||||
| `profile` | no | Defaults to `azure` on this HTTP surface. |
|
||||
| `max_rounds` | no | Debate round cap. |
|
||||
| `max_tokens` | no | **Per-invocation token ceiling.** Set it. The built-in default is 100 000 tokens per run, which is a ceiling nobody chose for your workload. |
|
||||
| `top_k` | no | Retrieval breadth. |
|
||||
|
|
@ -180,7 +188,7 @@ HTTP 400 means the request was malformed; 500 means the run itself failed, with
|
|||
## 7. Honest limits
|
||||
|
||||
- **This framework has never been run against a live model in our environment.** Everything above is
|
||||
measured against tests, an offline simulation and container builds. The first live run in *your*
|
||||
measured against tests and an offline simulation. The first live run in *your*
|
||||
tenant is the first live run, full stop.
|
||||
- The system is a **technical framework**. Data protection assessments, lawful basis and risk
|
||||
ownership belong to whoever deploys it — see `README.md` and `SECURITY.md`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue