Order 20260906T213322Z: measure and propose, no src, no bump. Measured against SPEC _okf-canonical @ ad30107 and the corpus _okf-upstream @ 3fcbb9f (denominator 53, extracted at the pin because the work tree had moved on to 9a15b13). Three claims in the tags/description entry are stale against the 1.3.0 parser. The parser does have a sequence type -- _consume_block_list parses block lists of scalars -- what it lacks is tolerance for the flush-left indentation 36/53 of the corpus uses. Removing tags alone now lets 6/53 pass, not the 4/53 recorded, and the entry's headline claim does not hold at all: description alone unblocks 0/53, and with all three surface forms closed 44/53 still stop on generated as a top-level block mapping. The entry oversells its own reach by a factor of seven. The SPEC has no depth rule. no-nesting-past-depth-1 is entirely ours; the conformance floor is only "a parseable YAML frontmatter block" (SS11.1). Candidates were measured by normalizing the surface form onto a shape the parser already accepts, then importing parse_frontmatter -- the predicate is never re-implemented, only the input's spelling is rewritten. P1 (scalar flow sequence) takes the corpus from 0/53 to 6/53 without spending depth-1; P2 and P3 buy 0/53 each and 6/53 stacked on P1. Recommendation is P1 alone, and the note says out loud that this does not open the corpus. The label "punkt 44" is not grep-able: it came from a count-after-insertion, and the entry is today the 12th of 45 at docs/LIMITATIONS.md:126. No src change, no version bump, no push. 868 passed, coverage 130/130 + 6/6 gaps, redos sweep exit 0 -- all after git add.
15 KiB
Beslutningsgrunnlag — LIMITATIONS «punkt 44» (tags/description-gapet)
Målt: 2026-09-07, mot HEAD = 44e2b31 (v1.3.0, urørt) og pinnet SPEC
_okf-canonical @ ad30107. Korpus: _okf-upstream @ 3fcbb9f.
Hva dette er: underlaget for én operatørbeslutning — hvilket predikat, om
noe, skal slippe inn den formen tags faktisk har i korpuset.
Hva dette ikke er: beslutningen. Ingen fil i src/ er endret, ingen
versjon er bumpet, ingenting er pushet (0 upushede commits ved øktstart).
1. Referenten: «punkt 44» er ikke grepbart
Ordren og STATE peker på «LIMITATIONS punkt 44». Målt:
$ grep -c '^- \*\*' docs/LIMITATIONS.md
45
$ grep -n '^- \*\*' docs/LIMITATIONS.md | awk -F: 'NR==44 {print $1}'
756 # -> ZWJ-oppføringen, ikke tags/description
Tallet stammer fra commit 0184df9 (25.08), som skrev «43 -> 44 items» i
commit-meldingen: 44 var antallet oppføringer etter innsettingen, ikke
oppføringens posisjon. Oppføringen ble satt inn midt i dokumentet og er i dag
den 12. av 45, på docs/LIMITATIONS.md:126. Etiketten «punkt 44» løser seg
altså ikke opp verken ved posisjon eller ved grep, og den vil peke feil igjen
neste gang listen vokser. Referenten er entydig i prosa («tags/description»),
men nummeret bør ikke brukes videre.
2. Hva punkt 44 sier i dag, ordrett
docs/LIMITATIONS.md:126-144:
tagsanddescriptionblock the OKF import corpus universally, before the trust layer is even reached. The line-flat frontmatter parser has no sequence-value type at all:tagsis present in 53/53 upstream concept documents — 9/53 as a flow sequence ([a, b, c], rejected on the[indicator) and 44/53 as a block sequence (- a/- b, rejected as"malformed frontmatter line") — 100% rejection regardless of form.descriptionis present in 53/53; 29/53 is a folded plain scalar continuing on an indented second line, which the parser has no continuation-line model for and misreads as"nested mappings are not supported"(the remaining 24/53 are single-line and parse fine). Measured directly on the upstream reference bundles (_okf-upstream/okf@3fcbb9f): removingtagsalone lets 4/53 documents pass; removing bothtagsanddescriptiontogether (trust layer untouched) lets the same 4/53 pass, and all four then parsegeneratedcorrectly as a mapping. Independent of the mapping-form work above: neither1.2.0's flow mapping nor1.3.0'ssourcescarriers move anything on this corpus, becausetags/descriptionreject beforesourcesis ever read. No sequence-value type or continuation-line model exists in the stdlib-only parser to close this with.
3. SPEC, ordrett fra pinnet kopi (ad30107)
§2 Terminology (SPEC.md:81):
- Frontmatter: A YAML metadata block delimited by
---at the top of a markdown file.
§4 Concept documents (SPEC.md:157-159):
- A YAML frontmatter block, delimited by
---on its own line at the start of the file and a closing---on its own line.
§4.1 Frontmatter, skjelettet (SPEC.md:163-173):
--- type: <Type name> # REQUIRED title: <Optional display name> description: <Optional one-line summary> resource: <Optional canonical URI for the underlying asset> tags: [<tag>, <tag>, ...] # Optional
§4.1, de to bærende definisjonene (SPEC.md:194-199):
description: A single sentence summarizing the concept. Used byindex.mdgenerators, search snippets, and previews.tags: A YAML list of short strings for cross-cutting categorization.
§11 Conformance (SPEC.md:738-742):
A bundle is conformant with OKF v0.2 if:
- Every non-reserved
.mdfile in the tree contains a parseable YAML frontmatter block.
3.1 Det spec-en ikke sier
grep -n -i 'nest\|depth\|indent' SPEC.md gir null treff som uttrykker en
dybde- eller innrykksregel (13 treff, alle i andre betydninger — «flat list of»
i §9 og §13, «indent» ingen). SPEC-en har ingen dybderegel. «Ingen nesting
forbi dybde 1» er utelukkende vår egen sikkerhetsegenskap. Konformans-gulvet er
«a parseable YAML frontmatter block» — altså hele YAML.
To presiseringer som følger av ordlyden:
tagser definert som «A YAML list» — ikke som flow-formen. Skjelettets[<tag>, ...]er ett eksempel, ikke formkravet. Blokkformen er like konform.descriptioner «A single sentence». En setning brutt over to linjer som foldet plain scalar er samme setning; spec-en stiller ingen linjekrav.
4. Måleoppsett
Korpuset er hentet ut ved pinnen, ikke fra arbeidstreet — _okf-upstream står
i dag på 9a15b13, og 3fcbb9f er en ekte forgjenger (git merge-base --is-ancestor → 0), med 23 filer endret i okf/ mellom dem.
$ git -C _okf-upstream archive 3fcbb9f okf/bundles | tar -x -C scratchpad/corpus
$ find scratchpad/corpus -name '*.md' ! -name index.md ! -name log.md | wc -l
53
Nevner = 53. Definisjonen er «hver .md under okf/bundles/ som ikke er et
reservert strukturnavn» — som er nøyaktig §11.1s «every non-reserved .md file».
Positiv kontroll. Et null-resultat må sjekkes mot et kjent-positivt tilfelle
før det konsumeres. Følgende dokument parser i dag, mot samme HEAD:
type: Metric
description: Recognized revenue for a period.
tags:
- finance # INNRYKKET blokksekvens
- revenue
generated: { by: reference_agent/gemini-2.5-pro, at: 2026-06-30T14:00:00Z }
sources:
- id: revenue-policy
resource: policies/revenue-recognition.md
→ tags blir ['finance', 'revenue'], sources blir en liste av dicter.
Instrumentet avviser altså ikke alt; tags som blokksekvens fungerer allerede
i dag, forutsatt innrykk.
5. Målingen
5.1 Formsensus over de 53 (scratchpad/shapes.py, exit 0)
| nøkkel | form | antall |
|---|---|---|
tags |
blokksekvens uten innrykk (- a i kolonne 0) |
36/53 |
tags |
flow-sekvens [a, b, c] |
9/53 |
tags |
enkeltlinje-skalar | 8/53 |
description |
skalar + innrykket fortsettelseslinje | 29/53 |
description |
enkeltlinje-skalar | 24/53 |
generated |
topp-nivå blokk-mapping ( by: på neste linje) |
44/53 |
generated |
flow-mapping { ... } |
9/53 |
sources |
blokksekvens uten innrykk | 44/53 |
sources |
blokksekvens med innrykk | 5/53 |
5.2 Baseline og kandidater (scratchpad/candidates.py, exit 0)
Kandidatene er målt ved å normalisere overflateformen inn i en form
parseren allerede godtar, og så importere parse_frontmatter. Predikatet er
aldri re-implementert; bare stavemåten på inputen er skrevet om.
| variant | passerer | dominerende residual |
|---|---|---|
| baseline (v1.3.0 som utgitt) | 0/53 | 32× nested mappings, 12× malformed line, 9× flow sequence |
| P1 skalar-flow-sekvens | 6/53 | 32× nested mappings, 12× malformed line |
| P2 blokksekvens uten innrykk | 0/53 | 44× nested mappings |
| P3 foldet plain scalar | 0/53 | 36× malformed line |
| P1+P3 | 6/53 | 36× malformed line |
| P1+P2 | 6/53 | 44× nested mappings |
| P1+P2+P3 | 6/53 | 44× nested mappings, 3× allowlist |
De 6 som passerer med P1 er alle i acme_retail; de er 6 av de 9 med
flow-sekvens-tags, og de tre siste stoppes av allowlisten
(parameters.name ×2, not.term ×1), ikke av tags.
5.3 Taket
Med alle tre predikatene er taket 6/53. Residualet er 44× topp-nivå
blokk-mapping på generated og 3× allowlist. En diagnostisk kjøring som også
normaliserte topp-nivå blokk-mapping til flow-mapping traff neste vegg med én
gang: 44× «a quoted scalar inside a flow mapping is not a supported form» —
korpuset skriver at: '2026-07-10T23:16:06+00:00' med enkeltfnutter.
6. Tre påstander i punkt 44 er målt feil
-
«The line-flat frontmatter parser has no sequence-value type at all.» Usant siden 1.3.0.
_consume_block_list(okf.py:662) parser blokklister av rene skalarer, og den positive kontrollen i §4 beviser det. Det som mangler er ikke sekvenstypen, men innrykkskravet:_consume_block_listkreverraw[:1] in (" ", "\t"), og korpuset skriver- ai kolonne 0. Feilklassen «44/53 rejected as malformed frontmatter line» er i dag 12/53, fordi de øvrige trefferdescription-fortsettelsen først. -
«removing
tagsalone lets 4/53 documents pass … removing both … the same 4/53.» Målt i dag: 6/53 medtagsfjernet, og 6/53 med begge fjernet. Tallet 4 var riktig for 1.2.0-parseren; 1.3.0ssources-bærere flyttet to dokumenter til. -
«
tags/descriptionreject beforesourcesis ever read» → derfor er dette «det ENESTE residualet som blokkerer hele korpuset». Den slutningen holder ikke.descriptionalene løsner 0/53 — fjerner man baredescription, passerer ingenting. Og lukker man alle tre formene, står 44/53 fortsatt pågeneratedsom topp-nivå blokk-mapping. Den bindende skranken på dette korpuset er altså ikke tags/description, men den topp-nivå blokk-mappingen vi bevisst avviser. Punkt 44 overselger sin egen betydning med en faktor på over sju (6 mot 53).
Punkt 44 bør skrives om etter at operatøren har bestemt seg — det er en dokumentasjonsendring som hører sammen med predikatvalget, ikke før det.
7. Kandidatpredikatene
Ordren spurte etter predikatet som slipper inn en ren skalar-flow-sekvens. Det er P1. P2 og P3 tas med fordi målingen viser at P1 alene er en liten gevinst, og beslutningen bør se hva naboene koster.
P1 — flow-sekvens av rene skalarer
Predikat: i _parse_flow_sequence, når første ikke-blanke tegn i et element
ikke er {, les elementet som en plain scalar dersom det ikke inneholder noen
av { } [ ] : , " ' # og ikke er tomt. Blandet sekvens (skalar + mapping)
avvises, slik blokklisten allerede gjør.
- (a) Slipper inn:
tags: [finance, revenue, headline-metric]— 9/53 i korpuset. Passeringen går fra 0/53 til 6/53. - (b) Avviser fortsatt: siterte elementer (
['a', 'b']), elementer med kolon eller komma i seg, tom sekvens[], uavsluttet[a, b, blandet[a, {b: c}], og nestet[[a]]— alle på tegn-nivå, uten YAML-semantikk. - (c) Dybde-1: bruker den ikke opp. Elementene er blad; ingen ny nestingsgrad oppstår. Det er samme dybde blokklisten av skalarer allerede har.
- (d) Testen som pinner den:
tags: [a, b]→["a", "b"];tags: ['a']raiser;tags: [a, {b: c}]raiser med blandingsfeilen;tags: []raiser;sources: [{ id: x }]parser uendret (ingen regresjon på G30-bæreren).
P2 — blokksekvens uten innrykk
Predikat: i _consume_block_list, godta også raw[:1] == "-" når linjen
starter med - og forrige toppnøkkel hadde tom verdi.
- (a) Slipper inn:
tags:+- ai kolonne 0 — 36/53. Men ogsåsources:i samme form — 44/53. - (b) Avviser fortsatt: alt innholdet i elementet avviser i dag; allowlisten
og
_reject_mapping_constructer uendret. - (c) Dybde-1: bruker den ikke opp for skalarelementer, men den er ikke
gratis: den åpner samtidig den ikke-innrykkede blokk-mapping-bæreren for
sources, hvor elementenes fortsettelseslinjer er innrykket. Det er en større flate enntags, og den bør vurderes for seg. - (d) Testen:
tags:\n- a\n- b→["a", "b"];sources:\n- id: x\n title: y→ én dict; en linje- auten forutgående tom toppnøkkel raiser fortsatt;tags:\n- a\n- {b: c}raiser med blandingsfeilen. - Målt effekt alene: 0/53. Den løsner ingenting uten P1 eller uten at
generatedogså åpnes.
P3 — foldet plain scalar (fortsettelseslinje)
Predikat: etter en toppnøkkel med ikke-tom, ikke-[/{ verdi, slå sammen
etterfølgende innrykkede linjer som ikke starter med - og ikke inneholder
en uquotet ": ", med ett mellomrom som skjøt.
- (a) Slipper inn:
descriptionbrutt over to linjer — 29/53. - (b) Avviser fortsatt: en innrykket linje som ser ut som
k: vtreffer fremdeles nested-mapping-avvisningen;-treffer fremdeles listeruten._reject_dangerous_valuekjører på den sammenslåtte verdien, ikke på fragmentene. - (c) Dybde-1: bruker den ikke opp — resultatet er én skalar.
Men den svekker et vern: i dag er enhver innrykket linje uten aktiv listenøkkel
et avvist nestet uttrykk. Etter P3 er den regelen betinget av at linjen ikke
inneholder
": "— altså samme heuristikk som_reject_mapping_construct, gjenbrukt til å slippe gjennom i stedet for til å avvise. - (d) Testen:
description: en setning\n som fortsetter→ én streng med ett mellomrom;description: x\n y: zraiser fortsatt som nested mapping;description: x\n - araiser fortsatt. - Målt effekt alene: 0/53.
8. Anbefaling
P1 alene. Ikke P2, ikke P3, ikke nå.
Begrunnelsen er tallene, ikke smaken:
- P1 er den eneste av de tre som flytter passeringstallet i det hele tatt (0 → 6). P2 og P3 gir hver for seg 0/53, og lagt oppå P1 gir de fortsatt 6/53. De koster parserflate og kjøper null målt konformans.
- P1 er den minste flaten: den er et tegn-nivå-predikat inne i en funksjon som allerede eksisterer, og den bruker ikke opp dybde-1-regelen.
- P1 lukker et gap STATE allerede fører som bevisst («
tags: [a, b]konformansgap»), og den bringer parseren i linje med §4.1s eget skjelett — den ene formen spec-en faktisk skriver ut. - P2 og P3 bør ikke besluttes på dette korpuset, fordi korpuset ikke kan skille
dem: 44/53 stopper på
generatedsom topp-nivå blokk-mapping uansett. Å bygge P2 og P3 nå ville være å betale for to predikater og måle null.
Den ærlige konsekvensen, som må sies høyt: P1 tar korpuset fra 0/53 til 6/53. Det lukker ikke «hele korpuset». Skal 53/53 nås, er den neste beslutningen en helt annen og mye tyngre en — topp-nivå blokk-mapping (44/53) pluss siterte skalarer (44/53) — og den bruker opp dybde-1-regelen. Det er en sikkerhetsbeslutning, ikke en parserdetalj, og den hører ikke i denne ordren.
9. Verifiseringslogg
| Påstand | Kommando | Exit | Resultat |
|---|---|---|---|
| Nevner = 53 | find scratchpad/corpus -name '*.md' ! -name index.md ! -name log.md | wc -l |
0 | 53 |
| Pinnen er ekte forgjenger | git -C _okf-upstream merge-base --is-ancestor 3fcbb9f HEAD |
0 | ja (HEAD = 9a15b13) |
| SPEC-pinnen er ren | git -C _okf-canonical rev-parse --short HEAD; git status --porcelain |
0 | ad30107, rent tre |
| SPEC har ingen dybderegel | grep -n -i 'nest|depth|indent' SPEC.md |
0 | 13 treff, 0 relevante |
| Baseline 0/53 | PYTHONPATH=src .venv/bin/python scratchpad/measure.py |
0 | 0 passerer |
| Formsensus | PYTHONPATH=src .venv/bin/python scratchpad/shapes.py |
0 | tabell §5.1 |
| Kandidattall | PYTHONPATH=src .venv/bin/python scratchpad/candidates.py |
0 | tabell §5.2 |
| Positiv kontroll | inline, se §4 | 0 | parser, tags == ['finance','revenue'] |
| LIMITATIONS-antall | grep -c '^- \*\*' docs/LIMITATIONS.md |
0 | 45 |
| Upushet ved øktstart | git rev-list --count origin/main..HEAD |
0 | 0 |
Ikke målt: om P1 påvirker ytelse eller ReDoS-marginen — predikatet er tegn-for-tegn uten regex, men ingen sveip er kjørt, siden ingen kode er skrevet. Kandidatene er målt ved overflatenormalisering, ikke ved en patchet parser: det er en trofast simulering av hva som slippes inn, men den beviser ikke at en implementasjon av P1 avviser nøyaktig (b)-listen. Testene i (d) er det som ville pinne det.