portfolio-optimiser/pyproject.toml
Kjell Tore Guttormsen a41272def5 chore(release): 1.0.0 version sync + the six undocumented feat commits, tag deliberately withheld
Version 1.0.0 across the four sites that carry it — pyproject.toml, __init__.py,
uv.lock, test_smoke.py. Measured that these are the only four: README carries no
version badge, and CHANGELOG's `## [0.1.0]` is history rather than a bump site.

The heading stays `[Unreleased]`. STATE authorises the CHANGELOG CONTENT now and
holds the TAG until after Wednesday's freeze, so stamping `## [1.0.0] - <date>`
today would be a future-dated claim about an event that has not happened — and
one to rewrite if the dress rehearsal fails or the freeze slips. `pyproject` at
1.0.0 with `[Unreleased]` populated is the release-prep state, not an
inconsistency; nothing machine-reads the CHANGELOG (measured). The global
versjonssync rule is read as CONTENT, not heading. Tag day is then one atomic
move: rename the heading, stamp the date, tag.

The re-lock was the hazard, and it was gated rather than assumed. Bumping the
version stales `uv.lock`, and the next `uv run` would have re-locked it
invisibly against a RANGE dependency (`agent-framework-core>=1.9.0,<2`) — while
the two ExperimentalWarning lines are pinned byte-for-byte in the stderr golden,
and STATE's own okf note records that a bare sync is enough for a guard to stop
guarding with no local diff. So: bump, then `uv lock` EXPLICITLY, then diff
before any test ran. The diff is the single `portfolio-optimiser` version line;
agent-framework-core, llm-ingestion-okf (v0.3.2) and llm-ingestion-guard
(v0.3.4) are untouched, and uv.lock was re-checked AFTER the suite to confirm no
silent re-lock.

CHANGELOG prose for the six feat commits `[Unreleased]` did not cover — it
carried only Step 5 and the scripted registry. Console entry points and the
golden transcript are Added; the Step-7 inbox, the anchored walkthrough, the
stderr damping and the derived provenance sentence are Changed, scoped as the
OFFLINE SIMULATION rather than framework runtime, since they change what the
walkthrough exercises and not the library's behaviour. The content gate is
Security, and carries its opt-in qualifier: `materialize` stays ungated by
design and `materialize_gated` is asked for by name — an entry claiming "ingest
now scans content before writing" without that clause would overclaim, and it
sits next to the sentence read on stage Thursday. A Notes line names the two
open boundaries (ingest stamp spec divergence, D7 mirroring) so 1.0.0 reads as a
stable surface rather than a finished programme.

Measured, not asserted: 810 passed / 4 skipped unchanged · ruff + mypy clean (31
source files) · no `0.1.0` remaining outside .venv/shared · and the demo RUN, not
just tested — stdout byte-identical to tests/golden/demo-transcript.stdout, exit
0, 61 stdout / 4 stderr lines, matching dress rehearsal nr. 0. The version string
appears nowhere in either golden (0 hits), so the bump could not move the fasit.

Two STATE premises corrected by measurement: 24 commits since v0.1.0, not 23;
and eight feat commits exist since the tag, of which six were undocumented.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ue1AnPZYsC9Tk7e5Tyv8Fv
2026-08-10 04:46:39 +02:00

97 lines
6.3 KiB
TOML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[project]
name = "portfolio-optimiser"
version = "1.0.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.9.0,<2", # kjerne (GA) — to-sidig pin (S2.5): major-bump krever re-verifisering av privat-API-premissene (test_maf_version_guard)
"agent-framework-foundry>=1.8.2", # 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.8.2", # OpenAI + OpenAI-kompatible lokale endpoints (GA) → lokal profil
# Promotert dev→core i Fase 2 (MVP-runtime, ikke lenger spike-only):
"agent-framework-orchestrations>=1.0.0", # GA orchestration builders (GroupChat/Concurrent/Magentic); resolves med core 1.9.0
"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",
"llm-ingestion-okf", # Door A ingest (§4§6) — the shared implementation of shared/ingest-spec.md; zero runtime deps, MAF-free (D7)
"llm-ingestion-guard", # 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"
# 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.3.2" }
# 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.
llm-ingestion-guard = { git = "https://git.fromaitochitta.com/open/llm-ingestion-pipeline-security.git", rev = "v0.3.4" }
# 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"]
[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.