1
0
Fork 0
llm-ingestion-pipeline-secu.../docs/2026-09-07-limitations-44-maaling.md
Kjell Tore Guttormsen 6e7c8d2b98 docs(okf): measure the tags/description gap against the pinned SPEC and corpus
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.
2026-09-06 23:58:02 +02:00

317 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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`:
> **`tags` and `description` block the OKF import corpus universally, before the
> trust layer is even reached.** The line-flat frontmatter parser has no
> sequence-value type at all: `tags` is 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.
> `description` is 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`): removing `tags` alone
> lets 4/53 documents pass; removing both `tags` and `description` together
> (trust layer untouched) lets the same 4/53 pass, and all four then parse
> `generated` correctly as a mapping. **Independent of the mapping-form work
> above:** neither `1.2.0`'s flow mapping nor `1.3.0`'s `sources` carriers move
> anything on this corpus, because `tags`/`description` reject before `sources`
> is 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`):
> 1. 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`):
> ```yaml
> ---
> 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 by
> `index.md` generators, 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:
>
> 1. Every non-reserved `.md` file 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:
- `tags` er definert som «A YAML list» — **ikke** som flow-formen. Skjelettets
`[<tag>, ...]` er ett eksempel, ikke formkravet. Blokkformen er like konform.
- `description` er «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`:
```yaml
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
1. **«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_list` krever
`raw[:1] in (" ", "\t")`, og korpuset skriver `- a` i kolonne 0.
Feilklassen «44/53 rejected as malformed frontmatter line» er i dag 12/53,
fordi de øvrige treffer `description`-fortsettelsen først.
2. **«removing `tags` alone lets 4/53 documents pass … removing both … the same
4/53.»** Målt i dag: **6/53** med `tags` fjernet, og **6/53** med begge
fjernet. Tallet 4 var riktig for 1.2.0-parseren; 1.3.0s `sources`-bærere
flyttet to dokumenter til.
3. **«`tags`/`description` reject before `sources` is ever read» → derfor er
dette «det ENESTE residualet som blokkerer hele korpuset».** Den slutningen
holder ikke. `description` alene løsner **0/53** — fjerner man bare
`description`, passerer ingenting. Og lukker man *alle tre* formene, står
**44/53** fortsatt på `generated` som 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:` + `- a` i 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_construct` er 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 enn `tags`, 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 `- a` uten 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
`generated` også å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:** `description` brutt over to linjer — 29/53.
- **(b) Avviser fortsatt:** en innrykket linje som ser ut som `k: v` treffer
fremdeles nested-mapping-avvisningen; `- ` treffer fremdeles listeruten.
`_reject_dangerous_value` kjø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: z` raiser fortsatt som nested mapping;
`description: x\n - a` raiser 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å `generated` som 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.