From 98ab172c807f2c63cd7008125cf0353d506db84b Mon Sep 17 00:00:00 2001 From: gnuduncan Date: Wed, 10 Jun 2026 13:27:40 +0200 Subject: [PATCH] Prepare ruby-dag v1.6.0 review-hardening release - Bump DAG::VERSION to 1.6.0 - CHANGELOG: date the 1.6.0 section (2026-06-10) - ROADMAP: mark V1.6 review hardening and Release v1.6 as Done - Add spec/r0/v1_6_release_gate_test.rb pinning the EffectLedger port defaults, DispatchAbortedError, tick(only_workflow_id:), :workflow_retrying, Result.from_h round-trip, and the CI coverage gate - Relax the v1.5 gate version pin to >= per release-gate convention Co-Authored-By: Claude Fable 5 --- CHANGELOG.md | 2 + Gemfile.lock | 2 +- ROADMAP.md | 2 + lib/dag/version.rb | 2 +- spec/r0/v1_5_release_gate_test.rb | 2 +- spec/r0/v1_6_release_gate_test.rb | 70 +++++++++++++++++++++++++++++++ 6 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 spec/r0/v1_6_release_gate_test.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 24e7f5d..7e7534e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.6.0 — 2026-06-10 + Project-review hardening pass: design fixes at the storage-port seams, DRY consolidation, performance work, and CI/cop enforcement. diff --git a/Gemfile.lock b/Gemfile.lock index 52e2930..1f093a4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - ruby-dag (1.5.0) + ruby-dag (1.6.0) GEM remote: https://rubygems.org/ diff --git a/ROADMAP.md b/ROADMAP.md index 4ad94c0..7ba0a75 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -50,6 +50,8 @@ Tracked phases: | Release v1.4 | — | Done | | V1.5 mutation testing gate | — | Done | | Release v1.5 | — | Done | +| V1.6 review hardening | #192 | Done (#191) | +| Release v1.6 | #192 | Done | | S0 (SQLite adapter, in Delphi) | TBD | Next | | Release v1.0 | #74 | Done (#126, #156) | diff --git a/lib/dag/version.rb b/lib/dag/version.rb index 7786825..a27f482 100644 --- a/lib/dag/version.rb +++ b/lib/dag/version.rb @@ -2,5 +2,5 @@ module DAG # Library version. Bumped per release; see `CHANGELOG.md`. - VERSION = "1.5.0" + VERSION = "1.6.0" end diff --git a/spec/r0/v1_5_release_gate_test.rb b/spec/r0/v1_5_release_gate_test.rb index 5ce5540..db090b4 100644 --- a/spec/r0/v1_5_release_gate_test.rb +++ b/spec/r0/v1_5_release_gate_test.rb @@ -6,7 +6,7 @@ class R0V15ReleaseGateTest < Minitest::Test ROOT = File.expand_path("../..", __dir__) def test_version_is_bumped_to_mutation_testing_release - assert_equal "1.5.0", DAG::VERSION + assert_operator Gem::Version.new(DAG::VERSION), :>=, Gem::Version.new("1.5.0") end def test_changelog_contains_v1_5_release_notes diff --git a/spec/r0/v1_6_release_gate_test.rb b/spec/r0/v1_6_release_gate_test.rb new file mode 100644 index 0000000..cca7185 --- /dev/null +++ b/spec/r0/v1_6_release_gate_test.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +require_relative "../test_helper" + +class R0V16ReleaseGateTest < Minitest::Test + ROOT = File.expand_path("../..", __dir__) + + def test_version_is_bumped_to_review_hardening_release + assert_equal "1.6.0", DAG::VERSION + end + + def test_changelog_contains_v1_6_release_notes + changelog = normalized("CHANGELOG.md") + + assert_includes changelog, "## 1.6.0 — 2026-06-10" + assert_includes changelog, "Project-review hardening pass" + assert_includes changelog, "DAG::Ports::EffectLedger" + assert_includes changelog, "DAG::Effects::DispatchAbortedError" + assert_includes changelog, ":workflow_retrying" + end + + def test_roadmap_marks_v1_6_release + roadmap = normalized("ROADMAP.md") + + assert_includes roadmap, "V1.6 review hardening" + assert_includes roadmap, "Release v1.6" + end + + def test_effect_ledger_port_carries_the_canonical_completion_defaults + port = File.read(File.join(ROOT, "lib/dag/ports/effect_ledger.rb")) + + assert_includes port, "module EffectLedger" + assert_includes port, "def complete_effect_succeeded(effect_id:, owner_id:, result:, external_ref:, now_ms:)" + assert_includes port, "def complete_effect_failed(effect_id:, owner_id:, error:, retriable:, not_before_ms:, now_ms:)" + assert_includes port, "def thread_safe_for_dispatch?" + assert_includes DAG::Ports::Storage.ancestors, DAG::Ports::EffectLedger + refute File.read(File.join(ROOT, "lib/dag/ports/storage.rb")).include?("method_overridden?") + end + + def test_dispatcher_exposes_per_workflow_tick_and_abort_report + dispatcher = File.read(File.join(ROOT, "lib/dag/effects/dispatcher.rb")) + + assert_includes dispatcher, "def tick(limit:, only_workflow_id: nil)" + assert_includes dispatcher, "DispatchAbortedError" + assert_operator DAG::Effects::DispatchAbortedError, :<, DAG::Error + assert DAG::Effects::DispatchAbortedError.instance_method(:report) + end + + def test_event_types_include_workflow_retrying + assert_includes DAG::Event::TYPES, :workflow_retrying + assert_equal :retrying, DAG::TraceRecord::EVENT_STATUS.fetch(:workflow_retrying) + end + + def test_result_from_h_round_trips_every_step_outcome + success = DAG::Success[value: 1, context_patch: {"k" => "v"}] + failure = DAG::Failure[error: {"code" => "x"}, retriable: true] + waiting = DAG::Waiting[reason: :external, not_before_ms: 5] + + [success, failure, waiting].each do |outcome| + assert_equal outcome, DAG::Result.from_h(outcome.to_h) + end + end + + def test_ci_enforces_the_coverage_gate + workflow = File.read(File.join(ROOT, ".github/workflows/ci.yml")) + + assert_includes workflow, "COVERAGE" + refute_path_exists File.join(ROOT, ".github/workflows/ruby.yml") + end +end