docs(readme): satisfy the repo-standard first screen

The gate flagged three real ERRORs for a standalone-class repo:

- the opening line was a licence badge, so `description == catalog ==
  README` — the one thread a machine can actually check — was broken.
  The forge description now leads, badges follow, and the paragraph
  under them stops repeating it.
- no `## Install`. Added as its own top-level heading, because that
  fixed position is what an agent handed "install this" pattern-matches
  on. It states the uv-from-source path honestly: nothing is on a
  package index, the one non-PyPI dependency resolves from its pinned
  tag, and since this forge has no CI runner the clean-clone `uv run
  pytest` IS the verification — said in as many words so the absent CI
  badge reads as a choice rather than an omission.
- no `## Non-goals`. Six, each traceable to something the repo already
  enforces: no reallocation between projects, no compliance claims, no
  network connector (`http` is rejected fail-fast), no query-time
  retrieval, not a port of the MAF sibling, not a running service.

Also links CHANGELOG.md, which the README had never pointed at.

The gate still reports 7 ERROR here. All seven are one defect in the
check, not in the repo: `checkInternalLinks` resolves targets against
the set of tracked FILES, so every `[x](dir/)` is "missing" even when
the directory is tracked and full. All seven targets verified present.
Rewriting them to point at some file inside each directory would make
the runs/s10 sentence untrue — it claims all four artifacts live there
— so the links stand and the defect went to repo-standard by coord
(20260803T194933Z, with a minimal repro).

Suite green at 711 passed; the README<->--help parity test reads this
file and still holds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gu3n2PVVnb9fZDCe2wnU1h
This commit is contained in:
Kjell Tore Guttormsen 2026-08-03 21:50:08 +02:00
commit 90ed9ee469

View file

@ -1,14 +1,15 @@
# portfolio-optimiser-claude
Claude Agent SDK sibling implementation of the portfolio-optimiser method: an open Python framework that finds cost savings inside each project in a portfolio.
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Python](https://img.shields.io/badge/python-%E2%89%A53.10-blue.svg)](pyproject.toml)
[![Built on Claude Agent SDK](https://img.shields.io/badge/built%20on-Claude%20Agent%20SDK-D97757.svg)](https://github.com/anthropics/claude-agent-sdk-python)
Sibling implementation of the portfolio-optimiser method on the **Claude Agent SDK**
(decision D7). An open, generic Python framework that finds cost savings *inside* each
project in a portfolio of independent projects: agents generate candidate measures, a
mandatory deterministic validator gates the numbers, domain experts judge via
human-in-the-loop, and the system learns from the verdicts.
The projects in the portfolio are independent, and the saving is found *inside* each of
them: agents generate candidate measures, a mandatory deterministic validator gates the
numbers, domain experts judge via human-in-the-loop, and the system learns from the
verdicts. This is the **Claude Agent SDK** implementation of that method (decision D7).
> **Status:** the D7 build (S5S10) is complete, and the deterministic **ingest layer**
> (CSV and SQL source types) has since been added in front of the loop. The deterministic
@ -22,6 +23,41 @@ human-in-the-loop, and the system learns from the verdicts.
> the legal basis for any processing. The framework ships only the technical
> preconditions: local-only operation, first-class provenance, no silent data egress.
## Install
Not published to a package index — this repo is consumed from source, with `uv`:
```bash
git clone https://git.fromaitochitta.com/open/portfolio-optimiser-claude.git
cd portfolio-optimiser-claude
uv sync
uv run pytest # the full suite, offline, no API key
```
`uv sync` resolves the one non-PyPI dependency (`llm-ingestion-okf`) from a pinned tag on
the same forge, declared in [`pyproject.toml`](pyproject.toml) — no extra index or
credentials are needed. Nothing runs the suite automatically: this forge has no CI runner,
so that one command from a clean clone is the verification, and there is no CI badge above
pretending otherwise.
## Non-goals
- **Not a portfolio reallocator.** It finds savings *inside* each project; it never moves
budget between them, and it does not rank projects against each other.
- **Not a compliance product.** The deployer owns DPIA, risk assessment, and the legal
basis for any processing (see the disclaimer above); the framework ships technical
preconditions only.
- **No network or live-source connectors.** The `http` source type is a documented
extension point that is *not* built here — a manifest naming it is rejected fail-fast,
never silently accepted.
- **No query-time retrieval over the bundle.** Data reaches the model only as a
pre-materialized OKF bundle (method-spec §3 Step 1); there is no RAG index and no
keyword chunk-stuffing.
- **Not a port of the MAF sibling.** It is built from the shared spec alone; the two
implementations exist to be compared, not to converge by copying.
- **Not a continuously running service.** Everything below the run layer is deterministic
and offline, and the programme budgeted exactly one live model run (S10, below).
## Built from the spec, not the sibling
The method itself is framework-neutral and lives in
@ -358,3 +394,7 @@ uv run mypy src # strict
The offline invariant is deliberate: everything below the run layer is pure config/file
logic, so the full suite (including every load-bearing seam proof) runs with no key and
no network.
## Changelog
See [CHANGELOG.md](CHANGELOG.md).