portfolio-optimiser/tests/fixtures/README.md
Kjell Tore Guttormsen 0add73531b feat(okf): derive a cost baseline from a priced schedule, or refuse
MAJOR-4 (misjonsreview v2 section 7), owner B = the consumer. Neither existing
projection into ir.CostBaseline can serve an ingested tender corpus:
cost-baseline.json is hand-written per project and baseline_from_project belongs
to the road domain, so a K2-shaped bundle could be navigated and never anchored.
okf.derive_cost_baseline reads the numbers already in the bundle.

The premise was MEASURED before anything was built on it, and the order's two
pointers named two different forms. examples/*/expected-bundle/ carry pipe
tables, but every one of them is csv- or sql-sourced via render.render_table --
the xlsx path never reaches render_table at all. Measured with pandoc 3.10.2
under the producer's own writer and arguments: extract._extract_office converts,
and inbox.py hands that text to render_inbox_concept untouched, so an
xlsx-sourced concept file carries a pandoc SIMPLE table whose dash rule defines
the column spans. A pipe-only reader would have been inert on exactly the corpus
this exists for. Both forms are read, by two scanners over one role mapping and
one number grammar.

No judgement anywhere: the header vocabulary and the number grammar are closed,
and every ambiguity refuses -- no candidate table, more than one, two columns
claiming one role, two rows sharing a cost code, a row that prices nothing. A
partly-priced schedule refuses in full, because a half-derived baseline anchors
some codes while cost_baseline_anchored reports True.

Wired behind --derive-cost-baseline and never silently: one resolution in
run.py's bundle arm serves both the full run and the dry run, and the refusal
propagates rather than degrading to the file loader.

The two fixtures are pandoc's output verbatim, not hand-typed. The unpriced one
is K2's actual pre-award shape, and the columns survive as blanks -- so the
table IS a candidate and the refusal is the sharp one.

Load-bearing MEASURED: 18 mutations all red against the WHOLE suite, green
control 1230 passed / 5 skipped (from 1208/5, superset, 0 removed), golden
demo-transcript.stdout byte-unchanged (ea8c534773acdbe41ae68f2c55724d69aaf8be4f).
M17 is the one that matters for arm (b): dropping the positivity guard makes the
mutant raise pydantic ValidationError, which IS a ValueError but is NOT the named
class -- so pytest.raises(ValueError) would have stayed green against exactly the
mutation the arm exists to catch. Verified directly, not argued.

Honesty limits stated in the invariant row: NS 3451 section rows are not
classified (K2 itself was not available to measure), the stamp records that a run
was anchored and never which projection anchored it, the hosted surface is
deliberately untouched, and no live K2 file was read.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 03:15:39 +02:00

31 lines
1.8 KiB
Markdown

# Test fixtures
## `k2-prisskjema-SYNTETISK/` and `k2-prisskjema-uprisert-SYNTETISK/`
**SYNTETISK — every number in these bundles is invented.** They copy the *structure* of a
public-tender `Prisskjema.xlsx` (NS 3451 posts: code, description, unit, quantity, unit price,
sum) and nothing else. **No private tender document is reproduced here**, and the unit prices in
the priced variant are round synthetic values chosen to be obviously not a real bid — they must
never be read as anyone's pricing. This is the first building block of the S7b corpus.
The two variants are the two halves of the same measurement:
| bundle | `Enhetspris` column | what it stands for |
| --- | --- | --- |
| `k2-prisskjema-SYNTETISK/` | filled | a priced schedule a baseline CAN be derived from |
| `k2-prisskjema-uprisert-SYNTETISK/` | empty | K2's actual pre-award state — codes and descriptions, no quantities or prices |
### The table form is MEASURED, not hand-typed
Both bodies are the **verbatim output** of the producer's own office conversion, so the fixture
states something about the format rather than recording our own idea of it:
pandoc -f xlsx -t markdown --eol=lf --wrap=none <sheet>.xlsx
with `pandoc 3.10.2` — the writer and the two arguments are `llm_ingestion_okf.extract`'s
`_PANDOC_WRITER` / `_PANDOC_ARGS`. That is a pandoc **simple table** (a dash rule whose groups
define the column spans), NOT the pipe table `render_table` emits: measured in session 78, the
xlsx path reaches a concept body through `inbox.py`'s `render_inbox_concept(sanitized_text, …)`
and never touches `render_table` at all. An empty spreadsheet cell therefore arrives as blank
space inside its column span — which is exactly what the unpriced variant has to carry for the
refusal it gates to be the real one.