feat(p20): the requirement that is RIGHT, and a clause number that is not a price
Three seams, one commit: A, B and C touch the same four modules (run.py carries
the debate task, the grounding composition and the announcement; okf.py carries
one reference-number vocabulary read by both A and B), so splitting them into
three commits would have meant hunk-level staging of entangled files. Stated
rather than silently restructured.
A — the declaration answers with the DOCUMENT's own words. Measured: 13
declarations over round 3 and P17b, not one naming a fasit concept, while the
tool answered {"declared": true, ...} by echoing the caller's own arguments. It
now returns the document's title and req_number, read off Bundle.context_files
(so the type: verdict layer can never be named back), plus the sentence saying
what the declaration binds. A path the base carries as no concept answers with
empty strings rather than refusing. The commission's success_criteria now reach
the DEBATE task through mandate.criteria_block, the one renderer, empty when
there are none — which is what keeps every un-commissioned prompt, and the
golden, byte-identical.
B — a clause number is not a price. THE ORDER'S OWN RULE WAS FELLED BY
MEASUREMENT: it asks to refuse a code that IS declared req_number/prosessnr,
and neither of its two known positives is. n500 declares seksjon 10.4.1..10.4.4
but never the bare 10.4; r761 declares 2727 prosessnr and 2753 seksjon, none of
them 1.10.4, which occurs once, as prose ("iht. vegnormal N200 kap. 1.10.4").
The COMPLEMENT fires on both and closes the hole _ground_against_input already
admits in writing -- "it fails OPEN on a coincidental match". Unanchored run +
requirement-shaped code + the base declares a vocabulary + the code is not in
it -> refused, naming the denominator. All five of kontrakt-sorasen's real
process codes ARE declared and pass, which is what keeps the one context set
built on real codes measurable. Replayed over all 24 codes of round 3 + P17b:
exactly the two known positives flip validated -> rejected, 22 unchanged.
C — a parse failure no longer burns the round ledger blind. _fetch_parsed takes
a BUILDER instead of a finished message list, so the retry carries the parse
reason; measured, kontrakt-sorasen-04 spent 11 of 12 rounds re-asking the same
question. And announced_subject names the routed bases instead of saying "the
portfolio" for a two-base commission.
Suite 1807/5 (from 1781, +26, 0 removed), golden demo-transcript.stdout
BYTE-UNCHANGED (shasum -a 1 of the CONTENT = ea8c534773acdbe41ae68f2c55724d69aaf8be4f),
ruff and mypy clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
64723c5d89
commit
c8f0c8f7c4
12 changed files with 1098 additions and 37 deletions
|
|
@ -1224,6 +1224,53 @@ _DIRECTORY_PAGE_MAX: Final = 50
|
|||
#: hence ``unquote_scalar``, this repo's ONE de-quoting rule).
|
||||
_FILTER_FIELDS: Final = ("req_number", "prosessnr")
|
||||
|
||||
#: Which frontmatter keys DECLARE a reference number — the base's own vocabulary of requirement and
|
||||
#: process numbers. Derived from ``_FILTER_FIELDS`` rather than restating it (two copies of the two
|
||||
#: measured keys is the kø-(p) drift), plus ``seksjon``, which is the field that carries the BARE
|
||||
#: form-3 number on the N corpora and on R761 (``seksjon: '10.4.3'``, ``seksjon: '11.11'``) while
|
||||
#: ``req_number`` carries the composed ``Krav 10.4.3—1``. MEASURED 15.09 over the four delivered
|
||||
#: bases: n100 553 distinct declared numbers, n200 1 440, n500 365, r761 2 765.
|
||||
#:
|
||||
#: NOT added to ``_FILTER_FIELDS`` itself, and that is deliberate: what a ``filter`` word searches
|
||||
#: is measured and gated (P18), and widening it would change ``total_matches`` for every navigator
|
||||
#: call. These two constants answer different questions — "what does a filter look in" and "what
|
||||
#: does this document declare as its number" — over ONE list of the measured reference keys.
|
||||
REFERENCE_NUMBER_FIELDS: Final = (*_FILTER_FIELDS, "seksjon")
|
||||
|
||||
|
||||
def reference_number(file: BundleFile) -> str:
|
||||
"""The document's OWN reference number as its top-level frontmatter states it, or ``""``.
|
||||
|
||||
First non-empty of ``_FILTER_FIELDS``, in that order: the N corpora declare ``req_number``
|
||||
("Krav 4.1.2—1") and R761 declares ``prosessnr`` ("'11.11'", quoted — hence ``unquote_scalar``),
|
||||
and MEASURED no delivered document declares both. ``seksjon`` is deliberately NOT read here:
|
||||
this answers "which requirement IS this", and a section number names the chapter a requirement
|
||||
sits in, not the requirement.
|
||||
|
||||
Read off ``BundleFile.frontmatter``, so P15's top-level-wins rule applies and a nested
|
||||
``sources:`` entry can never answer for the concept.
|
||||
"""
|
||||
for key in _FILTER_FIELDS:
|
||||
value = unquote_scalar(file.frontmatter.get(key, ""))
|
||||
if value:
|
||||
return value
|
||||
return ""
|
||||
|
||||
|
||||
def declared_reference_numbers(file: BundleFile) -> tuple[str, ...]:
|
||||
"""Every reference number this ONE document declares (``REFERENCE_NUMBER_FIELDS``), de-quoted.
|
||||
|
||||
The unit of the reference VOCABULARY the validator's stage 0b checks a requirement-shaped code
|
||||
against (P20/B). Per DOCUMENT rather than per base, because the caller composing the grounding
|
||||
already walks the base once and the boundaries it composes are the ones the gate must read
|
||||
(P18/B1's rule: one document is one unit, never a blob).
|
||||
"""
|
||||
return tuple(
|
||||
value
|
||||
for key in REFERENCE_NUMBER_FIELDS
|
||||
if (value := unquote_scalar(file.frontmatter.get(key, "")))
|
||||
)
|
||||
|
||||
|
||||
def _matches_filter(file: BundleFile, needle: str) -> bool:
|
||||
"""Case-insensitive SUBSTRING over the document's title and its reference number.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue