Valkyrie test harness - #58
Conversation
The test suite now runs green against Hyrax's Valkyrie test apps in all three persistence configurations: koppie (Postgres, flex off), allinson (Postgres, flex on), and sirenia (Fedora metadata). CI runs each. The submodule had been pinned to a Hyrax 2.9-era commit and never checked out, so no test app existed. ActiveFedora-era specs are tagged and skipped until their part of the Valkyrie port lands. The submodule tracks main because the released 5.3.0 references a class it does not ship. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The gem no longer depends on bolognese, removing 28 transitive gems. DataCite's REST API accepts JSON directly, so the XML crosswalk had no remaining purpose, and DOI autofill moves to doi.org content negotiation. Metadata serialization and autofill now raise NotImplementedError until their replacements land. The dependency floors also move up to match what Hyrax 5.3 already requires: Ruby 3.2 and Rails 6.1. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Identifiers now live in their own table, one row per identifier per resource, so a work can hold a DOI and a RAiD at once without either overwriting the other. Each row tracks its own provider state, sync time, and whether we minted it or someone supplied it. Hyrax's identifier interface assumes a single overwritable attribute and a bare string return, which leaves no room for state, errors, or additional schemes. Registrars now return a result object, and providers are looked up by scheme rather than hardcoded to DataCite. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Work types now carry DOI fields as Valkyrie attributes, and a work type can hold its DOI in an attribute other than doi via holds_doi_in. Solr indexing covers the DOI, the depositor's intent, and the state the provider reports. doi_status_when_public now records intent only; what DataCite currently says lives on the identifier record, because state is provider-specific vocabulary. Where a repository already declares the attribute the gem leaves it alone, since redeclaring would make the gem unloadable there. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds a rake task that installs the doi properties into the current m3 profile, and a validator that warns when a profile would leave DOIs invisible on the show page or attached to no work type. The task creates a new profile version rather than editing the current one, since saved works pin their schema version to a row id. Also adds a freyja test target: dassie with VALKYRIE_TRANSITION=true, the only configuration with Wings loaded. It covers applications midway through migrating off ActiveFedora, and immediately caught an rspec-rails API that differs on the Rails 6.1 app. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Credentials now reach a registrar per instance, resolved through a store the host application configures. The default reads them from the environment; a multi-tenant host replaces it to source them per tenant. A connection test confirms both that DataCite answers and that the credentials work, without minting anything. Credentials were class attributes, which are process-wide, so two Sidekiq threads serving different tenants could overwrite each other mid-flight. The store also describes its own fields, so a form can render itself from that rather than hardcoding them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A serializer turns a work into DataCite REST v2 attributes. Which work field feeds which DataCite field is read from datacite_mapping on m3 profile properties, so an adopter can change it without a deploy, and it reports which required fields a work still lacks. Some values cannot be read from a field at all: a repository without a creator field has to derive creators from its typed-role contributors. Those come from a configured extractor, which takes precedence over the mapping. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Registering a DOI is now one idempotent request carrying the state we want. DataCite's REST API takes an event — register, publish, or hide — so a work intended to be findable while still private is hidden rather than published: it resolves for anyone holding the DOI without being publicly indexed. Registering returns the state DataCite reported, along with any field-level errors, and missing required metadata is named before the request goes out. The legacy MDS API needed three calls whose combined side effects determined the state, including a delete that existed only to undo the other two. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Whether a work should get a DOI now lives in a policy object the registrar consults, so a repository can limit minting to particular work types without the registrar knowing about that choice. A work type qualifies by naming a registrar, which is what including a scheme concern does. The checks were three predicates inlined in the registrar, which left no way to restrict minting without editing it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds a mint endpoint requiring edit permission on the work, and a helper that decides whether to offer the button on a show page. Both minting endpoints are POST and return JSON, since reserving an identifier has a side effect at DataCite that a browser prefetch must not be able to trigger. The gem also registers its own registrar now. Hyrax ships an empty registrar hash and its generator only writes one into a host initializer, so a skipped generator left minting silently unavailable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rewrites the DOI tab off inline jQuery onto a delegated vanilla-JS asset, and adds the mint button as a show-page action. The tab's autofill handler used the jquery-ujs event signature while the stack ships rails-ujs, so the DOI was never sent; the missing-field warning looked for a hardcoded creator selector that matches nothing in a repository without that field. The engine now wires its own helpers. The tab previously appeared only if the adopter ran the install generator, and its work-type check read class ancestry, which a flexible-metadata profile does not touch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Replaces the actor stack with a publisher listener that syncs metadata for works that already have a DOI. Editing a work without one still mints nothing. It also listens for permission changes, not just metadata saves: embargo and lease release change visibility without saving metadata, so a work meant to become findable would otherwise stay registered indefinitely after release. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Autofill now works: paste a DOI and the form populates from the metadata its publisher registered. Reading is separate from minting, so a DOI recorded this way is marked external and never has metadata pushed back to it. Metadata comes from doi.org content negotiation as CSL JSON, so any registration agency resolves rather than DataCite alone — a journal article's CrossRef DOI is the common thing a depositor pastes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds a renderer that links a DOI to its resolver, and withholds draft DOIs — a draft is reserved but does not resolve, so linking one gives readers a dead link. Drops a copy of Hyrax 2.9's attribute markup that the gem carried to add its one row. Hyrax now builds that list from each field's own profile settings, so the copy was quietly overriding every work type's configured display. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rewrites the remaining pre-Valkyrie specs against Valkyrie resources, or drops them where a Valkyrie spec already covered the same ground. All of them were excluded from every run, so none had executed since the port began, and each referenced code this rewrite has since removed. Two gaps came out of it: the form and presenter concerns had no live coverage at all, and the shared examples the gem ships for adopters were still asserting ActiveModel validations that a Valkyrie resource does not have. The suite now runs those examples so they cannot drift again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Installing raised on boot from registrar settings that no longer exist. The work-type generator looked for class declarations Valkyrie work types do not have, so it reported success while changing nothing. The migration generator raised before writing anything. Installing now also creates the identifier table, rather than leaving a step an adopter hits later as a missing-table error on first mint. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Removes a helper module nothing includes any more, and which would misbehave if something did: the engine prepends both helpers it bundles, so including it would shadow Hyrax's own methods instead of wrapping them. Also drops rubocop exclusions naming five deleted spec files, and corrects the gemspec, which claimed MIT and packaged a license filename this repo has never had. The license is Apache 2.0, as the LICENSE file, the README badge, and every other Samvera project have it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rewrites the README around explicit minting, which is the behavior most likely to surprise someone expecting the old automatic version, and adds a configuration guide covering credential stores, minting policy, and the flexible-metadata setup. Drops two guides written for Hyrax 2.9 whose steps referenced code this rewrite removed. Nothing linked to either. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Swaps the CircleCI badge for the GitHub Actions workflow. CircleCI still serves an image for projects it no longer builds, so the old badge looked like a passing build while reporting on nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR modernizes hyrax-doi for Valkyrie-only Hyrax (>= 5.3), reintroducing working DOI minting/sync with a new persistence model (one row per identifier) and updated DataCite REST v2 integration, plus a refreshed test harness across multiple Hyrax targets.
Changes:
- Introduces
Hyrax::DOI::PersistentIdentifiertable-backed storage and keepswork.doias a projection for indexing/display compatibility. - Replaces prior ActiveFedora/Bolognese-based flows with DOI.org CSL autofill, DataCite REST v2 registration results, credential-store based configuration, and publisher-driven sync jobs.
- Adds extensive RSpec coverage, updated generators, docker-compose targets, and GitHub Actions matrix to validate multiple Hyrax configurations (koppie/allinson/sirenia/freyja).
Reviewed changes
Copilot reviewed 132 out of 135 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| spec/views/hyrax/base/form_doi_spec.rb | Adds view spec coverage for DOI form partial behavior (buttons/radios/autofill attrs). |
| spec/support/persistent_identifier_table.rb | Creates PID table in the test environment for model specs without running generators. |
| spec/spec_helper.rb | Keeps ActiveFedora-tag exclusion filter for cross-target consistency. |
| spec/services/hyrax/doi/state_reachability_spec.rb | Tests DataCite state reachability constraints. |
| spec/services/hyrax/doi/registration_result_spec.rb | Tests the new registrar result object (success/changed/errors). |
| spec/services/hyrax/doi/recorded_identifier_spec.rb | Tests recorded (non-minted) identifier schemes (ORCID/ROR). |
| spec/services/hyrax/doi/publisher_listener_spec.rb | Tests publisher subscription and sync-enqueue rules. |
| spec/services/hyrax/doi/minting_policy_spec.rb | Tests minting eligibility rules and registrar policy enforcement. |
| spec/services/hyrax/doi/flexible_schema_validators/doi_validator_spec.rb | Tests DOI-related warnings emitted from flexible schema validator. |
| spec/services/hyrax/doi/flexible_schema_validator_integration_spec.rb | Confirms decorator prepend is active inside Hyrax validator service. |
| spec/services/hyrax/doi/flexible_profile_installer_spec.rb | Tests profile merge/versioning behavior for flexible metadata installs. |
| spec/services/hyrax/doi/doi_resolver_spec.rb | Tests DOI.org CSL JSON resolution and parsing into Hyrax attributes. |
| spec/services/hyrax/doi/datacite_serializer_spec.rb | Tests DataCite payload generation and required-field reporting. |
| spec/services/hyrax/doi/datacite_registrar_spec.rb | Removes legacy registrar specs tied to old API/behavior. |
| spec/services/hyrax/doi/datacite_registrar_credentials_spec.rb | Tests registrar credential resolution and ping behavior. |
| spec/services/hyrax/doi/credentials_spec.rb | Tests credential object completeness, mode normalization, and redaction. |
| spec/services/hyrax/doi/credential_store_spec.rb | Tests environment store behavior and thread-isolated credential fetching. |
| spec/services/bolognese/writers/hyrax_work_writer_spec.rb | Removes specs for Bolognese-based roundtripping (dependency removed). |
| spec/services/bolognese/readers/hyrax_work_reader_spec.rb | Removes specs for Bolognese-based crosswalk reading (dependency removed). |
| spec/routing/hyrax/doi/routes_spec.rb | Adds routing specs for POST-only mint/draft and GET autofill. |
| spec/renderers/hyrax/renderers/doi_attribute_renderer_spec.rb | Adds renderer spec ensuring DOI links and draft suppression. |
| spec/rails_helper.rb | Updates fixtures config for rspec-rails 6/7 compatibility and removes AF cleaner hooks. |
| spec/presenters/hyrax/doi/doi_presenter_behavior_spec.rb | Adds presenter behavior specs for DOI and state/intent separation. |
| spec/presenters/concerns/doi_presenter_behavior_spec.rb | Removes legacy presenter shared-spec wiring. |
| spec/presenters/concerns/datacite_doi_presenter_behavior_spec.rb | Removes legacy DataCite presenter shared-spec wiring. |
| spec/models/hyrax/doi/persistent_identifier_spec.rb | Adds model spec coverage for PID validation, uniqueness, sync history. |
| spec/models/concerns/hyrax/doi/doi_projection_spec.rb | Tests projection sync between PID record and work attribute. |
| spec/models/concerns/hyrax/doi/doi_collision_spec.rb | Tests safe behavior when host predeclares DOI fields/types. |
| spec/models/concerns/hyrax/doi/doi_behavior_spec.rb | Adds DOIBehavior spec coverage (regex, registrar defaults). |
| spec/models/concerns/hyrax/doi/doi_attribute_name_spec.rb | Tests configurable attribute name for DOI projection/read/write. |
| spec/models/concerns/hyrax/doi/datacite_doi_behavior_spec.rb | Tests DataCite concern behavior and shared examples alignment. |
| spec/models/concerns/doi_behavior_spec.rb | Removes legacy DOIBehavior spec targeting ActiveFedora GenericWork. |
| spec/models/concerns/datacite_doi_behavior_spec.rb | Removes legacy DataCite concern spec targeting ActiveFedora GenericWork. |
| spec/jobs/hyrax/doi/sync_doi_job_spec.rb | Adds specs for sync job behavior (provider routing, missing work). |
| spec/jobs/hyrax/doi/register_doi_job_spec.rb | Removes legacy job spec for AF-era register job. |
| spec/indexers/hyrax/doi/indexers/doi_indexer_spec.rb | Adds specs for indexing projection, intent vs state, and custom attr name. |
| spec/helpers/work_show_helper_spec.rb | Removes legacy helper spec tied to removed WorkShowHelper behavior. |
| spec/helpers/work_form_helper_spec.rb | Removes legacy helper spec tied to old helper-injection approach. |
| spec/helpers/hyrax/doi/work_form_helper_spec.rb | Adds helper specs for tab insertion and required-field selector generation. |
| spec/helpers/hyrax/doi/mint_button_helper_spec.rb | Adds helper specs for mint button eligibility and show_actions_for integration. |
| spec/generators/migrations_generator_spec.rb | Adds generator specs ensuring migration writes correctly and includes indices/version. |
| spec/generators/install_generator_spec.rb | Updates install generator specs to validate initializer is inert and migration installed. |
| spec/forms/hyrax/doi/form_behavior_spec.rb | Adds form behavior specs for DOI/DataCite form concerns on ResourceForm. |
| spec/forms/concerns/doi_form_behavior_spec.rb | Removes legacy form concern spec targeting GenericWorkForm. |
| spec/forms/concerns/datacite_doi_form_behavior_spec.rb | Removes legacy DataCite form concern spec targeting GenericWorkForm. |
| spec/fixtures/metadata.xml | Removes legacy DataCite XML fixture. |
| spec/fixtures/datacite.json | Removes legacy DataCite JSON fixture (Bolognese-era). |
| spec/fixtures/csl/datacite_dataset.json | Adds CSL JSON fixture for DOI.org resolution tests. |
| spec/fixtures/csl/crossref_journal_article.json | Adds CSL JSON fixture for DOI.org resolution tests. |
| spec/features/create_draft_doi_spec.rb | Removes legacy JS feature spec based on old front-end/API expectations. |
| spec/features/autofill_spec.rb | Removes legacy/pending JS feature spec tied to removed stack. |
| spec/controllers/hyrax_doi_controller_spec.rb | Removes legacy controller spec (old formats/behavior). |
| spec/actors/hyrax/actors/doi_actor_spec.rb | Removes legacy actor spec (actor itself removed). |
| lib/tasks/hyrax/doi_tasks.rake | Adds rake task to install DOI properties into flexible metadata profiles. |
| lib/hyrax/doi/spec/shared_specs/solr_document/doi_behavior.rb | Updates shared spec for SolrDocument DOI fields and adds doi_state checks. |
| lib/hyrax/doi/spec/shared_specs/doi_form_behavior.rb | Updates shared form spec to reflect terms handling under new UI/tab approach. |
| lib/hyrax/doi/spec/shared_specs/doi_behavior.rb | Updates shared model spec to reflect Valkyrie behavior and projection APIs. |
| lib/hyrax/doi/spec/shared_specs/datacite_doi_form_behavior.rb | Updates shared DataCite form spec similarly to DOI form shared spec. |
| lib/hyrax/doi/flexible_schema_validator_service_decorator.rb | Adds decorator to append DOI profile validation warnings. |
| lib/hyrax/doi/engine.rb | Wires registrars, schema search path, helper prepends, and publisher subscription. |
| lib/hyrax/doi/configuration.rb | Adds configuration object for providers, credential store, extractors, minting policy. |
| lib/hyrax/doi.rb | Requires configuration and removes placeholder module content. |
| lib/generators/hyrax/doi/templates/db/migrate/create_hyrax_doi_persistent_identifiers.rb.erb | Adds migration template for new PID table. |
| lib/generators/hyrax/doi/templates/config/initializers/hyrax-doi.rb | Rewrites initializer template to use Hyrax::DOI.configure (optional config). |
| lib/generators/hyrax/doi/migrations_generator.rb | Adds dedicated migration generator (with Rails migration version stamping). |
| lib/generators/hyrax/doi/install_generator.rb | Updates install generator to write initializer + invoke migrations (no helper injection). |
| lib/generators/hyrax/doi/add_to_work_type_generator.rb | Updates generator to inject concerns into Valkyrie work model/forms (no presenter injection). |
| hyrax-doi.gemspec | Updates license, Ruby/Hyrax/Rails constraints, dependencies (remove bolognese, add faraday follow redirects). |
| Gemfile.koppie | Adds test-app gemfile for koppie target. |
| Gemfile.dassie | Cleans comment and keeps target gemfile. |
| Gemfile.allinson | Adds test-app gemfile for allinson target. |
| Gemfile | Pins erb ~> 4.0 for sprockets compatibility. |
| docs/IMPLEMENTATION.md | Removes outdated Hyrax 2.9/ActiveFedora implementation guide. |
| docs/CONFIGURATION.md | Adds new configuration documentation aligned to credential store/policy/flex profile install. |
| docker-compose-sirenia.yml | Adds sirenia target compose for Fedora Valkyrie adapters. |
| docker-compose-koppie.yml | Adds koppie target compose. |
| docker-compose-freyja.yml | Updates freyja compose with transition mode and clearer naming/comments. |
| docker-compose-allinson.yml | Adds allinson target compose. |
| config/routes.rb | Makes draft reservation POST-only and adds POST mint route. |
| config/metadata/doi.yaml | Adds schema loader config for doi and doi_status_when_public fields/indexing/view behavior. |
| config/locales/hyrax_doi.en.yml | Adds new i18n strings for draft/autofill/mint UI and flexible-schema warnings. |
| app/views/hyrax/base/_show_action_mint_doi.html.erb | Adds show-page mint action partial wired via helper seam. |
| app/views/hyrax/base/_attribute_rows.html.erb | Removes hardcoded Hyrax 2.9-era override for show metadata rows. |
| app/services/hyrax/doi/registration_result.rb | Adds richer registrar result type (identifier/state/changed/errors/response). |
| app/services/hyrax/doi/recorded_identifier.rb | Adds recorded identifier validation/normalization/resolution (ORCID/ROR). |
| app/services/hyrax/doi/publisher_listener.rb | Adds publisher listener to enqueue DOI sync when metadata/ACL updates happen. |
| app/services/hyrax/doi/ping_result.rb | Adds ping result type for credential/service checks. |
| app/services/hyrax/doi/minting_policy.rb | Adds policy object controlling mint eligibility and default state. |
| app/services/hyrax/doi/flexible_schema_validators/doi_validator.rb | Adds flexible-schema DOI validator emitting warnings (not errors). |
| app/services/hyrax/doi/flexible_profile_installer.rb | Adds service to create new flexible profile version including DOI properties. |
| app/services/hyrax/doi/doi_resolver.rb | Adds DOI.org CSL resolver for autofill (follow redirects, parse/shape checks). |
| app/services/hyrax/doi/datacite_serializer.rb | Adds serializer for DataCite REST v2 payloads, including profile mapping and extractors. |
| app/services/hyrax/doi/credentials.rb | Adds credential data object with mode normalization and redaction. |
| app/services/hyrax/doi/credential_store.rb | Adds credential store API plus environment-backed store and field schemas. |
| app/services/bolognese/writers/hyrax_work_writer.rb | Removes Bolognese writer integration. |
| app/services/bolognese/readers/hyrax_work_reader.rb | Removes Bolognese reader integration. |
| app/renderers/hyrax/renderers/doi_attribute_renderer.rb | Adds DOI renderer resolving render_as: doi and suppressing drafts. |
| app/presenters/concerns/hyrax/doi/doi_presenter_behavior.rb | Updates presenter to read multivalued Solr field and pass render options incl. state. |
| app/presenters/concerns/hyrax/doi/datacite_doi_presenter_behavior.rb | Updates status logic to reflect observed provider state vs depositor intent. |
| app/models/hyrax/doi/persistent_identifier.rb | Adds ActiveRecord model for identifier rows and sync history. |
| app/models/concerns/hyrax/doi/solr_document/doi_behavior.rb | Updates SolrDocument attributes to read correct Solr keys and adds doi_state. |
| app/models/concerns/hyrax/doi/doi_behavior.rb | Rewrites DOIBehavior for Valkyrie, projection, PID lookup, and configurable attr name. |
| app/models/concerns/hyrax/doi/datacite_doi_behavior.rb | Updates DataCite concern to declare intent field and registrar name (Valkyrie). |
| app/jobs/hyrax/doi/sync_doi_job.rb | Adds sync job to push updated metadata to provider for minted identifiers. |
| app/jobs/hyrax/doi/register_doi_job.rb | Removes legacy register job. |
| app/indexers/hyrax/doi/indexers/doi_indexer.rb | Adds indexer mixin for DOI fields, intent, and state. |
| app/helpers/hyrax/doi/work_show_helper.rb | Removes legacy show helper used by prior attribute_rows override. |
| app/helpers/hyrax/doi/work_form_helper.rb | Updates helper to add DOI tab under flex/non-flex and expose required-field selectors. |
| app/helpers/hyrax/doi/mint_button_helper.rb | Adds helper to contribute show action and determine mint button eligibility. |
| app/helpers/hyrax/doi/helper_behavior.rb | Removes legacy helper aggregation module. |
| app/forms/concerns/hyrax/doi/doi_form_behavior.rb | Updates form concern to delegate DOI without forcing it into generic term lists. |
| app/forms/concerns/hyrax/doi/datacite_doi_form_behavior.rb | Updates form concern to delegate intent field without adding to generic term lists. |
| app/controllers/hyrax/doi/hyrax_doi_controller.rb | Rewrites controller actions to JSON API for draft/mint/autofill with updated auth. |
| app/actors/hyrax/actors/doi_actor.rb | Removes legacy actor-based automatic minting behavior. |
| .ruby-version | Sets repo Ruby version to 3.3.0. |
| .rubocop.yml | Updates RSpec cop exceptions after spec suite restructuring. |
| .gitignore | Ignores OS/editor artifacts and multiple app lockfiles. |
| .github/workflows/lint-test.yml | Expands CI matrix to multiple docker-compose targets and parallel nodes. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Test Results 17 files + 12 17 suites +12 12m 50s ⏱️ + 8m 47s Results for commit f574261. ± Comparison against base commit 842c11d. This pull request removes 125 and adds 344 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
Answers a mint request for an unknown work with a JSON 404 instead of raising into an HTML 500 the client cannot read, and writes a single value where a work type's DOI field will not accept an array. Gives each CI shard its own Docker project. Four shards of one app shared a set of volumes and raced to create directories inside them, so the containers never started and no specs ran. Also clears 71 rubocop offenses that only the bundled version reports. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The web and worker containers share two volumes and both create the same directories in them at boot, so starting the pair raced and one died before any specs could run. Specs enqueue with the test adapter and need no worker. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Lowers the Hyrax floor to 5.2. The 5.3.0 version bump lives on a release commit that was never merged back, so Hyrax main ships the flexible metadata stack while still declaring 5.2.0 — and a 5.3 floor made the gem unresolvable for every application tracking main, Hyku included. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The generated migration declared CreateHyraxDoiPersistentIdentifiers, but the engine registers DOI as an acronym, so Rails camelizes the filename to CreateHyraxDOIPersistentIdentifiers and db:migrate raised NameError. The generator's own spec had the wrong spelling too, so nothing caught it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
322fe7a to
d1313d7
Compare
93ebe1d to
56c0693
Compare
The DOI tab now records what a depositor enters. It offers three situations -- mint nothing, record a DOI the work already has, or mint a new one -- and only the chosen one's controls apply, so the panels no longer submit each other's values. Minting writes an identifier record that keeps the work's DOI in step for indexing and display, and a reserved draft is recorded before any work exists to hold it. The tab also no longer raises on a work type whose class does not declare the DOI attribute, which had stopped the create form opening at all. The tab collected values that were then discarded: the form concerns delegated readers to the work but declared no writable property, so ResourceForm dropped both DOI fields on submit, and nothing created a PersistentIdentifier row -- the sync job returns early without one, and a reserved DOI existed only at DataCite. The shared form examples asserted delegation rather than round-tripping, which is what let the missing writer stay green. Reconciling the submitted mode reads params without to_h, which raises on the unpermitted parameters a controller passes.
The autofill, reserve-a-DOI, and mint buttons now build their URLs from the mounted engine, so they reach the application's own mount point instead of a path nothing serves. Saving a work with a minting choice no longer fails on `undefined method 'embargo' for an instance of String`. The install generator reports when it cannot add the mount rather than claiming success, and the README says how to add it by hand. Three faults with one shape -- something worked in the suite but not in an application. Engine.routes.url_helpers builds paths against the engine's own route set and ignores the host's mount point; only feature specs mounted the engine, so no view spec could catch it. The form's sync returned the value an attribute writer hands back rather than the resource, which Hyrax's save step then asks for an embargo. The engine is now mounted for the whole suite, and the shared form examples assert what sync returns.
"Reserve a DOI now" now shows the identifier in a field of its own beside the button, with a copy button, and saves it with the work. Reserving a DOI early exists so it can be pasted into a document before that document is uploaded, so the depositor has to be able to read and copy it. The reservation was written into the existing-DOI input, which sits in a different mode panel: the depositor saw nothing but a disabled button, and because the minting mode discards that panel's value, the DOI was created at DataCite and then dropped when the work saved. The copy button falls back to selecting the text where navigator.clipboard is unavailable.
A work saving with a DOI reserved before it existed now claims that identifier record, so DataCite receives the work's metadata instead of keeping a draft that has nothing but a prefix. Describing a DOI a work already holds no longer requires a minting choice, while creating one still does -- a work type an operator excluded from minting is never touched either way. The reservation was recorded before the work existed and so carried no resource_id; nothing linked the two afterwards, so no sync ever ran and the orphan sweep would have counted a DOI that was in use. Hyrax::DOI.config is also reset between examples now: specs that set a restrictive policy leaked into everything after them, which is what four order-dependent failures here turned out to be.
Reserving a DOI now sets the work's minting intent to draft, so the work agrees it holds a reserved identifier. Nothing submits until the reservation actually succeeds, and a status the depositor picks afterwards still wins. A reserved DOI with a blank intent left the work holding a real identifier while claiming to want none. doi_status reported nothing, so the renderer could not tell a draft from a resolvable DOI and would have linked one that does not resolve; the show-page mint button requires an intent, so it was hidden, which left no route to promote the DOI at all.
Choosing Draft, Registered, or Findable on the deposit form now creates the DOI when the work is saved, and records the identifier so later edits keep DataCite current. A work type the minting policy excludes still mints nothing, and editing a work that asked for no DOI still creates none. The intent was recorded and nothing acted on it: the listener enqueued a sync only for a work that already had an identifier record, and the job returned early without one, so no DOI was created and no result was written back. A reserved DOI also moves to its own form parameter -- it shared doi[] with the existing-DOI field, so the reconciliation that drops a value left behind in an unselected panel could not tell the two apart and discarded an identifier that already existed at DataCite.
A registered or findable DOI is only created when the work carries the metadata DataCite requires. Blank required fields are named for the depositor to fill, and the deposit form says plainly that no DOI will be created until they are. A sync job also mints at most one DOI however many times it runs. The serializer substituted DataCite's :unav sentinel for a blank creator or publisher, the current year for a missing publication year, and Other for a missing resource type -- then reported those same fields as absent, so the registrar refused to mint and the placeholders were discarded while the form promised they would be sent. Minting decided from the absence of an identifier record, which is written only after the provider replies, so a duplicate enqueue or a retry each saw nothing and each created a permanent identifier.
Summary
Details
hyrax >= 5.3, no compatibility shims.0.3-stablecarries the old API.doiattribute is now a projection of the primary row.doi_status_when_publicstays on the work as the depositor's intent; what the provider reports lives on the identifier record. A work marked findable sits atregisteredwhile private and becomes findable when it — or its embargo — does.eventon one idempotent PUT rather than emerging from the side effects of three calls plus a corrective delete.class_attributes were process-wide, so concurrent Sidekiq threads serving different tenants could overwrite each other's credentials mid-flight.Bugs found and fixed along the way
solr_document.doireaddoi_ssi, which nothing has ever written, so a DOI could never reach a show page.pendingsince 0.3._attribute_rowsoverride replaced profile-driven rendering with a hardcoded Hyrax 2.9 field list, so a work's own metadata profile decided nothing about its show page.Not in this PR
_show_actions.html.erbfour times, so the show-page mint button needs work there regardless.show_actions_forseam so the mint button needs no glue in the host application. The gem guards for its absence, so the two can merge in either order.SimpleCov.rootandSimpleCov.startfor itself, so the reported 2.66% is 659/24695 of Hyrax's codebase, not this gem's ~2,000 lines.