pubid 2.0.0.pre.alpha.16 → 2.0.0.pre.alpha.18
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/parg/ieee.json +1 -1
- data/lib/pubid/ieee/CLAUDE.md +2 -0
- data/lib/pubid/ieee/builder.rb +12 -6
- data/lib/pubid/ieee/components/draft.rb +6 -1
- data/lib/pubid/ieee/identifiers/joint_development.rb +32 -17
- data/lib/pubid/version.rb +1 -1
- metadata +1 -1
data/lib/pubid/ieee/CLAUDE.md
CHANGED
|
@@ -95,3 +95,5 @@ The lesson BSI paid for: a wrapper's hand-written `#number` delegation makes the
|
|
|
95
95
|
- **`all_parts_edition_keys` missed `revision`, `reaffirmed` AND `edition_month` — three gaps, found in two passes.** `Identifier.all_parts_edition_keys` defaults to `%i[date year edition version]`. A first pass fixed IEEE's `revision` attribute (the numbered/lettered draft revision id — "2" in "P802.16Rev2"), a separate discriminator from `edition`/`year` that this list never covered, so `"IEEE P802.16Rev2".to_all_parts === "IEEE P802.16Rev3"` was `false` — two revisions of the same draft failed to collapse. Code review of that same change then found it had stopped one attribute too early: `reaffirmed` (the "(R2010)" year, read by `renderer.rb` and `urn_generator.rb`) meant two reaffirmations of the same standard — `"IEEE Std 218-1956 (R1980) …"` vs `"… (R1990) …"` — also failed to collapse; and `edition_month`, the month half of the `"Edition N YYYY-MM"` rendering (`renderer.rb`'s `"Edition #{edition} #{year}-#{edition_month}"`), survived even though its sibling `year` is already in the default list, so `"IEEE Std 802.11 Edition 3.0 2015-03"` didn't match `"… 2015-06"`. All three fixed together: `Pubid::Ieee::Identifier.all_parts_edition_keys` is `super + %i[revision reaffirmed edition_month]`. Not on the original hand-off's audit list (which didn't cover IEEE); found during code review of the OGC/3GPP/NIST fix for the same class of bug. **Lesson**: finding one missed attribute on a flavor does not mean the audit of that flavor is finished — check every date/edition/version/revision/reaffirmation-shaped attribute against the renderer and builder, not just the one the bug report named (see the root `CLAUDE.md` bullet). Locked by `spec/pubid/all_parts_edition_keys_audit_spec.rb`.
|
|
96
96
|
|
|
97
97
|
- **The project designator format, and the bare-P parse that dropped it (pubid#18).** IEEE's own draft documents are cited by their short designator — "P1201/D0.3", "P10000/D1.2" — and metanorma-ieee had to post-process the full rendering to produce it. Two edits. **(1) `format: :project`** registers `Pubid::Ieee::ProjectRenderer` in the IEEE format registry: the code (with parts), a PREPENDED "P" when the identifier is a project but the code does not already carry it, and "/D<draft>"; no publisher, no type word, no date. "Project" is detected in all three places a marker can live depending on the building path — `code_obj.prefix` (the bare spelling), the "P" type code, or a `typed_stage` with `project_status` (D1-D6). **(2) The bare-P data loss**: `ieee_p_identifier` consumed its leading "P" with a bare `str("P")`, so "P1201/D0.3" parsed WITHOUT its P anywhere (the number was "1201", prefix nil) — the issue's complaint verbatim. The rule now lets `number` capture the P (the #318 pattern), so `code.prefix` survives and the designator has something to read. The DEFAULT rendering is unchanged — the corpus keeps the P in every unapproved-draft canonical, and #318's idempotence work locked that; the issue's suggestion that the default drop the P predates the corpus and is not adopted. A published (non-project) id renders its bare number under `:project` — the format is a draft-designator view.
|
|
98
|
+
|
|
99
|
+
- **Joint stage-first forms are lead ISO, and the ISO face is lossless (pubid#477)**: a stage word printed in the ISO position (`IEEE FCD 15026.3:2010`, `IEEE/IEC CD2 P62582-2017-05`) parses as printed (#469): `Builder#build_joint_development` sets `lead_party "ISO"` whatever the publisher order, so `canonical_format` is `:iso`. PR #472 had made the lead the first printed publisher and rendered an IEEE-first form in the `D=` face — but the grammar artifact cannot parse most of those renders (`D=FCD`, `D=CD.2`, a non-P number, a month), and `D=CD-2020` parses into a *different* id (`ieee_draft`, no `iso_stage`), so 19 published `relaton-data-ieee` rows stopped matching themselves. The `D=` face now prints only for an id that carries a `D=` designator, or on an explicit `to_s(format: :ieee)`. `JointDevelopment#to_iso_format` prints `iso_stage` as stored (`DIS2`, `CD4` — #472's bare `CD` lost the iteration) and the date in the spelling that parses back (`#iso_date_suffix`: `:2018`, `-2018-05`, `, April 2019`). **The test is `parse(to_s) == id`, not a stable `to_s`**: a lossy render reaches a fixed point and round-trips its *hash* (`iso_stage_spellings_spec` held both while dropping `CD4`→`CD`), yet the reparse is a different identifier. Measured over the 118 joint stage rows of `relaton-data-ieee`: `to_s` stable 100 → 118, `==` 51 → 106; the other 12 carry an `ieee_draft` or an edition that the ISO face still drops. **PARG separator-in-capture, again (#471)**: the draft `revision` capture is `".12"`, and `Draft#to_s` adds its own dot, so `handle_draft` strips the leading dot (`D2022.10.12` rendered `D2022.10..12`). Check every capture a renderer re-joins with a separator. Locked by `spec/pubid/ieee/joint_stage_roundtrip_spec.rb` (stored index hashes → `parse(to_s) == row`).
|
data/lib/pubid/ieee/builder.rb
CHANGED
|
@@ -861,11 +861,12 @@ module Pubid
|
|
|
861
861
|
|
|
862
862
|
# Detect lead party based on pattern
|
|
863
863
|
if parsed[:iso_stage]
|
|
864
|
-
# ISO stage word present
|
|
865
|
-
#
|
|
866
|
-
#
|
|
867
|
-
#
|
|
868
|
-
|
|
864
|
+
# ISO stage word present: the reference is printed in the ISO
|
|
865
|
+
# position ("IEEE FCD 15026.3:2010"), so it parses as printed
|
|
866
|
+
# (pubid#469) - lead ISO, ISO face, whatever the publisher
|
|
867
|
+
# order. The printed first publisher is not the arrangement, and
|
|
868
|
+
# the published relaton-data-ieee rows carry lead ISO (pubid#477).
|
|
869
|
+
attributes[:lead_party] = "ISO"
|
|
869
870
|
attributes[:iso_stage] = extract_value(parsed[:iso_stage])
|
|
870
871
|
|
|
871
872
|
# Create typed_stage for ISO stage
|
|
@@ -1471,7 +1472,12 @@ module Pubid
|
|
|
1471
1472
|
version = version.sub(/\A-/, "") if version
|
|
1472
1473
|
end
|
|
1473
1474
|
|
|
1474
|
-
|
|
1475
|
+
# The PARG capture carries its separator (".12", the #471
|
|
1476
|
+
# convention); Draft#to_s prints the dot itself, so keep only
|
|
1477
|
+
# the digits or "D2022.10.12" renders "D2022.10..12" (pubid#477).
|
|
1478
|
+
if draft_data[:revision]
|
|
1479
|
+
revision = extract_value(draft_data[:revision])&.delete_prefix(".")
|
|
1480
|
+
end
|
|
1475
1481
|
|
|
1476
1482
|
# The compound both-systems form (docs/IEEE-DRAFT-STAGES.md
|
|
1477
1483
|
# §1.3): the stage half of "=DDIS.3".
|
|
@@ -143,7 +143,12 @@ day: nil, iso_stage: nil, iso_iteration: nil)
|
|
|
143
143
|
result = "/D#{version}"
|
|
144
144
|
result += "=#{iso_stage}" if iso_stage
|
|
145
145
|
result += ".#{iso_iteration}" if iso_stage && iso_iteration
|
|
146
|
-
result +=
|
|
146
|
+
result += if revision.to_s.start_with?(".")
|
|
147
|
+
# a captured revision may carry its separator dot
|
|
148
|
+
revision.to_s
|
|
149
|
+
else
|
|
150
|
+
".#{revision}"
|
|
151
|
+
end if revision
|
|
147
152
|
|
|
148
153
|
if year
|
|
149
154
|
# Use original month format to preserve abbreviated vs full names
|
|
@@ -69,6 +69,10 @@ module Pubid
|
|
|
69
69
|
# Set lead_party if not provided - default to first publisher
|
|
70
70
|
if args[:lead_party]
|
|
71
71
|
self.lead_party = args[:lead_party]
|
|
72
|
+
elsif iso_stage
|
|
73
|
+
# A stage-first reference is lead ISO, as the builder sets it
|
|
74
|
+
# (pubid#477) — a hand-built id must agree with a parsed one.
|
|
75
|
+
self.lead_party = "ISO"
|
|
72
76
|
elsif publishers && !publishers.empty?
|
|
73
77
|
# Lead party defaults to first publisher if not explicitly set
|
|
74
78
|
# Builder should override this with detected lead party
|
|
@@ -137,17 +141,13 @@ module Pubid
|
|
|
137
141
|
|
|
138
142
|
# The stage word is the ISO format's own position convention —
|
|
139
143
|
# it prints whenever the identifier carries one, regardless of
|
|
140
|
-
# lead party (the format face decides, not the arrangement).
|
|
141
|
-
# stage
|
|
142
|
-
#
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
#
|
|
146
|
-
|
|
147
|
-
# "DIS3" prints "DIS" — every iso_stage_spellings_spec
|
|
148
|
-
# expectation); the iteration is draft machinery, not ISO-face
|
|
149
|
-
# identity.
|
|
150
|
-
stage_word = iso_stage.to_s.sub(/\A([A-Z]+?)\d+\z/, '\1')
|
|
144
|
+
# lead party (the format face decides, not the arrangement).
|
|
145
|
+
# The stage prints as stored, iteration included ("DIS2",
|
|
146
|
+
# "CD4"): the face is lossless, so parse(to_s) == self
|
|
147
|
+
# (pubid#477). A stage-tracked D= designator decomposes into its
|
|
148
|
+
# stage word and date ("D=CD-2020" → "CD", 2020); the P project
|
|
149
|
+
# stage is IEEE convention and never prints here.
|
|
150
|
+
stage_word = iso_stage.to_s
|
|
151
151
|
stage_word = nil if stage_word.empty?
|
|
152
152
|
draft_year = nil
|
|
153
153
|
if stage_word.nil? &&
|
|
@@ -164,10 +164,9 @@ module Pubid
|
|
|
164
164
|
code_str += mark unless code_str.empty?
|
|
165
165
|
parts << code_str if code_str && !code_str.empty?
|
|
166
166
|
|
|
167
|
-
# Join with space and add
|
|
168
|
-
#
|
|
169
|
-
result = parts.join(" ")
|
|
170
|
-
result += ":#{year || draft_year}" if year || draft_year
|
|
167
|
+
# Join with space and add the date (a decomposed D= date rides
|
|
168
|
+
# here as the year).
|
|
169
|
+
result = parts.join(" ") + iso_date_suffix(year || draft_year)
|
|
171
170
|
# Only the language/edition marker ("(E)", "(E/F)") prints; a
|
|
172
171
|
# trailing relationship narrative is metadata, not identity.
|
|
173
172
|
if parenthetical_content&.match?(%r{\A[A-Z](?:\s*[/&]\s*[A-Z])*\z})
|
|
@@ -177,6 +176,21 @@ module Pubid
|
|
|
177
176
|
result
|
|
178
177
|
end
|
|
179
178
|
|
|
179
|
+
# The ISO-face date, in the spelling that parses back to the same
|
|
180
|
+
# year and month: the colon year (":2018"); a numeric month glued
|
|
181
|
+
# with dashes ("-2018-05"); a text month as ", February 2015".
|
|
182
|
+
def iso_date_suffix(date_year)
|
|
183
|
+
return "" unless date_year
|
|
184
|
+
return ":#{date_year}" unless month
|
|
185
|
+
|
|
186
|
+
if month.match?(/\A\d+\z/)
|
|
187
|
+
# The grammar reads only a two-digit month ("05", never "5").
|
|
188
|
+
"-#{date_year}-#{month.rjust(2, '0')}"
|
|
189
|
+
else
|
|
190
|
+
", #{month} #{date_year}"
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
180
194
|
# Convert to IEEE format representation
|
|
181
195
|
# ISO/IEC/IEEE P26511/D8-2018
|
|
182
196
|
# @return [String] IEEE format string
|
|
@@ -195,8 +209,9 @@ module Pubid
|
|
|
195
209
|
|
|
196
210
|
# Add IEEE draft notation if available (e.g., /D8). An ISO stage
|
|
197
211
|
# word renders in IEEE's stage-tracked position as the ordinal-less
|
|
198
|
-
# stage draft (docs/IEEE-DRAFT-STAGES.md §1.3, spelling 7)
|
|
199
|
-
#
|
|
212
|
+
# stage draft (docs/IEEE-DRAFT-STAGES.md §1.3, spelling 7) — only
|
|
213
|
+
# on an explicit to_s(format: :ieee): a stage-first reference is
|
|
214
|
+
# lead ISO, so its canonical face is the ISO one (pubid#477).
|
|
200
215
|
# The iso_stage branch is checked FIRST — the typed_stage registry
|
|
201
216
|
# lookup for a stage word answers a draft-equivalent ordinal ("D2"),
|
|
202
217
|
# which is not the canonical stage-tracked spelling.
|
data/lib/pubid/version.rb
CHANGED