The version moves 1.1.0 -> 1.2.0 in every place it is written: pyproject, the package __init__, the smoke test that pins it, the README's wheel-install command (gate-pinned against the build) and uv.lock -- five sites, plus the new CHANGELOG section. A new, backward-compatible surface, no removals: fourteen run-path steps that had only ever been reachable through a path that builds a chat client now each have a command of their own. The README gains a status block at the top, and half of it is what v1 is NOT: no domain expert has validated an output, three planned rounds of expert feedback were set aside rather than passed, five of the eight kinds of feedback the design names have no typed way back into a run, and the multi-agent debate is exercised in the suite only against scripted clients. That half is the point -- a reader who installs this should learn the limits from the first screen, not from a gate they have to run themselves. Measured on this tree at this commit: suite 2238 passed / 0 failed / 5 skipped / 5 xfailed (769 s), ruff check and mypy src clean, and both gates re-run after staging and unchanged (v1 gate exit 1: 0/3 - 0/3 - 3/8 - no report - 3/8 - NOT MEASURED - 1/20; B gate exit 1: 15/17 - 0/2 - 15/15 - 0/3 - 4/5 - NOT MEASURED). No tag is created here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
135 lines
9.6 KiB
TOML
135 lines
9.6 KiB
TOML
[project]
|
||
name = "portfolio-optimiser"
|
||
version = "1.2.0"
|
||
description = "Generic framework on Microsoft Agent Framework for per-project cost-savings optimization"
|
||
readme = "README.md"
|
||
requires-python = ">=3.10"
|
||
dependencies = [
|
||
# MAF — GA-pakker, IKKE meta-pakken `agent-framework`. Metaen drar `agent-framework-core[all]`,
|
||
# og `[all]` trekker inn de fortsatt-beta integrasjonene (azure-ai-search/cosmos/ollama/…) som
|
||
# tvinger pre-releases og drar med en ALPHA pydantic. Offisiell guide: installer kun det du trenger.
|
||
# Beta-integrasjoner legges til per-fase (med snevert pre-release-scope) når de faktisk trengs.
|
||
"agent-framework-core>=1.18.0,<2", # kjerne (GA) — to-sidig pin (S2.5): major-bump krever re-verifisering av privat-API-premissene (test_maf_version_guard). F16 (12.09): løftet fra 1.16.0; 17 private/ugaranterte former, 16 sjekket mekanisk av proben, se docs/2026-09-12-f16-maf-1180.md. F15 (02.09) løftet 1.9.0→1.16.0.
|
||
# F16 (12.09): løftet 1.8.2 → 1.13.0 SAMMEN med `-openai` og `core`, og koblingen er MÅLT, ikke antatt.
|
||
# foundry 1.13.0 krever selv `core<2,>=1.17.0` OG `openai<2,>=1.14.2`, så de tre kan ikke løftes hver for
|
||
# seg. Resolveren ville BEHOLDT 1.8.2 (den krever bare `core<2,>=1.9.0`, målt) — men to av 1.17/1.18s
|
||
# BREAKING-endringer navngir core OG foundry i SAMME punkt (#7918 sequence-only middleware-inputer,
|
||
# #8127 `SecretString`), så et 1.9.0-æra foundry mot en 1.18.0 core er halvparten av en koordinert
|
||
# endring — nøyaktig «importerer fortsatt, semantikken har flyttet i stillhet»-klassen F15 § 4 målte.
|
||
"agent-framework-foundry>=1.13.0", # Azure/Foundry-profil: FoundryChatClient (GA)
|
||
"azure-identity>=1.25", # S4.1: AzureFoundryBackend passes an explicit AzureCliCredential (Foundry requires it); already transitive via foundry — promoted to a declared direct dep (zero new install weight)
|
||
"agent-framework-openai>=1.14.3", # OpenAI + OpenAI-kompatible lokale endpoints (GA) → lokal profil; F16: løftet 1.8.2 → 1.14.3 (foundry 1.13.0 krever `openai>=1.14.2`; se raden over)
|
||
# Promotert dev→core i Fase 2 (MVP-runtime, ikke lenger spike-only):
|
||
# F16 (12.09): dette gulvet STÅR på 1.1.1, og det er en MÅLING, ikke en utelatelse: 1.1.1 (2026-08-21) er
|
||
# fortsatt siste utgivelse på PyPI, så det finnes ingenting å løfte det til. Kravet `core<2,>=1.15.0` er
|
||
# tilfredsstilt av core 1.18.0. F15s formulering «de to gulvene løftes SAMMEN — det finnes ingen delvis
|
||
# bump» var sann for F15s bump; etter F16 er den MÅLT SVAKERE: core kan løftes uten at orchestrations kan.
|
||
"agent-framework-orchestrations>=1.1.1", # GA orchestration builders (GroupChat/Concurrent/Magentic)
|
||
"pulp>=2.8", # deterministisk validator-solver; PuLP bundler CBC i wheelen (R2). Installert 3.3.2.
|
||
# PuLP 4.0 vil kreve `pip install pulp[cbc]` + COIN_CMD (Fase-migrasjonsnotat).
|
||
"mcp>=1.28.0", # tynn lokal-mappe MCP-server (Step 7) — GA (resolverte 1.28.0) per Step 1-beslutning
|
||
"anyio>=4.14", # kø-(z): ingest_mcp.py bruker anyio.fail_after direkte (MCP-timeout-stien); allerede transitiv via mcp — promotert til deklarert direkte dep (zero new install weight, resolverte 4.14.0)
|
||
"pydantic>=2.11,<3", # IR/validering (B1) — eksplisitt pin til STABIL 2.x, aldri alpha
|
||
# S3.1: brute-force cosine for the hybrid verdict retriever — MAF-free, offline (D-C).
|
||
# Upper bound is <2.3, NOT <3, and it is load-bearing twice over: numpy 2.3+ requires
|
||
# Python >=3.11 (2.4+ requires >=3.12), so a wider range silently contradicts this project's
|
||
# `requires-python = ">=3.10"`; and numpy 2.3+ stubs use PEP 695 `type` statements, which
|
||
# mypy refuses to parse under `python_version = 3.10` (python/mypy#18701) — breaking
|
||
# `uv run mypy src` outright. Raise both floors together or not at all.
|
||
"numpy>=2.0,<2.3",
|
||
# Door A ingest (§4–§6) — the shared implementation of shared/ingest-spec.md, MAF-free (D7).
|
||
# NOT "zero runtime deps" since 0.4.0: llm-ingestion-guard is okf's one runtime dependency,
|
||
# and okf >=0.8.5 declares `>=1.2,<2.0` for it. That is why the two lines below move together.
|
||
"llm-ingestion-okf",
|
||
"llm-ingestion-guard",
|
||
# U14 (økt 55, operatørbeslutning 23.08): the tracing seam's ONE new runtime dependency.
|
||
# `opentelemetry-api` was already here transitively via agent-framework-core, but the SDK is
|
||
# what `configure_otel_providers()` needs — without it MAF raises ModuleNotFoundError, so the
|
||
# seam cannot land as an opt-in without declaring it. The console exporter this framework uses
|
||
# (`opentelemetry.sdk.trace.export.ConsoleSpanExporter`) ships INSIDE this package, so console
|
||
# mode costs exactly one declaration. The OTLP exporter packages are deliberately NOT declared:
|
||
# they are egress, they drag grpc/protobuf into a published wheel, and MAF already raises a
|
||
# named ImportError telling the operator which one to install. Stated honesty limit, not an
|
||
# oversight — see tracing.py.
|
||
"opentelemetry-sdk>=1.42,<2",
|
||
# Door A content gate — scans materialized concepts before they reach the bundle; zero runtime deps, MAF-free (D7)
|
||
]
|
||
|
||
# Console entry points — the install surface a fresh clone gets from `uv sync` (P4 pkt. 5).
|
||
# Deliberately TWO, not five: `run` is the framework CLI (three documented modes) and `simulation`
|
||
# is the offline end-to-end proof the README points a newcomer at. `costsim` / `hitl` / `preflight`
|
||
# keep the `python -m` form — they are operator utilities, not the product's front door, and every
|
||
# name here is a name the freeze has to carry. Pinned by tests/test_console_entry_points.py.
|
||
[project.scripts]
|
||
portfolio-optimiser = "portfolio_optimiser.run:main"
|
||
portfolio-optimiser-demo = "portfolio_optimiser.simulation:main"
|
||
portfolio-optimiser-toolbox = "portfolio_optimiser.toolbox:main"
|
||
|
||
# Distribution channel for the shared ingest library (mirrors portfolio-optimiser-claude,
|
||
# verified in consumer CI): git pin against the public Forgejo repo — reproducible for every
|
||
# consumer, uv.lock pins the exact commit behind the tag. Bump the rev on a new library tag.
|
||
[tool.uv.sources]
|
||
llm-ingestion-okf = { git = "https://git.fromaitochitta.com/open/llm-ingestion-okf.git", rev = "v0.8.5" }
|
||
# Pinned to a TAG, never a floating ref — a security component whose version can move under a
|
||
# `uv sync` is a gate that can stop gating without a local diff (the okf `generated`-literal
|
||
# lesson, measured 2026-08-09). Bumping this is a decision, not maintenance.
|
||
# `tag =`, never `rev =`, and never a lower 1.x: okf >=0.8.5 pins this library itself via its own
|
||
# [tool.uv.sources] `tag = "v1.4.0"`, and uv treats `rev = "v1.4.0"` as a DIFFERENT url from
|
||
# `tag = "v1.4.0"` at the same value — both spellings were measured to fail resolution as
|
||
# "conflicting URLs" (P13 § 2a). The declared floor okf asks for is >=1.2, but 1.2.0 is not
|
||
# choosable for the same reason.
|
||
llm-ingestion-guard = { git = "https://git.fromaitochitta.com/open/llm-ingestion-pipeline-security.git", tag = "v1.4.0" }
|
||
|
||
# Dev tooling as a PEP 735 dependency-group (uv includes it by default in `uv sync`/`uv run`),
|
||
# so the documented bare `uv sync` + `uv run pytest` workflow installs it without `--extra`.
|
||
#
|
||
# INTENTIONAL, RECORDED DEVIATION (Fase 2 review F4): the original plan Step 1 authorized only
|
||
# moving `agent-framework-orchestrations` + `pulp` from the dev extra into core. Migrating the
|
||
# dev group from `[project.optional-dependencies]` to this PEP 735 `[dependency-groups]` block
|
||
# went beyond that stated scope, but is KEPT (not reverted) because it is what makes the brief's
|
||
# Success Criterion SC1 ("bare `uv sync` + `uv run pytest`") install dev tooling without
|
||
# `--extra` — reverting would break SC1. Logged here so the deviation is no longer silent.
|
||
[dependency-groups]
|
||
dev = [
|
||
"pytest>=8",
|
||
"ruff>=0.6",
|
||
"mypy>=1.11",
|
||
"pytest-asyncio>=0.24", # MAF orchestrations are async (await workflow.run(...)) — test-only
|
||
]
|
||
|
||
[build-system]
|
||
requires = ["hatchling"]
|
||
build-backend = "hatchling.build"
|
||
|
||
[tool.hatch.build.targets.wheel]
|
||
packages = ["src/portfolio_optimiser"]
|
||
|
||
# Fase 4a: the wheel CARRIES shared/ (spec, persona skill, example bundles) as packaged data —
|
||
# a byte-identical mirror under portfolio_optimiser/_shared/, resolved by shared_root() only when
|
||
# no working tree is present (checkout wins; PORTFOLIO_SHARED_ROOT wins over both). This is what
|
||
# makes an installed wheel — and a container — work without a clone, while shared/ itself stays a
|
||
# pull-only subtree at the repo root. Pinned by tests/test_shared_packaged_data_loadbearing.py.
|
||
[tool.hatch.build.targets.wheel.force-include]
|
||
"shared" = "portfolio_optimiser/_shared"
|
||
|
||
[tool.ruff]
|
||
line-length = 100
|
||
src = ["src", "tests", "spikes"]
|
||
|
||
[tool.pytest.ini_options]
|
||
pythonpath = ["src", "."]
|
||
testpaths = ["tests"]
|
||
asyncio_mode = "auto"
|
||
|
||
[tool.mypy]
|
||
python_version = "3.10"
|
||
|
||
# Third-party libs without bundled type stubs (py.typed) — analysed as untyped, not errors.
|
||
[[tool.mypy.overrides]]
|
||
module = ["pulp.*", "agent_framework_foundry.*", "llm_ingestion_guard.*"]
|
||
ignore_missing_imports = true
|
||
# NOTE on `llm_ingestion_guard`: the override alone would make the seam type-BLIND, not
|
||
# type-safe — every symbol arrives as `Any`, so a field rename upstream would type-check
|
||
# happily and fail at runtime. `ingest.materialize_gated` therefore coerces each value it
|
||
# reads off the guard's result objects to a concrete type at the boundary (the okf precedent),
|
||
# and the seam's behaviour is pinned by tests/test_ingest_content_gate_loadbearing.py.
|