pubid 2.0.31 → 2.0.33
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/data/iso/update_codes.yaml +5 -0
- data/lib/pubid/iec/CLAUDE.md +2 -0
- data/lib/pubid/iec/identifier.rb +35 -0
- data/lib/pubid/iso/CLAUDE.md +21 -0
- data/lib/pubid/version.rb +1 -1
- 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: 8aef45a3d166689b823ce4ab85ab8651e066838a49ddf5b7d23e40345c1a9e0c
|
|
4
|
+
data.tar.gz: 0d9e256b0cfcdb8ba4354b7e16836e1a0f236f14f5f682bce0850504e4af16ae
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7cdbc8c5709b74a0a3298a56b79ea954a689a95f94868c2c3a0973ad5912c07581a03f797944caf5f62414ad71cb6c27f9a4b0243351b883962adc67a5b5b2ff
|
|
7
|
+
data.tar.gz: 00debefc3b8438a48a158c4a706817807f75e2489cc8a3f8ceb247ebd7598592aa4927c6a0942730db12dba5d7e9af0ae875d126f7d7a321732eb2d866e7388d
|
data/data/iso/update_codes.yaml
CHANGED
|
@@ -2,6 +2,11 @@ ISO/R 657/IV: ISO/R 657-4:1969
|
|
|
2
2
|
ISO/IEC/IEEE 8802-22.2:2015/Amd.2:2017(E): ISO/IEC/IEEE 8802-22:2015/Amd.2:2017(E)
|
|
3
3
|
ISO/TR 17716.2: ISO/TR 17716
|
|
4
4
|
ISO/TR 17716.2(E): ISO/TR 17716(E)
|
|
5
|
+
# Unassigned-part placeholder: ISO's open data writes `-_` where a
|
|
6
|
+
# multipart project has no part number yet ("ISO/NP TS 6041-_", title
|
|
7
|
+
# "… Part _: _No part"). It carries no identity, so drop it and leave the
|
|
8
|
+
# part nil (relaton/relaton-data-iso#43).
|
|
9
|
+
"/(\\d)-_(?=[\\s:\\/(]|$)/": '\1'
|
|
5
10
|
# Long-form draft typed stages (DIS TR, FDIS PAS, ...) → canonical short
|
|
6
11
|
# typed-stage abbrs (DTR, FDPAS, ...). DIS/FDIS are typed-stages of the
|
|
7
12
|
# IS class only — for TR/TS/PAS/ISP they have dedicated D<type>/FD<type>
|
data/lib/pubid/iec/CLAUDE.md
CHANGED
|
@@ -47,6 +47,8 @@ These notes were part of the root `CLAUDE.md`. Read them before you change `lib/
|
|
|
47
47
|
|
|
48
48
|
- **The dotted supplement sub-number survives (issue #725 — the gap the #724 wave recorded).** The ballot faces print it — `/DAM 2.3:2022`, `/DCOR 1.3` on the base, and the dotted base designation `60038-2.3` in the ballot-prefix faces — and the ISO flavor has always kept its dot (its declared field is `stage_iteration`, a `Components::Iteration`; the issue's "`sub_number`" label is prose for this facet). The IEC losses were NOT grammar-shaped: the raw bound hash already carried `supp_stage_iteration`/`stage_iteration` on every dotted shape — they were **build-side and render-side**: `Builder#build_supplement` dropped the peeled `stage_iteration` (so `/DAM 2.3:2022` silently renumbered to `DAM 2`), `ensure_base`'s designation-move left the dot on the supplement (so `IEC/FDAM 60038-2.3` held it as a facet of the implied FDAM 1 instead of the base), and both `Base#number_portion` and `render_supplement_attached` dropped the facet at print time (so even the losslessly-parsed `IEC 60038-2.3` rendered as its sub-number-less twin). The facet rides the layer whose designation carries the dot: the SUPPLEMENT for the on-base draft faces, the BASE for the ballot-prefix faces and the plain dotted base (`parse("IEC/FDAM 60038-2.3") == parse("IEC 60038-2.3/FDAM 1")` still holds — the legacy rule now claims the dotted designation itself, so the ballot face and the on-base face are the same identifier). The grammar change is width only: the three dot-sites (base `stage_iteration`, `supp_stage_iteration`, `supp2_stage_iteration`) admit `1*digit` instead of one digit (`\.\d+`; nothing downstream starts with a digit, so no guard), baked at the CI-pinned compiler. **Surfaces:** `to_s` renders the dot on both layers (`/DAM 2.3:2022`, `IEC 60038-2.3`), `to_hash` serializes it (the flat `stage_iteration` scalar), the pubid-scheme URN already had the `iter-` atom, and the official URN rides the dotted number in the supplement's number slot (`amd:2.3:2022`; ISO keeps the facet in its version atom — this scheme has none, so the number slot carries the designation as printed). The MR string stays iteration-less, matching ISO (`iso.10646_amd.2.2022` is also iteration-less). **Unattested shapes deliberately stay raising:** a dotted ballot NUMBER in the prefix faces (`IEC/DCOR 1.3 60038-2`, `ISO/IEC PDAM 2.3 10646:2012`) — no source prints it, so no identity is guessed for it. **Measured by the replay gate:** over all 26,861 full-fixture inputs, `to_s`/`to_hash`/`to_urn`/`to_mr_string`/class are byte-identical to the 2.0.30 baseline — 0 diffs (no corpus row carried the facet). Locked by `spec/pubid/iec/dot_subnumber_spec.rb` (the on-base, ballot-prefix, plain-base and raising rows) and the testsuite corpus round (pass rows in `pass/`, never `full/`). (hand-off: iec-dot-subnumber.)
|
|
49
49
|
|
|
50
|
+
- **The standalone no-part dotted face is rejected at parse (issue #727).** `IEC/AMD 1.2:2017` parsed and then LOST the dot at render: `render_supplement_standalone` prints the base number and the supplement's own number only, so the stored `stage_iteration` was dropped and `parse(to_s) != parse` — the URN (`amd:1.2:2017`) and `to_hash` carried a facet the canonical face cannot print. No IEC source prints a no-part standalone face with a dotted number (the facet is attested only on the on-base draft faces; 0 rows in the gem fixtures, the testsuite ledger or `relaton-data-iec`), so the shape is **rejected at parse** — the #726 ruling for unattested dotted shapes — rather than built unrenderable. **The crash the issue reported does not reproduce on the Ruby side, and that finding shaped the fix**: the Ruby renderer nil-guards `copublishers` (`copublishers&.any?`) and the parse path always materializes the publisher (the attribute default fills it; the only `publisher_portion` crash needs a hand-set `publisher = nil`, unreachable from parse and from_hash — verified at 2.0.29, the released 2.0.31 and main over a ~40-shape probe matrix); the crash in the issue came from pubid-ts#184's note, where the TS `publisherPortion` reads `copublishers` off a supplement whose table does not materialize the empty collection. So the nil-guard branch of the issue's suggested direction had nothing to guard, and the live Ruby defect was the lossy render on the same face. **The check is the SHAPE, not a grammar route**: `Identifier.parse` walks the built object's `base` chain after `ensure_base` and raises `ParseError` (with `input:`/`flavor:` set, `parse_failure_cause` nil — the synthetic-raise shape) when a `SupplementIdentifier` layer holds both a `stage_iteration` and a synthetic self-base. One condition covers all three parse routes — the `supp_*` standalone branch (`IEC/AMD 1.2:2017`), the publisher-less plain route (`AMD 1.2:2017`, bound as `type_with_stage` + `stage_iteration`, no `supp_` keys) and a dotted layer under an undotted second supplement (`IEC/AMD 1.2:2017/COR 1:2018`) — and none of the neighbours that keep the dot on a printable layer: the single-document draft faces (`IEC CD 1.2:2017`, `IEC/DTR 1.2:2017` — not supplements, the dot rides the base and `parse(to_s) == parse` holds), the DAM-family decodes (`IEC/DAM 1.2` → `IEC 1.2/DAM 1`, dot on the base designation) and the on-base faces (a real base, `synthetic_base?` false). The undotted standalone faces keep parsing with their #693 residue renders (`IEC/AMD 1:2017` → `IEC Amd 1-1:2017`). BSI's delegation (`bsi/single_identifier.rb` → `Pubid::Iec.parse`) and `Pubid.parse` routing raise through the same entry. **`from_hash` deliberately still deserializes the shape** (rendering the undotted face as it always did): parse can no longer produce the hash, no stored row carries it, and rejecting deserialization would hard-break a consumer cache holding a pre-#727 parse — the residue is pinned, not chased. **No corpus round follows** (the shape is unattested; nothing moves to `pass/`). Locked by the new blocks in `spec/pubid/iec/dot_subnumber_spec.rb`: the 11 raising rows with the message, the input/flavor/cause shape of the synthetic raise, the keep-parsing rows (render + `from_hash(to_hash) ==` + re-parse idempotence), the undotted residue rows, and the deserialization residue. (hand-off: iec-standalone-dotted-reject.)
|
|
51
|
+
|
|
50
52
|
## pubid-scheme URN (issue #670; gaps closed by #687)
|
|
51
53
|
|
|
52
54
|
`lib/pubid/iec/pubid_urn_schema.rb` completes the partial schema the IEEE
|
data/lib/pubid/iec/identifier.rb
CHANGED
|
@@ -275,9 +275,44 @@ module Pubid
|
|
|
275
275
|
# parse holds that layout before any reader runs
|
|
276
276
|
# (SupplementIdentifier#number).
|
|
277
277
|
id.ensure_base if id.is_a?(SupplementIdentifier)
|
|
278
|
+
reject_standalone_dotted_supplement(id, string)
|
|
278
279
|
id
|
|
279
280
|
end
|
|
280
281
|
|
|
282
|
+
# A supplement's OWN dotted sub-number has nowhere to print on the
|
|
283
|
+
# standalone (self-base) face: render_supplement_standalone prints the
|
|
284
|
+
# base number and the supplement number only, so the parsed dot was
|
|
285
|
+
# dropped at render and parse(to_s) != parse. No IEC source prints a
|
|
286
|
+
# no-part standalone face with a dotted sub-number — the facet is
|
|
287
|
+
# attested only on the on-base draft faces ("IEC 60038-2/DAM 2.3:2022")
|
|
288
|
+
# — so the shape is rejected here instead of being built unrenderable
|
|
289
|
+
# (pubid#727; the same ruling as the prefix-face dotted ballot numbers,
|
|
290
|
+
# which the grammar keeps raising). The walk reaches the dotted layer
|
|
291
|
+
# when it sits under an undotted second supplement ("/AMD 1.2:2017" as
|
|
292
|
+
# the base of a "/COR 1" chain). The single-document draft faces
|
|
293
|
+
# ("IEC CD 1.2:2017") and the DAM-family decodes ("IEC/DAM 1.2") keep
|
|
294
|
+
# their dot on a non-supplement layer and pass; the on-base faces have
|
|
295
|
+
# a real base, so synthetic_base? is false and they pass too.
|
|
296
|
+
STANDALONE_DOTTED_SUPPLEMENT_MESSAGE =
|
|
297
|
+
"the standalone no-part supplement face carries a dotted sub-number " \
|
|
298
|
+
"(e.g. \"IEC/AMD 1.2:2017\"): no IEC source prints one, and the " \
|
|
299
|
+
"standalone face has no layer to print the dot on, so the stored " \
|
|
300
|
+
"sub-number would be dropped at render — the dotted sub-number is " \
|
|
301
|
+
"attested only on the on-base draft forms"
|
|
302
|
+
|
|
303
|
+
def self.reject_standalone_dotted_supplement(id, input)
|
|
304
|
+
node = id
|
|
305
|
+
while node.is_a?(SupplementIdentifier)
|
|
306
|
+
if node.stage_iteration && node.synthetic_base?
|
|
307
|
+
raise Pubid::Errors::ParseError.new(
|
|
308
|
+
STANDALONE_DOTTED_SUPPLEMENT_MESSAGE, nil,
|
|
309
|
+
input: input, flavor: "iec"
|
|
310
|
+
)
|
|
311
|
+
end
|
|
312
|
+
node = node.base
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
|
|
281
316
|
# from_hash is the shared polymorphic dispatch on Pubid::Identifier.
|
|
282
317
|
# IEC_TYPE_MAP remains as the key_value polymorphic_map.
|
|
283
318
|
end
|
data/lib/pubid/iso/CLAUDE.md
CHANGED
|
@@ -207,3 +207,24 @@
|
|
|
207
207
|
`spec/pubid/iso/ballot_face_decode_spec.rb` (all 13 SSOT anchors, the
|
|
208
208
|
no-number rule, base-whole guards, Am alias, stored-twin agreement, and
|
|
209
209
|
the website-face-vs-stored-face drift rows the SSOT §5 records).
|
|
210
|
+
|
|
211
|
+
- **The unassigned-part placeholder `-_` is dropped before the parse
|
|
212
|
+
(relaton/relaton-data-iso#43).** ISO's open data
|
|
213
|
+
(`iso_deliverables_metadata.jsonl`) writes `-_` where a multipart project
|
|
214
|
+
has no part number yet — record 95616 is `ISO/NP TS 6041-_`, stage 10.20,
|
|
215
|
+
title "… Part _: _No part". The grammar's part body is word characters and
|
|
216
|
+
digits, so the id failed, and the relaton crawler left the file unindexed.
|
|
217
|
+
A `data/iso/update_codes.yaml` regex removes `-_` after a digit when a
|
|
218
|
+
separator (`:`, `/`, `(`, space) or the end follows, so the id parses as
|
|
219
|
+
`ISO/NP TS 6041` with a nil part. A nil part is the honest model (the part
|
|
220
|
+
is unknown), and `Pubid::Iso.parse` of the `-_` form (the call relaton's
|
|
221
|
+
crawler and lookup make) gives the same identifier as the index row. The
|
|
222
|
+
render is normalized, not byte-exact. No grammar or artifact change.
|
|
223
|
+
**Known gap:** the rule is ISO-only, and IEC's grammar accepts `_` as a
|
|
224
|
+
part, so `Pubid.parse("ISO 6041-_")` routes to IEC (an exact round trip
|
|
225
|
+
wins) with part `"_"`. The reported `ISO/NP TS 6041-_` still reaches ISO,
|
|
226
|
+
because IEC cannot read the NP stage. BSI and CSA delegate to ISO and get
|
|
227
|
+
the normalization. Over the whole open-data file (81,625
|
|
228
|
+
non-`Withdrawn` references, 2026-11-14) this was the only failure; the
|
|
229
|
+
`Withdrawn …` rows fail too, but the crawler skips them. Locked by
|
|
230
|
+
`spec/pubid/iso/update_codes_spec.rb`.
|
data/lib/pubid/version.rb
CHANGED