test(identity): a document that declares a doc-number names its own directory

Red first (K3-19 a). A NISO-STS delivery built with `okf build` put every
concept under a directory named for the delivery path's file name -- a UUID
that occurs 0 times in the document -- and every `sources` entry named that
file twice, while the document carries exactly one <std-ident> with a
<doc-number> and one <title-wrap>, neither of which this package read.

11 of the 14 tests are red: `extract.declared_identity` does not exist, and
the build still names the directory and the address title from the file.
The 3 that pass today pin the fallback layer that must survive the change: no
declaration keeps the file name, a declared title carrying a flow terminator
falls to the file name, and a name another document's file already holds is
not taken.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-11 02:59:36 +02:00
commit be169eeca0
3 changed files with 273 additions and 0 deletions

View file

@ -33,6 +33,7 @@ round-trip-symmetric defect.
|---|---|
| `sts-mini.xml` | The known-positive. A `<standard>` root with `<sec>` at three nesting levels carrying `<label>`+`<title>`, two lettered points (`a)`, `b)`) with a **label and no title**, one `<table-wrap>` with a label and two rows, `<p>` bodies, a `<list>`, and **one unnumbered section** (`Forord`, `<title>` with no `<label>`) mirroring the single such section in R761. The lettered points are what the 4 954 label-only `<sec>` in that document look like: promoted to headings they would bury its own 2 761. |
| `sts-empty-label.xml` | A `<sec>` carrying a `<label>` and **nothing else**, between a lettered point that has a body and the next titled section. The label is held as a prefix for a body line that never arrives, so it was overwritten and lost: measured on R761 that is exactly one `x)`, two characters of 1 283 395, ratio 0.999998. An exact invariant does not get to be 0.999998. |
| `sts-identity.xml` | A document that **states who it is**: exactly one `<std-ident>` with a `<doc-number>` and a `<year>`, one `<title-wrap>` whose `<full>` carries a **comma** (as R761's does, which is why that title cannot be written into a `sources` flow mapping verbatim), and a `<std-ref type="dated">`. Its body carries the `sec-type="spec"` shape the `description` rule reads: a titled `<sec>` whose first spec point has one `<p>`, a second spec point that must never become the description, a titled child with no spec point of its own, and a spec point with **two** `<p>` of which only the first counts. `sts-mini.xml` is the half identity (a `<title-wrap>`, no `<doc-number>`) and `sts-empty-label.xml` the absent one. |
| `generic-feed.xml` | Known-negative: XML that is **not** STS. It must produce text and ONE plan — never zero, never a crash, and never element names promoted to headings. |
| `xml-doctype-bomb.xml` | Known-negative, security: a `<!DOCTYPE` with a small nested-entity expansion. It must be refused by `code`, and the test asserts the expansion appears in **no** output, including the error text. Small on purpose — the point is that it is never parsed, not that it detonates. |
| `xml-malformed.xml` | Known-negative: an unterminated tag must raise a typed `ExtractionError`, not leak `ParseError` and not yield zero concepts in silence. |

41
tests/fixtures/sts-identity.xml vendored Normal file
View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<standard>
<front>
<std-doc-meta>
<title-wrap xml:lang="nb"><intro></intro><main></main><compl></compl><full>R900 Testnormalen Standard for fiksturer, tester og kontroll</full></title-wrap>
<std-ident><originator>TST</originator><doc-type>Innledning</doc-type><doc-number>R900 Testnormalen</doc-number><isbn>000-00-0000-000-0</isbn><year>2024</year></std-ident>
<std-ref type="dated">R900 Testnormalen:2024</std-ref>
</std-doc-meta>
</front>
<body>
<sec id="s-88" sec-type="procedure">
<label>88</label>
<title>Rekkverk</title>
<sec id="s-88-612" sec-type="procedure">
<label>88.612</label>
<title>Utskifting av enkeltkomponenter</title>
<sec id="s-88-612-a" sec-type="spec">
<label>a)</label>
<p>Omfatter utskifting av skadde enkeltkomponenter i rekkverk.</p>
</sec>
<sec id="s-88-612-b" sec-type="spec">
<label>b)</label>
<p>Et andre punkt blir aldri beskrivelsen.</p>
</sec>
<sec id="s-88-6121" sec-type="procedure">
<label>88.6121</label>
<title><italic>Utskifting av handlist</italic></title>
</sec>
</sec>
<sec id="s-88-613" sec-type="procedure">
<label>88.613</label>
<title>Maling av rekkverk</title>
<sec id="s-88-613-a" sec-type="spec">
<label>a)</label>
<p>Omfatter maling av rekkverk.</p>
<p>Et andre avsnitt i samme punkt blir ikke med.</p>
</sec>
</sec>
</sec>
</body>
</standard>