From 8e0137893dd79c389c9f90e8d574eaaff1d19554 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 19 Jul 2026 21:21:49 +0000 Subject: [PATCH 1/3] Sync suggest-method.yml dropdowns with _data/tags.yml Update the preservation, extraction, library and sequencing dropdown options in the method issue form to match the current controlled vocabulary after the tags.yml revision on main (taxon and outcome already matched). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01HYAEmscFHjiQFP1sqNEBEF --- .github/ISSUE_TEMPLATE/suggest-method.yml | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/suggest-method.yml b/.github/ISSUE_TEMPLATE/suggest-method.yml index 3bf45a2..b74c326 100644 --- a/.github/ISSUE_TEMPLATE/suggest-method.yml +++ b/.github/ISSUE_TEMPLATE/suggest-method.yml @@ -58,14 +58,10 @@ body: label: Preservation type* multiple: true options: - - dry-pinned - - study-skin - - herbarium-pressed + - dry - fluid-ethanol - fluid-formalin - frozen - - dried-tissue - - bone-subfossil - "Other (describe in detail box)" validations: required: true @@ -79,7 +75,8 @@ body: - magnetic-bead - phenol-chloroform - ctab - - chelex + - commercial-kit + - diy-approach - "Other (describe in detail box)" validations: required: true @@ -89,11 +86,10 @@ body: label: Library prep method* multiple: true options: - - tagmentation - - ligation - single-stranded - - pcr-free - - hybridization-capture + - double-stranded + - commercial-kit + - diy-approach - "Other (describe in detail box)" validations: required: true @@ -106,9 +102,6 @@ body: - genome-skimming - shotgun-wgs - target-capture - - metabarcoding - - rad-seq - - sanger - "Other (describe in detail box)" validations: required: true From e72cf8ef5d39c5c4e0b28fdffb9023c01b56b37e Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 19 Jul 2026 21:23:32 +0000 Subject: [PATCH 2/3] Sync suggest-bibliography.yml tags with _data/tags.yml Update the method-tag dropdown in the bibliography issue form to the current controlled vocabulary (extraction, library, sequencing facets), removing the eight stale values that no longer exist in tags.yml. Shared values (commercial-kit, diy-approach) are listed once. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01HYAEmscFHjiQFP1sqNEBEF --- .github/ISSUE_TEMPLATE/suggest-bibliography.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/suggest-bibliography.yml b/.github/ISSUE_TEMPLATE/suggest-bibliography.yml index bfd4206..2ead56a 100644 --- a/.github/ISSUE_TEMPLATE/suggest-bibliography.yml +++ b/.github/ISSUE_TEMPLATE/suggest-bibliography.yml @@ -46,22 +46,20 @@ body: label: Relevant method tags multiple: true options: + # extraction - silica-column - magnetic-bead - phenol-chloroform - ctab - - chelex - - tagmentation - - ligation + - commercial-kit + - diy-approach + # library - single-stranded - - pcr-free - - hybridization-capture + - double-stranded + # sequencing - genome-skimming - shotgun-wgs - target-capture - - metabarcoding - - rad-seq - - sanger validations: required: false - type: input From 71ac08ec43eb1baa8f20ae201a709f6aa88b1128 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 19 Jul 2026 21:36:23 +0000 Subject: [PATCH 3/3] Add CI check that issue forms stay in sync with tags.yml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend scripts/validate_entries.rb (already run by ci.yml and deploy.yml) to verify each GitHub Issue Form dropdown matches the controlled vocabulary, driven by _data/facets.yml: - suggest-method.yml: one dropdown per methods-applicable facet, plus outcome - suggest-bibliography.yml: the `tags` dropdown = union of bibliography- applicable facet vocabularies Fails on drift in either direction — a stale option no longer in tags.yml, a vocab value the form doesn't offer, or a duplicated option. The "Other (describe…)" escape hatch is exempt. Document the guard in CONTRIBUTING. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01HYAEmscFHjiQFP1sqNEBEF --- CONTRIBUTING.md | 10 ++++--- scripts/validate_entries.rb | 57 ++++++++++++++++++++++++++++++++++--- 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 00e46c6..3659d67 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -67,10 +67,12 @@ truth. CI (`scripts/validate_entries.rb`) fails the build if an entry uses a value that isn't listed there, which keeps filtering consistent and stops typos fragmenting the taxonomy. -**Need a new tag value?** Add it to `_data/tags.yml` in the same PR. If that -value is also offered as a dropdown in an issue form, add it to the matching -list in `.github/ISSUE_TEMPLATE/*.yml` too — the forms can't read `tags.yml` -automatically. The maintainer curates this vocabulary. +**Need a new tag value?** Add it to `_data/tags.yml` in the same PR, and add it +to the matching dropdown in `.github/ISSUE_TEMPLATE/*.yml` too — the forms can't +read `tags.yml` automatically. CI enforces this: `scripts/validate_entries.rb` +fails if a form dropdown and the vocabulary drift apart in either direction (a +stale option, or a vocab value the form doesn't offer). The maintainer curates +this vocabulary. ## Local preview diff --git a/scripts/validate_entries.rb b/scripts/validate_entries.rb index 3e5c4c0..12bef8b 100644 --- a/scripts/validate_entries.rb +++ b/scripts/validate_entries.rb @@ -1,9 +1,11 @@ #!/usr/bin/env ruby # frozen_string_literal: true # -# Validates every method and bibliography entry against the controlled -# vocabulary in _data/tags.yml and a small required-field schema. -# Exits non-zero (failing CI) if any entry is invalid. Run: +# Validates (1) every method and bibliography entry against the controlled +# vocabulary in _data/tags.yml and a small required-field schema, and (2) that +# the GitHub Issue Form dropdowns stay in sync with that vocabulary (the forms +# can't read _data/tags.yml, so this guards against drift). +# Exits non-zero (failing CI) if anything is invalid. Run: # ruby scripts/validate_entries.rb require "yaml" @@ -11,6 +13,7 @@ ROOT = File.expand_path("..", __dir__) TAGS = YAML.safe_load_file(File.join(ROOT, "_data", "tags.yml")) +FACETS = YAML.safe_load_file(File.join(ROOT, "_data", "facets.yml")) errors = [] @@ -96,9 +99,55 @@ def as_array(v) end end +# --- issue-form vocabulary sync ------------------------------------------- +# Each form dropdown must offer exactly the vocabulary it maps to: no stale +# values (offered but no longer in tags.yml) and no missing values (in the +# vocab but not offered). The "Other (describe…)" escape hatch is exempt. +def facet_vocab(facet) + facet["grouped"] ? TAGS[facet["key"]].values.flatten : (TAGS[facet["key"]] || []) +end + +def check_form(rel, expected, errors) + path = File.join(ROOT, rel) + unless File.exist?(path) + errors << "#{rel}: file not found" + return + end + form = YAML.safe_load_file(path) + dropdowns = (form["body"] || []).each_with_object({}) do |b, h| + h[b["id"]] = b if b.is_a?(Hash) && b["type"] == "dropdown" + end + + expected.each do |id, vocab| + field = dropdowns[id] + unless field + errors << "#{rel}: expected dropdown `#{id}` is missing" + next + end + offered = Array(field.dig("attributes", "options")).reject { |o| o.to_s.start_with?("Other") } + + dupes = offered.select { |o| offered.count(o) > 1 }.uniq + dupes.each { |v| errors << "#{rel}: `#{id}` lists \"#{v}\" more than once" } + + (offered - vocab).each { |v| errors << "#{rel}: `#{id}` offers \"#{v}\" which is not in _data/tags.yml" } + (vocab - offered).each { |v| errors << "#{rel}: `#{id}` is missing vocab value \"#{v}\" (add it or the form drifts from tags.yml)" } + end +end + +# Method form: one dropdown per method-applicable facet, plus outcome. +method_expected = {} +FACETS.select { |f| f["methods"] }.each { |f| method_expected[f["key"]] = facet_vocab(f) } +method_expected["outcome"] = TAGS["outcome"] || [] +check_form(".github/ISSUE_TEMPLATE/suggest-method.yml", method_expected, errors) + +# Bibliography form: a single `tags` dropdown = union of bibliography-applicable +# facet vocabularies (deduped). +bib_tag_vocab = FACETS.select { |f| f["bibliography"] }.flat_map { |f| facet_vocab(f) }.uniq +check_form(".github/ISSUE_TEMPLATE/suggest-bibliography.yml", { "tags" => bib_tag_vocab }, errors) + # --- report ---------------------------------------------------------------- if errors.empty? - puts "✓ All entries valid." + puts "✓ All entries and issue forms valid." exit 0 else warn "✗ #{errors.length} validation error(s):"