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>
This commit is contained in:
parent
9e44afeefb
commit
0add73531b
11 changed files with 870 additions and 7 deletions
65
CLAUDE.md
65
CLAUDE.md
|
|
@ -1408,6 +1408,71 @@ Python ≥3.10. MAF (`agent-framework-core` 1.16.0, `-orchestrations` 1.1.1 —
|
|||
parameteren har aldri vært øvet, og det er RAPPORTERT, ikke fikset (utenfor denne ordren);
|
||||
`verified_field` validerer ikke `at`; og at en LEVENDE modell kaller falsifiseringsskillen godt er
|
||||
ikke bevist (structured-output-grensens klasse).
|
||||
- **Den TREDJE projeksjonen inn i `CostBaseline` DERIVERES fra en tabell som alt er i basen — og
|
||||
den nekter heller enn å oppfinne (MAJOR-4, økt 78):** `cost-baseline.json` er håndskrevet per
|
||||
prosjekt og `baseline_from_project` tilhører veg-domenet, så et INGESTERT anbudskorpus kunne
|
||||
navigeres og aldri forankres. `okf.derive_cost_baseline(bundle, *, project_id)` leser
|
||||
prisskjemaet. **`project_id` er PÅKREVD keyword, ikke lest av basen:** `run._project_from_bundle`
|
||||
fail-faster alt kjøringens id mot basens `validator-input.json`, så en andre lesing her ville vært
|
||||
kø-(p) — og ville dratt en IR-projeksjon inn i en funksjon hvis hele input er en tabell.
|
||||
**PREMISSET BLE MÅLT FØR NOE BLE BYGGET PÅ DET, og ordrens to pekere navnga TO ULIKE FORMER:**
|
||||
`examples/*/expected-bundle/` bærer PIPE-tabeller, men hver eneste av dem er csv-/sql-kilt og
|
||||
rendret av `render.render_table` — **xlsx-stien når ALDRI `render_table`.** Målt (pandoc 3.10.2,
|
||||
produsentens egen `_PANDOC_WRITER = "markdown"` + `_PANDOC_ARGS = ("--eol=lf", "--wrap=none")`,
|
||||
mot produsentens egen `tests/fixtures/two-line-krav.xlsx` og et håndlagt Prisskjema):
|
||||
`extract._extract_office` konverterer, og `inbox.py` gir teksten videre til
|
||||
`render_inbox_concept(sanitized_text, …)` URØRT — resultatet er en pandoc **SIMPLE table**, der
|
||||
dash-linja definerer kolonne-spennene. En pipe-only leser ville altså vært INERT på nøyaktig det
|
||||
korpuset MAJOR-4 finnes for, og en simple-only leser inert på eksemplene ordren pekte på. Begge
|
||||
leses, av TO skannere over ÉN rollemapping og ÉN tallgrammatikk (`_split_frontmatter`-formen: ett
|
||||
skann, to lesere), aldri to kopier av semantikken. **Span-slicing, ALDRI splitt på whitespace:**
|
||||
K2s hele form er tomme priseceller, og en whitespace-splitt kollapser dem og skyver hver senere
|
||||
verdi én kolonne til venstre — en feilmapping som leses som DATA (M16 → 3 røde).
|
||||
**Ingen skjønn noe sted:** header-vokabularet er lukket og matches EKSAKT (en delstrengregel ville
|
||||
latt `Enhetspris eks. mva` og `… inkl. mva` kreve samme rolle, og leseren ville valgt mellom to
|
||||
priser), tallgrammatikken er lukket og **dot-desimal** (målt output er `1250.0`/`42.5`, så et
|
||||
komma ville kjøpt ingenting og importert `1,250`s tusenskille-vs-desimal-tvetydighet gratis — et
|
||||
håndskrevet norsk `1 250,50` er en NEKTET celle, uttalt), og hver tvetydighet er en nekt: ingen
|
||||
kandidat-tabell, mer enn én, to kolonner om samme rolle, to rader med samme kostkode.
|
||||
**Delvis priset skjema nekter i SIN HELHET** — ikke forsiktighet: en halvderivert base forankrer
|
||||
noen koder mens `ProvenanceStamp.cost_baseline_anchored` rapporterer `True`, og den biten er
|
||||
påkrevd-uten-default nettopp fordi begge defaults ville løyet. Skannet over `context_files`, aldri
|
||||
`files` (MAJOR-3-regelen). **`CostBaselineDerivationError` subklasser `ValueError`**
|
||||
(`BundleIdMismatch`-presedensen) — CLI-ens nekt-tuppel og hostings 400-arm, aldri krasj-kanalen.
|
||||
Wiret bak `--derive-cost-baseline`, ALDRI stille: ÉN oppløsning i `run.py`s bundle-arm tjener både
|
||||
full kjøring og `live_dry_run`, og **nekten PROPAGERER** i stedet for å degradere til fil-lasteren
|
||||
(`load_mandate`-regelen — en kaller som ba om derivasjon og fikk en uforankret kjøring er besvart
|
||||
av en stille nedgradert ordre). Tre CLI-nekter, alle ved NAVN: krever `--bundle-dir`, refusert i
|
||||
`--portfolio` (ved navn, ikke ved gjennomfall til `--bundle-dir`-kravet — `--explore`-presedensen)
|
||||
og i `report_forbidden` (report-modus returnerer FØR nekten, så en utelatelse er et stille DROPP,
|
||||
ikke en nekt — F4-gapet). **FIXTUREN er MÅLT, ikke håndskrevet:** begge basene under
|
||||
`tests/fixtures/` er pandocs output ORDRETT, og den uprisede er K2s faktiske pre-award-form —
|
||||
**kolonnene OVERLEVER som blanke** (målt), så tabellen ER en kandidat og nekten blir den skarpe:
|
||||
leseren identifiserer kolonnene, leser tomme celler og nekter ved navn. `validator-input.json`
|
||||
skrives KUN i testen, aldri inn i den innsjekkede fixturen (`measure`/`claimed_saving_nok` er
|
||||
menneskets/mandatets). **`pytest.raises(ValueError)` ville IKKE gatet arm (b), og det er MÅLT, ikke
|
||||
resonnert:** M17 (drop positivitetsvakten) får mutanten til å reise
|
||||
`pydantic_core.ValidationError` — `isinstance(e, ValueError) is True`,
|
||||
`isinstance(e, CostBaselineDerivationError) is False` — så en løsere arm ville stått grønn mot
|
||||
nøyaktig den mutasjonen den finnes for. Load-bearing MÅLT
|
||||
(`tests/test_cost_baseline_derivation_loadbearing.py`, 22 armer), **18 mutasjoner alle røde mot
|
||||
HELE suiten** + grønn kontroll **1230 passed / 5 skipped** (fra 1208/5, supersett, 0 fjernet) og
|
||||
golden `demo-transcript.stdout` BYTE-UENDRET (`ea8c534773acdbe41ae68f2c55724d69aaf8be4f`):
|
||||
M1 detach run-wiringen (2 røde) · M2 fallback ved nekt (1) · M3 hopp over uprisede rader (2) ·
|
||||
M4 fabrikkér null (1) · M4b fabrikkér null uten tom-celle-nekten (1) · M17 drop
|
||||
positivitetsvakten (1) · M5 transponer mengde/enhetspris (3) · M6 skann `files` (1) · M7 ta første
|
||||
tabell ved tvetydighet (1) · M8 ta første kolonne ved duplisert rolle (1) · M9 last-write-wins på
|
||||
duplisert kode (1) · M10 utvid tallgrammatikken (1) · M11 drop simple-skanneren (3) · M12 drop
|
||||
pipe-skanneren (7) · M13 detach `--bundle-dir`-nekten (1) · M14 drop fra `report_forbidden` (1) ·
|
||||
M15 drop fra portefølje-partisjonen (1) · M16 whitespace-splitt (3). **Ærlighets-grenser, uttalt:**
|
||||
NS 3451 seksjonsrader (kode + overskrift, ingen mengde, inne i et ellers priset ark) er IKKE
|
||||
klassifisert — K2 selv var ikke tilgjengelig å måle her, så et slikt ark NEKTER, og regelen skrives
|
||||
når noen kan måle den ekte formen (en rad som er tom over alle tre kolonner er derimot en blank
|
||||
spacer og hoppes over); stempelet sier AT en kjøring var forankret, aldri HVILKEN av de tre
|
||||
projeksjonene forankret den; den hostede flaten er BEVISST urørt (feltet er ikke i whitelisten, så
|
||||
4e-halvdelene står uendret); og ingen LEVENDE K2-fil er lest — fixturen er syntetisk, og at
|
||||
produsenten faktisk emitterer denne formen for K2s Prisskjema er MÅLT på pandoc-stien, ikke på K2.
|
||||
|
||||
- **STATE.md er local-only** (gitignored). Voyage session-state er efemert; STATE.md er kanonisk kontinuitet.
|
||||
- Prosess: Voyage-plugin (`/trekbrief → /trekplan → /trekexecute → /trekreview`) per større fase.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue