Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 deletions TODO.sts-refactor/00-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,21 +167,29 @@ grep -r "method_missing|respond_to_missing|Object.const_get|\.send" lib/

### Architectural Items (High Effort)
- `03-namespace-coupling.md` — IN PROGRESS: 63→20 IsoSts→NisoSts references
remaining (issue #40). Source of truth is `ISOSTS.xsd`, NOT the NisoSts
models — they disagree on nearly every element.
remaining (issue #40). ISOSTS.xsd governs content models and all non-`@id`
attributes; the `@id` follows the 86948b9 convention.
- `04-register-versioning.md` — Version the models via lutaml-model Registers
- `11-duplicate-models.md` — 44 overlapping element resolution (depends on 03)

### Known bugsschema conformance (separate from 03)
### Schema conformancedropped ISOSTS attributes
The 2026-05-07 "@id added to all models (XSD-verified)" pass verified against
the **NISO** XSD and applied the result to IsoSts. ISOSTS disagrees:
- **16 IsoSts models silently drop ISOSTS attributes that exist** — real data
loss. `sub`/`sup` lose `arrange`+`specific-use`; `ext-link` loses 5 xlink
attrs; `mixed-citation` loses 6; `graphic`, `copyright-*`, `edition`,
`title`, `label`, `uri`, `named-content`, `underline`, `meta-date`, `body`
lose others.
- **25 IsoSts models carry an `@id` ISOSTS does not define** — harmless (never
populated on parse, never emitted on serialise), but dead surface.
the **NISO** XSD and applied the result to IsoSts.
- **Fixed — dropped ISOSTS attributes restored.** 15 IsoSts models were
silently dropping ISOSTS attributes present in real documents (data loss):
`sub`/`sup` (`arrange`+`specific-use`), `ext-link`/`mixed-citation`/`uri`/
`named-content` (`xlink:*`), `graphic` (`xlink:*`+`originator`), `copyright-*`,
`edition`, `title`, `label`, `underline`, `body`. This change adds them and
fixes `sec`/`standard`/`term-sec`, which mapped `xml:lang` under the wrong XML
name. (`meta-date` was NOT lossy — it already maps `type`.)
- **Not a bug — the conventional `@id`.** IsoSts models carry an `@id` that
ISOSTS does not itself define; this is the deliberate 86948b9 convention
(NISO-XSD-verified), not dead surface.
- **Remaining follow-up (separate change).** 7 spurious attributes on 5 models
(model carries an attr ISOSTS does not define: `graphic` `type`, `body`/`back`
`content-type`, `content-language`/`language` extras), and the 6 classes left
without `@id` in 86948b9 (`monospace`, `sc`, `strike`, `underline`, `uri`,
`standard_ref`).

## Next Action
Two independent tracks:
Expand Down
32 changes: 17 additions & 15 deletions TODO.sts-refactor/03-namespace-coupling.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,41 +14,42 @@ evolves, so coupling them violates OCP.
PR #31 reduced this from 157 to 63 references. Issue #40 reduced it further,
from 63 to 20.

## Source of truth: ISOSTS.xsd, NOT the NisoSts models
## Content models from ISOSTS.xsd; `@id` from the 86948b9 convention

The obvious approach — duplicate each NisoSts class into IsoSts — produces
**schema-incorrect models**. The NisoSts models disagree with
`reference-docs/isosts-v1/xsd/ISOSTS.xsd` on nearly every element:
IsoSts models carry `@id` following the compatibility convention established in
86948b9 (NISO-XSD-verified). ISOSTS.xsd governs element content
models and all non-`@id` attributes; it is not an authority that forbids the
conventional `@id`. So the two schemas can legitimately differ per element:

| Element | ISOSTS says | NisoSts model |
| Element | ISOSTS content/attrs | NisoSts model |
|---|---|---|
| `year` (:948) | `content-type`, `specific-use`, `xml:lang` — no `@id` | `@id` only |
| `doc-type` (:6378) | `type="xs:string"` — no attributes at all | `@id` + content |
| `doc-type` (:6378) | `type="xs:string"` | `@id` + content |
| `ics` (:6373) | `type="xs:string"` | `@id` + `ics-desc` child |
| `fpage` | `content-type`, `seq`, `specific-use`, `xml:lang`; no children | `@id` + bold/italic |
| `license` (:51) | `license-type`, `specific-use`, `xml:lang` | `@id`, `xlink:href` |
| `ruby` | **not an ISOSTS element** | exists (NISO only) |

`feature_doc.xml` declares `<!DOCTYPE standard SYSTEM ".../ISOSTS.dtd">`, and
the ISOSTS DTD agrees with ISOSTS.xsd (both derive `bold`, `sub` etc. from the
JATS 0.4 modules). ISOSTS.xsd is a faithful conversion and is the authority.
JATS 0.4 modules) on content models.

**Round-tripping does not prove correctness.** A model that invents or drops an
attribute still parses and serialises symmetrically, so the suite stays green
while the model is wrong. Assert the exact attribute set per element instead.

Attribute lists must be **generated** from the XSD, never hand-read: `version`
on `tex-math` and `specific-use` on `pub-id` sit after long `xs:enumeration`
blocks and are invisible to a truncated read.
Non-`@id` attribute lists must be **generated** from the XSD, never hand-read:
`version` on `tex-math` and `specific-use` on `pub-id` sit after long
`xs:enumeration` blocks and are invisible to a truncated read.

## Done in issue #40 — 43 refs removed, 27 classes added

- **14 `xs:string` elements** (`originator`, `doc-type`, `doc-number`,
`part-number`, `version`, `suppl-type`, `suppl-number`, `suppl-version`,
`urn`, `sdo`, `proj-id`, `release-version`, `ics`, `secretariat`) — modelled
as content-only IsoSts classes with no attributes. 23 refs.
as content IsoSts classes that also carry the conventional `@id` (86948b9);
`secretariat` is content plus `@id`, not content-only. 23 refs.
- **3 `permissions` refs** repointed to the existing `IsoSts::Permissions`.
- **`ruby` deleted** from `StyledContent` — ISOSTS defines no such element.
- **`ruby` deleted** from `StyledContent` — ISOSTS's `styled-content` content
model omits `<ruby>` (NISO permits it transitively via the emphasis group).
Behaviour change: `<ruby>` in `<styled-content>` no longer round-trips.
- **13 element classes** modelled from ISOSTS.xsd: `Year`, `PubDate`,
`ReleaseVersionId`, `IsProof`, `AltText`, `LongDesc`, `TexMath`, `PubId`,
Expand Down Expand Up @@ -114,6 +115,7 @@ reaches `TbxIsoTml`/MathML. Those are shared namespaces, outside this ADR.
## Verification

1. `grep -rho "Sts::NisoSts::" lib/sts/iso_sts/ | wc -l` → `20`
2. Every attribute on an IsoSts model traces to a line in `ISOSTS.xsd`
2. Every *non-`@id`* attribute on an IsoSts model traces to a line in
`ISOSTS.xsd`; `@id` follows the 86948b9 convention
3. Autoload registry 1:1 with the directory (112/112)
4. `bundle exec rspec` green; `bundle exec rubocop` clean
2 changes: 2 additions & 0 deletions lib/sts/iso_sts/body.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module IsoSts
class Body < Lutaml::Model::Serializable
attribute :id, :string
attribute :content_type, :string
attribute :specific_use, :string
attribute :paragraph, ::Sts::IsoSts::Paragraph, collection: true
attribute :sec, ::Sts::IsoSts::Sec, collection: true
attribute :term_sec, ::Sts::IsoSts::TermSec, collection: true
Expand All @@ -31,6 +32,7 @@ class Body < Lutaml::Model::Serializable

map_attribute "id", to: :id
map_attribute "content-type", to: :content_type
map_attribute "specific-use", to: :specific_use

map_element "p", to: :paragraph
map_element "sec", to: :sec
Expand Down
6 changes: 6 additions & 0 deletions lib/sts/iso_sts/copyright_holder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@ module Sts
module IsoSts
class CopyrightHolder < Lutaml::Model::Serializable
attribute :id, :string
attribute :content_type, :string
attribute :specific_use, :string
attribute :xml_lang, :string
attribute :content, :string, collection: true
attribute :sub, ::Sts::IsoSts::Sub
attribute :sup, ::Sts::IsoSts::Sup

xml do
element "copyright-holder"
map_attribute "id", to: :id
map_attribute "content-type", to: :content_type
map_attribute "specific-use", to: :specific_use
map_attribute "xml:lang", to: :xml_lang
mixed_content

map_content to: :content
Expand Down
6 changes: 6 additions & 0 deletions lib/sts/iso_sts/copyright_statement.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ module Sts
module IsoSts
class CopyrightStatement < Lutaml::Model::Serializable
attribute :id, :string
attribute :content_type, :string
attribute :specific_use, :string
attribute :xml_lang, :string
attribute :content, :string, collection: true
attribute :bold, ::Sts::IsoSts::Bold
attribute :italic, ::Sts::IsoSts::Italic
Expand All @@ -13,6 +16,9 @@ class CopyrightStatement < Lutaml::Model::Serializable
xml do
element "copyright-statement"
map_attribute "id", to: :id
map_attribute "content-type", to: :content_type
map_attribute "specific-use", to: :specific_use
map_attribute "xml:lang", to: :xml_lang
mixed_content

map_content to: :content
Expand Down
4 changes: 4 additions & 0 deletions lib/sts/iso_sts/copyright_year.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ module Sts
module IsoSts
class CopyrightYear < Lutaml::Model::Serializable
attribute :id, :string
attribute :content_type, :string
attribute :specific_use, :string
attribute :content, :string

xml do
element "copyright-year"

map_attribute "id", to: :id
map_attribute "content-type", to: :content_type
map_attribute "specific-use", to: :specific_use

map_content to: :content
end
Expand Down
5 changes: 4 additions & 1 deletion lib/sts/iso_sts/doc_number.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

module Sts
module IsoSts
# ISOSTS declares <doc-number> as type="xs:string" -- no attributes.
# ISOSTS declares <doc-number> as type="xs:string". The @id follows the
# NisoSts convention established in 86948b9, not ISOSTS itself.
class DocNumber < Lutaml::Model::Serializable
attribute :content, :string
attribute :id, :string

xml do
element "doc-number"

map_content to: :content
map_attribute "id", to: :id
end
end
end
Expand Down
5 changes: 4 additions & 1 deletion lib/sts/iso_sts/doc_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

module Sts
module IsoSts
# ISOSTS declares <doc-type> as type="xs:string" -- no attributes.
# ISOSTS declares <doc-type> as type="xs:string". The @id follows the
# NisoSts convention established in 86948b9, not ISOSTS itself.
class DocType < Lutaml::Model::Serializable
attribute :content, :string
attribute :id, :string

xml do
element "doc-type"

map_content to: :content
map_attribute "id", to: :id
end
end
end
Expand Down
6 changes: 6 additions & 0 deletions lib/sts/iso_sts/edition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@ module Sts
module IsoSts
class Edition < Lutaml::Model::Serializable
attribute :id, :string
attribute :content_type, :string
attribute :specific_use, :string
attribute :xml_lang, :string
attribute :content, :string, collection: true
xml do
element "edition"
map_attribute "id", to: :id
map_attribute "content-type", to: :content_type
map_attribute "specific-use", to: :specific_use
map_attribute "xml:lang", to: :xml_lang
mixed_content

map_content to: :content
Expand Down
10 changes: 10 additions & 0 deletions lib/sts/iso_sts/ext_link.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ class ExtLink < Lutaml::Model::Serializable
attribute :specific_use, :string
attribute :xml_lang, :string
attribute :xlink_href, :string
attribute :xlink_type, :string
attribute :xlink_role, :string
attribute :xlink_title, :string
attribute :xlink_show, :string
attribute :xlink_actuate, :string
attribute :content, :string
attribute :bold, ::Sts::IsoSts::Bold
attribute :italic, ::Sts::IsoSts::Italic
Expand All @@ -21,6 +26,11 @@ class ExtLink < Lutaml::Model::Serializable
map_attribute "specific-use", to: :specific_use
map_attribute "xml:lang", to: :xml_lang
map_attribute "xlink:href", to: :xlink_href
map_attribute "xlink:type", to: :xlink_type
map_attribute "xlink:role", to: :xlink_role
map_attribute "xlink:title", to: :xlink_title
map_attribute "xlink:show", to: :xlink_show
map_attribute "xlink:actuate", to: :xlink_actuate

map_content to: :content

Expand Down
2 changes: 2 additions & 0 deletions lib/sts/iso_sts/fpage.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class Fpage < Lutaml::Model::Serializable
attribute :seq, :string
attribute :specific_use, :string
attribute :xml_lang, :string
attribute :id, :string

xml do
element "fpage"
Expand All @@ -17,6 +18,7 @@ class Fpage < Lutaml::Model::Serializable
map_attribute "seq", to: :seq
map_attribute "specific-use", to: :specific_use
map_attribute "xml:lang", to: :xml_lang
map_attribute "id", to: :id
end
end
end
Expand Down
10 changes: 10 additions & 0 deletions lib/sts/iso_sts/graphic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ class Graphic < Lutaml::Model::Serializable
attribute :mime_subtype, :string
attribute :xlink_href, :string
attribute :xlink_type, :string
attribute :xlink_role, :string
attribute :xlink_title, :string
attribute :xlink_show, :string
attribute :xlink_actuate, :string
attribute :graphic_type, :string
attribute :originator, :string
attribute :label, ::Sts::IsoSts::Label
attribute :caption, ::Sts::IsoSts::Caption
attribute :alt_text, ::Sts::IsoSts::AltText
Expand All @@ -33,7 +38,12 @@ class Graphic < Lutaml::Model::Serializable
map_attribute "mime-subtype", to: :mime_subtype
map_attribute "xlink:href", to: :xlink_href
map_attribute "xlink:type", to: :xlink_type
map_attribute "xlink:role", to: :xlink_role
map_attribute "xlink:title", to: :xlink_title
map_attribute "xlink:show", to: :xlink_show
map_attribute "xlink:actuate", to: :xlink_actuate
map_attribute "type", to: :graphic_type
map_attribute "originator", to: :originator

map_element "label", to: :label
map_element "caption", to: :caption
Expand Down
5 changes: 4 additions & 1 deletion lib/sts/iso_sts/ics.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

module Sts
module IsoSts
# ISOSTS declares <ics> as type="xs:string" -- no attributes.
# ISOSTS declares <ics> as type="xs:string". The @id follows the
# NisoSts convention established in 86948b9, not ISOSTS itself.
class Ics < Lutaml::Model::Serializable
attribute :content, :string
attribute :id, :string

xml do
element "ics"

map_content to: :content
map_attribute "id", to: :id
end
end
end
Expand Down
9 changes: 7 additions & 2 deletions lib/sts/iso_sts/is_proof.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@

module Sts
module IsoSts
# ISOSTS declares <is-proof> as an empty complexType: its presence is the
# whole signal -- no attributes, no content.
# ISOSTS declares <is-proof> as an empty complexType: its presence carries
# no content. The @id follows the NisoSts convention established in 86948b9,
# not ISOSTS itself.
class IsProof < Lutaml::Model::Serializable
attribute :id, :string

xml do
element "is-proof"

map_attribute "id", to: :id
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/sts/iso_sts/issue.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class Issue < Lutaml::Model::Serializable
attribute :seq, :string
attribute :specific_use, :string
attribute :xml_lang, :string
attribute :id, :string

xml do
element "issue"
Expand All @@ -17,6 +18,7 @@ class Issue < Lutaml::Model::Serializable
map_attribute "seq", to: :seq
map_attribute "specific-use", to: :specific_use
map_attribute "xml:lang", to: :xml_lang
map_attribute "id", to: :id
end
end
end
Expand Down
4 changes: 4 additions & 0 deletions lib/sts/iso_sts/label.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ module Sts
module IsoSts
class Label < Lutaml::Model::Serializable
attribute :id, :string
attribute :alt, :string
attribute :xml_lang, :string
attribute :content, :string, collection: true
attribute :bold, ::Sts::IsoSts::Bold
attribute :italic, ::Sts::IsoSts::Italic
Expand All @@ -19,6 +21,8 @@ class Label < Lutaml::Model::Serializable
xml do
element "label"
map_attribute "id", to: :id
map_attribute "alt", to: :alt
map_attribute "xml:lang", to: :xml_lang
mixed_content

map_content to: :content
Expand Down
2 changes: 2 additions & 0 deletions lib/sts/iso_sts/lpage.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class Lpage < Lutaml::Model::Serializable
attribute :content_type, :string
attribute :specific_use, :string
attribute :xml_lang, :string
attribute :id, :string

xml do
element "lpage"
Expand All @@ -15,6 +16,7 @@ class Lpage < Lutaml::Model::Serializable
map_attribute "content-type", to: :content_type
map_attribute "specific-use", to: :specific_use
map_attribute "xml:lang", to: :xml_lang
map_attribute "id", to: :id
end
end
end
Expand Down
Loading
Loading