chore(release): v1.2.0 -- the toolbox surface, and a status block that says what it is not

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>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-20 11:33:22 +02:00
commit d8541d583f
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
6 changed files with 60 additions and 5 deletions

View file

@ -5,6 +5,37 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.2.0] - 2026-09-20
The release that opens the run path to callers who are not this framework. Every path through the
CLI builds a debate, and therefore a chat client; the steps the debate is built *on* need no model
at all, and this release gives each of them a command of its own.
### Added
- `portfolio-optimiser-toolbox` (`portfolio_optimiser.toolbox`), a third console command beside the
CLI and the offline demo. Fourteen subcommands, each a thin adapter over the function the run
path itself calls, never a second implementation: `navigate-bundle`, `cost-baseline`,
`retrieve-chunks`, `prepass-admit`, `validate-proposal`, `verdict-key`, `capture-verdict`,
`write-run-config`, `write-coverage`, `write-outbox`, `write-prepass`, `write-parse-failures`,
`write-proposal-reviews` and `write-debate-tools`. No model call and no network on any of them;
JSON on stdout; exit `0` the step ran, `2` the call was malformed, `3` the step refused and the
refusal is named. A proposal the deterministic validator blocks is also `3`, and carries the
verbatim reason and the stage rather than an exception envelope.
- The outcome an outbox records is **derived**, never supplied by the caller: `write-outbox` runs
the proposal through the same blocking gate the run path uses, because a door that accepted the
outcome as an argument would let anyone author an outbox of assertions. The outbox directory is
always the caller's to name, and `--stop-reason` is required - "finished" and "never found out"
are different runs.
- A measurement gate for the whole surface (`python -m portfolio_optimiser.evals.b_gate`): which
run-path steps are callable from outside, proved by a probe that executes the door and asserts on
data that came back from it. Fifteen of seventeen steps at this release; the round binder and its
report share one module entry point without a subcommand that tells them apart.
### Changed
- Console entry points are pinned against the **installed** distribution's metadata rather than
against `pyproject.toml`: a `[project.scripts]` line that has never been installed is a claim,
not a command.
## [1.1.0] - 2026-08-14 ## [1.1.0] - 2026-08-14
The release that makes the distribution stand on its own. `1.0.0` shipped a framework that could The release that makes the distribution stand on its own. `1.0.0` shipped a framework that could

View file

@ -23,8 +23,32 @@ review, test and judgement before anything ships.*
A short visual introduction — 12 slides, in Norwegian, for a general audience — ships with the A short visual introduction — 12 slides, in Norwegian, for a general audience — ships with the
repo: open [docs/kort-presentasjon.html](docs/kort-presentasjon.html) in any browser. repo: open [docs/kort-presentasjon.html](docs/kort-presentasjon.html) in any browser.
## Status - v1.2.0
**What v1 is.** The whole chain runs offline, end to end (`portfolio-optimiser-demo`), and the
run-path steps the chain is built on are callable from outside the framework as plain commands with
no model on the path - fifteen of seventeen, measured. `portfolio-optimiser-toolbox` exposes
`navigate-bundle`, `cost-baseline`, `retrieve-chunks`, `prepass-admit`, `validate-proposal`,
`verdict-key`, `capture-verdict`, `write-run-config`, `write-coverage`, `write-outbox`,
`write-prepass`, `write-parse-failures`, `write-proposal-reviews` and `write-debate-tools`; the v1
gate runs as `python -m portfolio_optimiser.evals.v1_gate`. A proposal authored outside the
framework therefore meets the same blocking deterministic validator, the same rejection stages and
the same `verdict_id` minting as one a debate produced. The two steps without a command of their
own are the round binder and its report, reachable only through
`python -m portfolio_optimiser.evals.round_builder`.
**What v1 is not.** No domain expert has validated an output of this framework. Three planned
rounds of expert feedback on a real cost report were set aside rather than passed, so every number
the system has produced has been judged by its own deterministic gate and by no one else. Of the
eight kinds of expert feedback the design names, three have a typed way back into a run - a
correction, a change of angle, and MCP tools - and the other five do not. The multi-agent debate is
exercised in the test suite only against scripted chat clients; the arms that call a real endpoint
are opt-in and skipped by default. What the suite proves about the debate is that the contract
holds, not that the model reasons well.
## Table of Contents ## Table of Contents
- [Status - v1.2.0](#status---v120)
- [Install](#install) - [Install](#install)
- [Walk the whole chain offline](#walk-the-whole-chain-offline) - [Walk the whole chain offline](#walk-the-whole-chain-offline)
- [Non-goals](#non-goals) - [Non-goals](#non-goals)
@ -63,7 +87,7 @@ that does not travel with wheel metadata — so the wheel names `llm-ingestion-o
alongside the wheel (measured: 65 packages, exit 0): alongside the wheel (measured: 65 packages, exit 0):
```bash ```bash
uv pip install portfolio_optimiser-1.1.0-py3-none-any.whl \ uv pip install portfolio_optimiser-1.2.0-py3-none-any.whl \
"llm-ingestion-okf @ git+https://git.fromaitochitta.com/open/llm-ingestion-okf.git@v0.3.2" \ "llm-ingestion-okf @ git+https://git.fromaitochitta.com/open/llm-ingestion-okf.git@v0.3.2" \
"llm-ingestion-guard @ git+https://git.fromaitochitta.com/open/llm-ingestion-pipeline-security.git@v0.3.4" "llm-ingestion-guard @ git+https://git.fromaitochitta.com/open/llm-ingestion-pipeline-security.git@v0.3.4"
``` ```

View file

@ -1,6 +1,6 @@
[project] [project]
name = "portfolio-optimiser" name = "portfolio-optimiser"
version = "1.1.0" version = "1.2.0"
description = "Generic framework on Microsoft Agent Framework for per-project cost-savings optimization" description = "Generic framework on Microsoft Agent Framework for per-project cost-savings optimization"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"

View file

@ -26,7 +26,7 @@ from portfolio_optimiser.run import (
run_project, run_project,
) )
__version__ = "1.1.0" __version__ = "1.2.0"
__all__ = [ __all__ = [
# Portfolio orchestration # Portfolio orchestration

View file

@ -2,4 +2,4 @@ from portfolio_optimiser import __version__
def test_version(): def test_version():
assert __version__ == "1.1.0" assert __version__ == "1.2.0"

2
uv.lock generated
View file

@ -1575,7 +1575,7 @@ wheels = [
[[package]] [[package]]
name = "portfolio-optimiser" name = "portfolio-optimiser"
version = "1.1.0" version = "1.2.0"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "agent-framework-core" }, { name = "agent-framework-core" },