cimas sync 2026-07-08: rubocop todo inherit fix + release.yml bundle install#90
Open
opoudjis wants to merge 22 commits into
Open
cimas sync 2026-07-08: rubocop todo inherit fix + release.yml bundle install#90opoudjis wants to merge 22 commits into
opoudjis wants to merge 22 commits into
Conversation
* Add pubid-iho gem for IHO publication identifiers New gem parses and renders IHO (International Hydrographic Organization) identifiers across the S, P, M, B, and C series, including letter-suffixed numbers (S-5A), colon/slash/hyphen sub-publications (S-158:100, P-1/21, P-6-3), appendices (S-65 Ap. B), and the Part syntax requested in relaton/relaton-iho#23 (S-100 Part 1). The IHO prefix is optional on input and always emitted on output. Wired into the meta-gem, release order, and integration dependency chain spec. * Add pubid-iho gem dependency to Gemfile
Lets pubid-iho parse and render forms like "IHO S-100 Annex A 5.2.0" and "IHO S-98 Annex C 1.0.0". Annex is a single uppercase letter, following the IHO usage observed in metanorma/iho-s-100 (Annex A "Terms and Definitions") and metanorma-iho#344 (S-98 Annex A/B/C). Mirrors the existing `appendix` plumbing: parser rule, identifier attribute, renderer method, plus round-trip spec cases (with and without version, with the IHO prefix optional on input). Refs relaton/relaton-iho#23.
Three additions to the IHO grammar, all driven by metanorma-iho#344: * `Appendix` is accepted as an input alias for `Ap.` (canonical form remains `Ap.` for backwards compatibility with the existing `IHO S-65 Ap. A` / `IHO S-53 Ap. 1` data and specs). * Appendix value extended from `digits | letter` to also accept `letter-digits` (e.g. `Appendix D-2` for S-122/S-123). * New `Suppl <digits>` rule and `:supplement` attribute, used by S-66 Supplements 1–4. Adds 6 round-trip cases plus the Appendix-canonicalisation pair in identifier_spec; existing 28 cases still pass (34 examples total). Refs relaton/relaton-iho#23.
* Add i18n for ITU annex-to-Special-Publication identifiers Implements localized rendering of "Annex to ITU-T OB ..." identifiers in fr/es/ar/ru/zh, with both short (structural) and long (title-style) forms via `to_s(language:, format: :long)`. Caller pattern matches metanorma-itu PR #497 (front_id.rb#itu_id_lang). Refs metanorma/pubid-itu#43. * Differentiate i18n_lang (rendering text) from language (document) Adds an `i18n_lang:` kwarg to `Pubid::Itu::Identifier#to_s` that controls identifier text translation, separate from the identifier's `language` attribute (which remains the document's own language and produces the trailing "-F"/"-S" suffix). The two can now be set independently: Pubid::Itu::Identifier.create(language: :fr, ...) .to_s(i18n_lang: :en) # => "Annex to ITU-T OB No. 1000-F" `language:` on `to_s` is retained as a deprecated alias for `i18n_lang:` to preserve backward compatibility for callers that already conflated the two (notably metanorma-itu PR #497). Refs #38 (comment). * Address PR #38 review: unify fr/es short=long, add German i18n * French and Spanish short forms now use the same `annex_long` template as their long forms (`Annexe au BE de l'UIT 1000-F`, `Anexo al BE de la UIT N.º 1000-S`). ITU itself uses the localized abbreviation `BE` rather than mixing the English `OB` into French or Spanish text. * German `i18n_lang: :de` now works: `annex_to.de` adds the "Anhang zum" prefix, producing `Anhang zum ITU-T OB No. 1000`. German is not an official ITU language so there is no `annex_long` template and no language-suffix code. * `render_language` no longer emits a stub trailing dash when the language has no LANGUAGES code mapping (fixes the `Anhang zum ITU OB 1000-` artifact reported in the review). The `ITU OB` vs `ITU-T OB` issue (ITU drops the sector for the Operational Bulletin) is intentionally deferred per @opoudjis. Refs #38 (comment). * Reject sector for OB (cross-bureau publication) OB (Operational Bulletin) is a cross-bureau ITU publication and must never be associated with a single bureau (T, R, D). The API now enforces this. * Identifier::Base#initialize raises ArgumentError when series == "OB" and sector is set. Direct callers must omit the sector. * Identifier::Base.transform (parser path) silently strips the sector when series is OB, so legacy strings like "ITU-T OB.1096" still round-trip — they normalize to "ITU OB No. 1096". * Renderer omits the "-sector" separator when sector is empty, so rendered OB identifiers are "ITU OB No. 1000" rather than "ITU-T OB No. 1000". Test fixture updates: existing OB parse fixtures updated to expect the normalized form; OB create fixtures drop sector: "T". New tests for the validation and the parse-time normalization. Heads-up for downstream callers: metanorma-itu PR #497 front_id.rb sets bureau ||= "T" unconditionally, which will now raise for OB. The caller needs to skip the bureau when series == "OB". Refs #38 (comment).
The auto-generated cassette path spec/vcr_cassettes/Pubid_Nist_Identifier_Base/generate_NIST_PubID_string_outputs/identifier_from_NIST_Tech_Pubs/parse_identifiers_successfully.yml exceeded Windows MAX_PATH (260 chars) when checked out under Bundler's deep vendor directory, breaking metanorma-plateau Windows GHA builds. Override the cassette name explicitly so the path is no longer derived from nested RSpec context descriptions. Fixes #49
Two `part_matcher` greediness bugs in `pubid-iso` surfaced by the ISO
Open Data deliverables dump:
- An alphabetic part code starting with a Roman-numeral letter (C, D,
I, L, M, V, X) was misparsed because `roman_numerals >> digits.absent?`
consumed the leading letter (e.g. `C` of `CS`) and left the rest of
the part unconsumed. Add a negative lookahead so the Roman branch
only succeeds when not followed by another uppercase letter.
- `ISO N/Add M` (no part, no year) failed because `part_matcher`
greedily matched `/A` as a single-letter part, leaving `dd M`
unparseable. The `Amd`/`Cor` variants worked because those tokens are
blocked by `supplements.absent?`; `Add` is handled by the separate
`addendum` rule and had no equivalent guard. Add `(str("Add") |
str("ADD")).absent?` to mirror that protection.
Together these fix 50 distinct identifiers in the ISO Open Data
deliverables dataset (plus all `Withdrawn N/Add M` rows that
relaton-iso rewrites to `ISO N/Add M` upstream).
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two parser/normalization gaps surfaced by the ISO Open Data deliverables dump (~80k references): - `<stage> <type> <num>` and `<typed_stage> <type> <num>` shapes were rejected because `std_document_body` only allowed a single prefix slot before the number. `ISO/IEC WD TR 14143-5` worked (WD in slot 1, TR in slot 2) but `ISO/IEC DIS TR 14143-5`, `ISO/IEC WD ISP 11182-3`, `ISO/IEC NP ISP 29110-4-2` did not. Refactor slot 2 to allow an optional stage/typed_stage followed by an optional type, which lets the natural `<stage|typed_stage> <type>` order parse. - `DIS <type>` and `FDIS <type>` are long-form spellings of canonical draft typed-stages (`DTR`, `FDTR`, `DPAS`, `FDPAS`, `DTS`, `FDTS`, `DISP`, `FDISP`). Add two regex normalizations to `update_codes.yaml` that rewrite the long form to the canonical short form before parsing. - Lowercase letter / `xx` part suffixes from early-stage `ISO/NP 10303` references (`-5a`, `-5b`, `-1xx`, `-2xx`) are non-canonical spellings. Add four explicit `update_codes.yaml` entries to normalize them to the uppercase canonical form, which already parses. Together these eliminate 55 distinct identifier failures from the ISO Open Data deliverables sweep (64 → 9 after the previous PR's 257 → 64; the remaining 9 are stage-prefixed supplements, addressed separately).
…rse (#58) Closes the last 9 parser failures from the ISO Open Data deliverables sweep, and corrects a latent `part_matcher` greediness bug that was producing incorrect AST for stage-prefixed supplements on identifiers with no part or year. ## part_matcher misparse (root cause) Inputs like `ISO 9000/WD Amd 1` were "parsing" but with the stage `WD` greedily eaten as a part code, yielding the wrong AST and the wrong round-trip output `ISO 9000-WD/Amd 1`. The same shape with `Add` instead of `Amd` failed outright (since `Add` is not in `SUPPLEMENTS` the rest of the rule chain couldn't recover). Both manifest the same underlying issue: `part_matcher` did not reject stage tokens followed by a supplement keyword. Two new absence guards in `part_matcher`: - `staged_supplement.absent?` — blocks `DAM`, `DCOR`, `DSuppl` etc. - `((stage | typed_stage) >> space >> (supplements | "Add" | "ADD")).absent?` — blocks `WD Amd`, `PWI Add`, `DIS Cor`, `CD Suppl`, etc. Existing specs only used these forms with a part or year (which routes around `part.maybe`), so the misparse was dormant — no test regressions. ## addendum rule extension `Add` was the only supplement keyword without a stage-prefix path in its grammar rule. Add an optional `stage.as(:typed_stage) >> space` prefix mirroring the supplement rule, enabling `WD Add`, `PWI Add`. ## update_codes.yaml normalizations Six regex entries rewrite long-form `DIS|FDIS <supplement-type>` to the canonical short staged-supplement token (which `staged_supplement` already accepts): - `/DIS Amd ` → `/DAM `, `/FDIS Amd ` → `/FDAM ` - `/DIS Cor ` → `/DCOR `, `/FDIS Cor ` → `/FDCOR ` - `/DIS Suppl ` → `/DSuppl ` - `/DIS Add ` → `/DAD ` Plus a `/DAdd ` → `/DAD ` entry for the legacy long-form Draft Addendum spelling. ## Result ISO Open Data sweep: 9 → 0 failures (cumulative across PRs #56, #57: 257 → 0).
…ge) (#70) Annotated rendering (#27) wrapped every prerendered param value in a <span> inside Pubid::Core::Renderer::Base#prerender_params. The ISO renderer, however, renders :stage in two phases: render_stage returns the Stage object unchanged during prerender, and postrender_stage renders it later in the overridden #render_identifier. With annotated: true, phase one stringified the Stage into a <span> String, so phase two's stage.empty_abbr? raised NoMethodError: undefined method 'empty_abbr?' for an instance of String This broke to_s(annotated: true) for every staged ISO identifier (ISO/DIS, ISO/CD, ISO/FDIS, ISO/NP, ISO/WD, ISO/AWI, ISO/DTR, ...). Published (no-stage) and pure-type (TR/TS) identifiers were unaffected, which is why the existing annotated_spec — covering only TR — missed it. Guard prerender annotation to String-rendered values only; deferred domain objects (Stage) are left intact for the subclass's phase-two handling, which already annotates them via annotate_value(:stage, ...). Adds stage regression coverage to pubid-iso annotated_spec.
Amendment#urn and Corrigendum#urn raised NoEditionError unless the base document had an edition, even though the URN renderer produces a valid URN without one (e.g. ISO 10231:2003/Amd 1:2015 -> urn:iso:std:iso:10231:amd:2015:v1, which the spec already declared as the expected URN). The parent Supplement#urn renders unconditionally; only these two subclasses added the guard. The raise broke serialization of working-draft amendments whose base has no edition (e.g. ISO/IEC 23008-1/WD Amd 1) in downstream consumers that render the URN during round-trip serialization (relaton-bib deep_clone). Drop the guard so both render like their parent. Update the amendment spec that asserted the raise to assert the round-trip URN, and add forward URN coverage to the editionless corrigendum context.
…release_command bundle install) request-checks: true
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Supersedes #88 from prior cimas-sync waves.
Summary
Cimas sync 2026-07-08 — master template corrections for two release-adjacent gaps:
.rubocop.yml— appended.rubocop_todo.ymlas the lastinherit_fromentry so per-gem todos take effect against the shared oss-guides config.inherit_fromis last-wins; the previous ordering left the shared config's stricterMetrics/*rules overriding per-gem grandfathering, and the todo became inert. Empirically verified on suma 2026-07-06: with the todo listed first, 34Metrics/*offenses remained; moved last, cleared. Audit confirmed all 54 gems mapping this template already carry a live.rubocop_todo.yml, so this reference is safe to emit unconditionally. Seemetanorma/ci:a864ed9..github/workflows/release.yml— added explicitrelease_command: | bundle install\n bundle exec rake release, compensating formetanorma/ci#314'sbundler_cachedeprecation (hardcoded tofalsein the release job after the metanorma-cli v1.16.6Bundler::GemNotFound: metanorma-nistincident). Without this override, the reusable's defaultrelease_command: bundle exec rake releasefires against uninstalled gems and fails. Surfaced by @kwkwan on metanorma-plugin-lutaml#285; deeper fix (bundle installinsiderubygems-release.yml's release job itself) tracked atmetanorma/ci#349. Seemetanorma/ci:f994f4c.What to expect on your gem
.rubocop_todo.ymlcovers current offenses: CI stays green..rubocop_todo.ymlhas plugin-drift (missed cops from ci#334'srubocop-rspec/rubocop-performance/rubocop-rakeaddition, or subsequent minor releases of those plugins): CI will red on rubocop-style failures. Fix per-gem:bundle exec rubocop --regenerate-todo— same recipe as sts-ruby / suma on 2026-07-05.release.ymlis template-only: no runtime effect until the gem's next release, at which point the two-linerelease_commandkicks in and fixes the missing-bundle-install failure that was silent-broken before.Wave discipline
--flatten-stalefull auto-close of prior stalecimas-sync-*wave branches on this repo.🤖