pubid 2.0.28 → 2.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.adoc +4 -3
- data/lib/pubid/export/flavor_exporter.rb +5 -3
- data/lib/pubid/iec/CLAUDE.md +2 -2
- data/lib/pubid/iec/identifiers/corrigendum.rb +4 -3
- data/lib/pubid/iec/renderer.rb +18 -2
- data/lib/pubid/iec/supplement_identifier.rb +1 -1
- data/lib/pubid/version.rb +1 -1
- data/lib/tasks/website-data.json +4224 -2412
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 34bcdf345b40aa5e1bc95e74b7c110e474c2019bda1e16e1cbbbe9988677427f
|
|
4
|
+
data.tar.gz: a2fa7df1b0c06f2ba455e55b88bf0e1b4891f15e6ae3e73fab71e698f3e88570
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5dbd5dffdb3a62b01d6d0692bb3b9bbe3c0cf1fda27c6425b4cafb9a393be1c81c550cda411d60a2888d2234e16f3820ed9253b057de2ca705cb19893ae15da8
|
|
7
|
+
data.tar.gz: f9c0a0ebf03670237ad1da8f21e575ce03e81eb73a8ed8b623bc98fcbca27130bbf23c69d72e98a51128dfd29185c325ed8d1c7fc193db97db87f9af62a14c8f
|
data/README.adoc
CHANGED
|
@@ -645,7 +645,8 @@ The exported JSON follows this structure:
|
|
|
645
645
|
"examples": ["ISO 9001:2015", "ISO/IEC 17031-1:2020", ...]
|
|
646
646
|
}
|
|
647
647
|
],
|
|
648
|
-
"attributes": [
|
|
648
|
+
"attributes": ["_type", "number", "part", "subpart", "stage_iteration",
|
|
649
|
+
"date", "edition", "languages", ...]
|
|
649
650
|
}
|
|
650
651
|
}
|
|
651
652
|
----
|
|
@@ -701,8 +702,8 @@ The exported JSON follows this structure:
|
|
|
701
702
|
|
|
702
703
|
|`attributes`
|
|
703
704
|
|`string[]`
|
|
704
|
-
|Lutaml::Model attribute names on the
|
|
705
|
-
|
|
705
|
+
|Lutaml::Model attribute names declared on the flavor's lead identifier
|
|
706
|
+
class (read through lutaml's class-level `attributes` introspection)
|
|
706
707
|
|
|
707
708
|
|`wrapper_types`
|
|
708
709
|
|`object[]`
|
|
@@ -202,10 +202,12 @@ module Pubid
|
|
|
202
202
|
end
|
|
203
203
|
end
|
|
204
204
|
|
|
205
|
+
# The flavor's declared attribute surface, from lutaml-model's public
|
|
206
|
+
# class-level introspection (`attributes` returns name => Attribute).
|
|
207
|
+
# #720: the previous `model_attributes` call targeted a method that does
|
|
208
|
+
# not exist, so the column was always empty.
|
|
205
209
|
def extract_attributes(klass)
|
|
206
|
-
klass.
|
|
207
|
-
rescue NoMethodError
|
|
208
|
-
[]
|
|
210
|
+
klass.attributes.keys.map(&:to_s)
|
|
209
211
|
end
|
|
210
212
|
|
|
211
213
|
def extract_wrapper_types
|
data/lib/pubid/iec/CLAUDE.md
CHANGED
|
@@ -41,8 +41,8 @@ These notes were part of the root `CLAUDE.md`. Read them before you change `lib/
|
|
|
41
41
|
|
|
42
42
|
- **A standalone supplement is `==` its `from_hash(to_hash)` round trip — the cause was the synthetic base's stage, not the ivar swap.** A supplement written without its base (`IEC/FDAM 60038-1`, `IEC/DCOR 60038-1`, `IEC/DISH 60038-1`) gets a bare `Pubid::Iec::SingleIdentifier` base from `SupplementIdentifier#ensure_base`; `to_s`, `to_urn`, `to_hash` and `#hash` agreed on both paths, but `==` was false, so `#matches?` failed silently. **The hand-off blamed the swapped `@number`/`@part` ivars; that was wrong.** `EqualityIgnored#==` compares through `public_send`, so the reader overrides hid the swap from it. The real difference was `base.typed_stage`: `ensure_base` set an IS/undated `TypedStage` with no `code`, which `stage_to_kv` cannot serialize, so `from_hash` rebuilt the base with none. **Diagnose an `==` failure by diffing the attributes through their readers, recursively, before trusting a hypothesis about ivars.** The stage write is deleted (the JCGM "delete the write" shape); the one visible change is `root.to_s` of the synthetic base on the parse path (`IEC IS60038` → `IEC60038`, the value `from_hash` already gave). The ivar swap was cleaned up too, because it was a hazard: `ensure_base` now moves the supplement number from `@part` into `@number`, so the stored layout is what `from_hash` rebuilds, and the `#number`/`#part` overrides, `@supplement_number`, `@synthetic_base` and `mark_synthetic_standalone!` are gone. `synthetic_base?` reads `base.instance_of?(SingleIdentifier)`, so it also survives `#exclude`, which copies `base` into a new object (on `main` the copy lost the flag and rendered in attached form, `IEC IS60038/FDAM1`). **The move must not depend on which reader runs first**, and a first version got that wrong: it called `ensure_base` only in the slash-form branch of `Builder#build`, but the canonical spelling `IEC FDAM 60038-1` (what `to_s` prints) reaches a different grammar branch, so a fresh parse kept the grammar layout until something read `base` — `.number` answered `60038`, `to_mr_string` gave `iec.60038_amd.60038`, and `#exclude` (which copies through the readers) copied the unmoved numbers onto a base synthesised afterwards, rendering `IEC FDAM 60038-60038`. So `#number`/`#part` keep a thin override that only TRIGGERS the move (`settle_standalone_layout`: `ensure_base` when there is a `part` and no base) and then return the stored value, and `Iec::Identifier.parse` calls `ensure_base` on a top-level supplement so a fresh parse already stores the moved layout. Supplements without a part (consolidation members, `IEC/AMD 1:2017`) are untouched by either. Two renderings outside the fixture corpus move, both repairs: `exclude(:date)` of a standalone supplement keeps the standalone form, and `IEC FDAM 60038-1 (all parts)` renders as itself instead of `IEC IS60038/FDAM1 (all parts)`. One hazard is left, unreachable from the grammar: reading `part` on a hand-built supplement BEFORE its base is assigned synthesises a base and moves the number, so a later `base =` renders the moved number. **A second hand-off claim was also wrong: an equal `#hash` for two unequal objects is legal** (the rule is `a == b ⇒ a.hash == b.hash`); `compute_hash` does not read `base`, which is a collision, not a defect. Measured: all 12,331 pass-fixture ids are byte-identical in `to_s`, `to_urn`, `to_mr_string`, `root.number`, `to_hash` and class; all 32,949 `relaton-data-iec` `index-v2.yaml` rows keep `from_hash(row).to_hash == row` and `parse(from_hash(row).to_s) == from_hash(row)`, and none has a `pubid:iec:single-identifier` base, so **no index migration follows**. Locked by `spec/pubid/iec/standalone_supplement_round_trip_spec.rb` and by the six standalone fixtures now in `full/iec-pubid.txt`, which the whole-corpus `==` sweep in `spec/pubid/iec/root_number_spec.rb` covers. **Residue, deliberately unchanged:** the self-base form renders its number twice — `IEC/AMD 1:2017` → `IEC Amd 1-1:2017` — because `render_supplement_standalone` prints `base.number` and then the supplement's own number, which are the same value there. (hand-off: iec-standalone-supplement-ivar-swap.) **CORRECTED 2026-11-12 (owner ruling, reverses this bullet's identity):** the part-to-number move this bullet introduced is the DEFECT the legacy-decode bullet below removes. `IEC/FDAM 60038-1` is not "base 60038 with FDAM 1": the whole `60038-1` is the base designation. The equality machinery this bullet built (the stored layout `from_hash` rebuilds, the reader-triggered settle, `synthetic_base?` reading the class) is kept and holds on the corrected identity.
|
|
43
43
|
|
|
44
|
-
- **The legacy prefix faces decode onto the modern identity (owner ruling 2026-11-12; evidence: `data/iec/legacy-notation.md`; reverses #693's resolution).** The old notation prints the stage token BEFORE the base designation — the JTC1 ballot faces `IEC/FDAM 60038-1`, `ISO/IEC PDAM 12207`, `ISO/IEC PDAM 2 10646:2012`, `ISO/IEC FPDAM 9075/1`, `ISO/IEC FDAM 1 14496-12:2004`, and the IEC draft faces `IEC/DCOR 60038-1`, `IEC/DISH 60038-1`, `IEC CDISH 60050-191`. #693's model had resolved those by STEALING the designation's part for the supplement (`ensure_base` moved `@part` into `@number`), so the old face and the modern on-base face (`IEC 60038-1/FDAM 1`) disagreed on the same document's identity. The decode now: **the designation moves WHOLE onto the base** (number, part, subpart, and the date — old notation prints the base's year, and a draft supplement carries no publication date of its own), **the supplement's number defaults to 1** (the no-number rule: an unnumbered DAM/PDAM/FDAM/FPDAM/DCOR/DISH means Amendment/Corrigendum/Interpretation-Sheet 1), and **the base is a concrete `InternationalStandard`**, not the synthetic `SingleIdentifier` — that concreteness is what makes the legacy face hash-match (and equal) the modern parse: `parse("IEC/DCOR 60038-1") == parse("IEC 60038-1/DCOR 1")`. The render is the modern on-base slash face (`IEC 60038-1/
|
|
45
|
-
**Two grammar halves.** The DAM-family prefix faces (`DAM`/`PDAM`/`FDAM`/`FPDAM`, spelled literally in the rule so the typed_stages table stays put for them) raised on main; the new `legacy_supplement` rule in `pubid-grammar` captures `legacy_stage`, the optional `legacy_supplement_number` (N before the base), and the base designation — including the old slash-part spelling (`FPDAM 9075/1` = base 9075, part 1; captured as `legacy_base_number` + `legacy_base_part`, and ordered BEFORE the dash-part alternative because `number_with_part` also matches a bare "9075", which would have left the "/1" dangling). The rule sits ahead of `standalone_supplement` in the ordered choice so both the slash and space faces reach it, and its date rides with the designation. PDAM/FPDAM joined the `iec_typed_stages` table and `Amendment::TYPED_STAGES` (stage codes mirror ISO's entries: PDAM at the CD level, FPDAM at the FDIS level; the LEAD harmonized codes are the circulation slots 30.20/50.20 — ISO's 30.00/50.00 are CDAM's and FDAM's (type, leading code) URN keys). The non-DAM draft faces (DCOR, FDCOR, CDISH, DISH, and any typed standalone with a designation-shaped token) already parsed; they are corrected by `ensure_base`, so the two paths converge on one decode. **The discriminator between a legacy face and a true standalone is the PART:** a designation token (`60038-1`, `9075/1`) moves whole onto the base; a bare ordinal (`IEC/AMD 1:2017`) is the supplement's own number and keeps the synthetic self-base (`IEC Amd 1-1:2017`, unchanged). Under the JTC1 reading a bare number after a DAM-family token is a base designation (`IEC FDAM 60038` → `IEC 60038/
|
|
44
|
+
- **The legacy prefix faces decode onto the modern identity (owner ruling 2026-11-12; evidence: `data/iec/legacy-notation.md`; reverses #693's resolution).** The old notation prints the stage token BEFORE the base designation — the JTC1 ballot faces `IEC/FDAM 60038-1`, `ISO/IEC PDAM 12207`, `ISO/IEC PDAM 2 10646:2012`, `ISO/IEC FPDAM 9075/1`, `ISO/IEC FDAM 1 14496-12:2004`, and the IEC draft faces `IEC/DCOR 60038-1`, `IEC/DISH 60038-1`, `IEC CDISH 60050-191`. #693's model had resolved those by STEALING the designation's part for the supplement (`ensure_base` moved `@part` into `@number`), so the old face and the modern on-base face (`IEC 60038-1/FDAM 1`) disagreed on the same document's identity. The decode now: **the designation moves WHOLE onto the base** (number, part, subpart, and the date — old notation prints the base's year, and a draft supplement carries no publication date of its own), **the supplement's number defaults to 1** (the no-number rule: an unnumbered DAM/PDAM/FDAM/FPDAM/DCOR/DISH means Amendment/Corrigendum/Interpretation-Sheet 1), and **the base is a concrete `InternationalStandard`**, not the synthetic `SingleIdentifier` — that concreteness is what makes the legacy face hash-match (and equal) the modern parse: `parse("IEC/DCOR 60038-1") == parse("IEC 60038-1/DCOR 1")`. The render is the modern on-base slash face, and for a draft stage it is the SPACED ballot face (`IEC 60038-1/FDAM 1`; owner ruling 2026-11-14 — the stored/citation twins are spaced: the frozen corpus carries the spaced `/FDAM 1`-family rows against only the decode-wave glued rows, and published amendments stay glued `/AMD1:2019`), so the legacy face is not a spelling facet — it is decoded, IHO-style. The discriminator is the typed stage's own published mark (`stage_code == :published` keeps glued `Amd`/`Cor`/`ISH`; every draft stage prints token + space + number in `Renderer#render_supplement_attached`).
|
|
45
|
+
**Two grammar halves.** The DAM-family prefix faces (`DAM`/`PDAM`/`FDAM`/`FPDAM`, spelled literally in the rule so the typed_stages table stays put for them) raised on main; the new `legacy_supplement` rule in `pubid-grammar` captures `legacy_stage`, the optional `legacy_supplement_number` (N before the base), and the base designation — including the old slash-part spelling (`FPDAM 9075/1` = base 9075, part 1; captured as `legacy_base_number` + `legacy_base_part`, and ordered BEFORE the dash-part alternative because `number_with_part` also matches a bare "9075", which would have left the "/1" dangling). The rule sits ahead of `standalone_supplement` in the ordered choice so both the slash and space faces reach it, and its date rides with the designation. PDAM/FPDAM joined the `iec_typed_stages` table and `Amendment::TYPED_STAGES` (stage codes mirror ISO's entries: PDAM at the CD level, FPDAM at the FDIS level; the LEAD harmonized codes are the circulation slots 30.20/50.20 — ISO's 30.00/50.00 are CDAM's and FDAM's (type, leading code) URN keys). The non-DAM draft faces (DCOR, FDCOR, CDISH, DISH, and any typed standalone with a designation-shaped token) already parsed; they are corrected by `ensure_base`, so the two paths converge on one decode. **The discriminator between a legacy face and a true standalone is the PART:** a designation token (`60038-1`, `9075/1`) moves whole onto the base; a bare ordinal (`IEC/AMD 1:2017`) is the supplement's own number and keeps the synthetic self-base (`IEC Amd 1-1:2017`, unchanged). Under the JTC1 reading a bare number after a DAM-family token is a base designation (`IEC FDAM 60038` → `IEC 60038/FDAM 1`), not a self-base mangle — that residue from the #693 bullet is gone.
|
|
46
46
|
**Measured by the replay gate, not the suite alone:** over all 26,838 full-fixture inputs, `to_s`/`to_urn`/`to_mr_string`/`to_hash`/class/`root.number` are byte-identical to the `main` baseline EXCEPT exactly the 6 #693-era standalone rows (both faces of FDAM/DCOR/DISH `60038-1`), which re-resolve to the corrected identities; 0 inputs stopped parsing; the prefix faces go raise→parse (12,491 full entries → 12,359 pass, fail steady at 132). #693's equality invariant (`parse == from_hash(to_hash)`) holds on every corrected identity. Locked by `spec/pubid/iec/standalone_supplement_round_trip_spec.rb` (rewritten: legacy faces decode and equal their modern parses, the self-base standalone keeps its form), `stage_separator_spec.rb`, `amendment_spec.rb`, `corrigendum_spec.rb`, `interpretation_sheet_spec.rb`, and the pass fixtures re-pinned by `validation:classify`. **Remaining gaps, deliberately open:** the dotted on-base `/Amd.1` spelling still raises in the IEC flavor (ISO accepts it), and the stamped prefix faces (`ISO/IEC FPDAM 10373-6/Amd 9:2001`, `ISO/IEC PDAM 9541-1/Amd.4`, `ISO/IEC FDAM 19776-2:2005/Am1:2006`, `ISO/IEC PDAM TR 9573-11/Amd.1`) stay raising — their on-base amendment stamps need the dotted/ISO stamp spellings the IEC flavor does not carry (gap 4 of the draft); the ISO-side agent owns that study.
|
|
47
47
|
|
|
48
48
|
## pubid-scheme URN (issue #670; gaps closed by #687)
|
|
@@ -46,9 +46,10 @@ module Pubid
|
|
|
46
46
|
type_code: :cor,
|
|
47
47
|
# "CDCOR" is the all-caps spelling the attached-supplement
|
|
48
48
|
# renderer emits (abbr.first.upcase) when a legacy prefix face
|
|
49
|
-
# decodes onto a CDCor draft ("IEC/CDCor 60038-1" renders
|
|
50
|
-
# "IEC 60038-1/
|
|
51
|
-
# render re-parses. abbr.first stays
|
|
49
|
+
# decodes onto a CDCor draft ("IEC/CDCor 60038-1" renders the
|
|
50
|
+
# spaced draft face "IEC 60038-1/CDCOR 1"); appended as an
|
|
51
|
+
# alias so the canonical render re-parses. abbr.first stays
|
|
52
|
+
# "CDCor" (spelling-only).
|
|
52
53
|
abbr: ["CDCor", "CDCOR"],
|
|
53
54
|
short_abbr: "CDCor",
|
|
54
55
|
long_abbr: "CD Cor",
|
data/lib/pubid/iec/renderer.rb
CHANGED
|
@@ -10,7 +10,7 @@ module Pubid
|
|
|
10
10
|
# "IEC 60038:2009"
|
|
11
11
|
# "IEC/CD 60038"
|
|
12
12
|
# "IEC 60038:2009/AMD1:2011"
|
|
13
|
-
# "IEC
|
|
13
|
+
# "IEC 60038-1/FDAM 1" (draft supplement: spaced ballot face)
|
|
14
14
|
# "IEC 60529:1989+AMD1:1999 CSV"
|
|
15
15
|
#
|
|
16
16
|
# The renderer is registered as the `:human` format in the IEC format
|
|
@@ -119,7 +119,7 @@ module Pubid
|
|
|
119
119
|
parts << id.base.to_s(**opts)
|
|
120
120
|
|
|
121
121
|
abbr = id.typed_stage.abbr.first.upcase
|
|
122
|
-
supp_part = "/#{abbr}#{id.number}"
|
|
122
|
+
supp_part = "/#{abbr}#{ballot_number_separator(id)}#{id.number}"
|
|
123
123
|
supp_part += ":#{id.date.render(context:)}" if id.date
|
|
124
124
|
parts << supp_part
|
|
125
125
|
|
|
@@ -128,6 +128,22 @@ module Pubid
|
|
|
128
128
|
parts.join
|
|
129
129
|
end
|
|
130
130
|
|
|
131
|
+
# Draft-stage supplements carry the ballot face: stage token, SPACE,
|
|
132
|
+
# number ("60038-1/FDAM 1", "60038-1/DCOR 1.3") — the spaced
|
|
133
|
+
# citation form the stored twins carry (the ISO corpus holds
|
|
134
|
+
# /FDAM 1, /PDAM 1, /FPDAM 2, /DAM 2.3:2022, /DCOR 1.3, /DISH 1 …;
|
|
135
|
+
# the published faces have no spaced twin). The published stages
|
|
136
|
+
# (stage_code :published — Amd/Cor/ISH) keep the glued
|
|
137
|
+
# corpus-dominant face ("60038-1/AMD1:2011"). The separator only
|
|
138
|
+
# rides when there is a number, so a numberless supplement renders
|
|
139
|
+
# the bare stage token on either side.
|
|
140
|
+
def ballot_number_separator(id)
|
|
141
|
+
return "" unless id.number
|
|
142
|
+
return "" if id.typed_stage.stage_code.to_s == "published"
|
|
143
|
+
|
|
144
|
+
" "
|
|
145
|
+
end
|
|
146
|
+
|
|
131
147
|
def render_consolidated(id, opts, _context)
|
|
132
148
|
id.identifiers.map.with_index do |sub_id, idx|
|
|
133
149
|
if idx.zero?
|
|
@@ -103,7 +103,7 @@ module Pubid
|
|
|
103
103
|
# 2026-11-12, reversing #693's part-to-number move, which stole the
|
|
104
104
|
# base's part for the supplement). The concrete base is what makes the
|
|
105
105
|
# decode hash-match (and equal) the modern on-base parse of the same
|
|
106
|
-
# document: `parse("IEC/DCOR 60038-1") == parse("IEC 60038-1/
|
|
106
|
+
# document: `parse("IEC/DCOR 60038-1") == parse("IEC 60038-1/DCOR 1")`.
|
|
107
107
|
#
|
|
108
108
|
# A supplement with no part (a true standalone like "IEC/AMD 1:2017",
|
|
109
109
|
# or a bare "+AMD1:2008" in a consolidation) keeps its own number and
|
data/lib/pubid/version.rb
CHANGED