docs(s31): close the review's honesty gap — narrow semantic claims to the shipped mechanism

This commit is contained in:
Kjell Tore Guttormsen 2026-07-25 13:00:13 +02:00
commit 9e149c6847
5 changed files with 81 additions and 36 deletions

View file

@ -122,14 +122,24 @@ when the seam is detached, so the loop cannot silently degrade into theater.
uv run python -m portfolio_optimiser.run --report --ledger ledger.json
```
`--semantic-retrieval` (S3.1) is an **opt-in** ranking change, valid in both run modes and
**off by default**. Off, prior verdicts are ranked exactly as before: a structural score over
the affected cost-code set, measure type and magnitude bucket, with surface text deliberately
excluded. On, that score is blended with brute-force cosine over embedded features, so a
semantically related prior verdict carrying a *different* code set can also reach the
hypothesis prompt. Since an embedder sees the proposal text, turning the flag on is a
deliberate, gated reversal of the text-excluded default — which is why it is a flag and not a
new default. Nothing about a flag-off run changes, and no savings claim depends on it.
`--semantic-retrieval` (S3.1) is an **opt-in** ranking change, **off by default**. Off, prior
verdicts are ranked exactly as before: a structural score over the affected cost-code set,
measure type and magnitude bucket, with surface text deliberately excluded. On, that score is
blended with a cosine term over the *same* structural triple, which lets a prior verdict on a
*different* cost-code set outrank one that ties structurally.
**What this ships is the seam, not better retrieval.** The bundled `FakeEmbedder` is a
deterministic sha256 projection carrying no semantics, so over a structural tie the resulting
order is deterministic but arbitrary. Retrieval *quality* depends entirely on injecting a real
embedder — `--embedder-config` selects one from a closed registry (never an import path; a
config file can never name arbitrary code to load), and `docs/extending.md` documents the
`Embedder` protocol. The embedding excludes `description`, matching the structural score and the
verdict-id hash, so a flag-on run reads no surface text either.
The flag is accepted in both run modes, but in single-project mode it **requires** `--bundle-dir`
and `--verdict-dir`: without them it cannot take effect, and the run is refused rather than
silently ignoring the flag. Nothing about a flag-off run changes, and no savings claim depends
on it.
The **prior-verdict fold — the learning step — happens only on the `--bundle-dir` path**; a
plain `--docs-dir`-only run is single-shot (no fold). `--decision`/`--rationale` apply to the