feat(identity): an STS document's doc-number names its directory and its title the address

K3-19 a. `extract.declared_identity` reads what a NISO-STS document states
about itself -- exactly one <std-ident> (<doc-number>, <year>) and exactly one
<title-wrap> (<full>, else <main>) -- and returns None for every other row,
for XML that is not STS, for an unparseable file, and for a document that
states neither. A value stated more than once is not read: an adopted
standard carries one <std-ident> per issuing body, and picking one is a guess.

`okf build` names a document's directory from its <doc-number> through the id
grammar, replacing only the file's stem. A declared name another document in
the run also claims falls back to the file name for both, said on stderr: the
existing collision gate would refuse both with "rename one", and a name read
from inside a document is not one a rename can change.

`sources[0].title` becomes <doc-number> + <year>, then the <title-wrap>
title, then the file name -- the first that survives the gate and can be
written into the flow mapping verbatim. Measured on R761, <full> carries a
comma, which ends a flow mapping, so it is never the title there; it is never
cleaned up either. `resource` stays the inbox-relative file.

Every other row, and every profile without an address, is untouched: the
identity is asked for only where `sources` is written.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-11 03:08:30 +02:00
commit ee8d5b5776
6 changed files with 230 additions and 13 deletions

View file

@ -113,8 +113,7 @@ def test_two_doc_numbers_are_no_doc_number() -> None:
"""
data = IDENTITY.read_bytes().replace(
b"</std-doc-meta>",
b"<std-ident><doc-number>NS 9000</doc-number><year>2020</year></std-ident>"
b"</std-doc-meta>",
b"<std-ident><doc-number>NS 9000</doc-number><year>2020</year></std-ident></std-doc-meta>",
)
identity = extract.declared_identity(IDENTITY.name, data)