From e476c964521c56387c61eb4dbfbcbb30ea9d7db8 Mon Sep 17 00:00:00 2001 From: TristanKruse Date: Mon, 26 Oct 2026 14:58:04 +0100 Subject: [PATCH] Prepare stable 1.0.0 API baseline and release checklist --- .github/PRE_RELEASE_CHECKLIST.md | 67 ++++++++++++++++++++------------ .github/RELEASING.md | 4 ++ API.md | 14 +++++++ CHANGELOG.md | 5 ++- Gemfile.lock | 4 +- README.md | 42 ++++++++++++++++---- lib/archunit/version.rb | 2 +- 7 files changed, 102 insertions(+), 36 deletions(-) diff --git a/.github/PRE_RELEASE_CHECKLIST.md b/.github/PRE_RELEASE_CHECKLIST.md index 133bfd5..8aa6030 100644 --- a/.github/PRE_RELEASE_CHECKLIST.md +++ b/.github/PRE_RELEASE_CHECKLIST.md @@ -1,26 +1,45 @@ # Stable-release readiness -All four currently open feature issues (#47, #48, #54, #55) have implementations in the pending -PR stack. They are not considered shipped until those changes reach `main` and a gem is published. - -## Before 1.0.0 - -- Merge the reviewed integration work and the rationale/exclusion PRs in dependency order. Retarget - stacked PRs to `main` after their base merges. Do not bypass the existing branch protections. -- Merge the pre-v1 audit fixes and rerun the entire matrix on `main`: supported Ruby versions, - Windows/Linux, coverage, lint, dogfooding, documentation links, installed-gem checks, and the RAG fixture. -- Keep the import-only default and the explicit `imports_and_constants` opt-in documented. Unknown - runtime behavior, ambiguous constants, and dynamic import paths are not a complete Ruby interpreter. -- Review representative passing and failing rules manually. Include a constant-only forbidden edge, - a safely inferred import, a `.because(...)` failure, and `.archignore` exclusions. -- Set the version to `1.0.0`, refresh the local gem lock entry, date the changelog, update installation - instructions, and replace prototype/pre-release wording with an accurate stable API contract. -- Run `bundle exec ruby scripts/check_release_metadata.rb --release`; development checks alone - intentionally do not prove publication readiness. -- Run `bundle exec rake security` with a freshly updated advisory database and review the JSON - evidence. Resolve actionable findings; do not add unexplained advisory ignores to pass CI. -- Publish only after maintainer approval via the trusted-publisher workflow. Install the published - version in a clean project and rerun a passing/failing architecture example before announcing it. +The original feature backlog (#47, #48, #54, #55) and the correctness/QA audit fixes (#63-65) are +merged. PRs #68-70 were reviewed and merged on 2026-10-26; the resulting `main` passed CI, security +scanning, and documentation deployment. This checklist tracks the 1.0.0 preparation, not proof that +RubyGems publication has happened. The preceding published gem is 0.0.1. + +## 1.0.0 preparation + +- [x] Merge the reviewed extraction, source-boundary, cycle, parser-diagnostic, conditional-constant, + and coverage fixes without bypassing protections. +- [x] Document the import-only default, explicit expanded mode, stable public surface, and migration + from 0.0.1. Unknown runtime behavior and ambiguous or unsupported names remain analysis limits. +- [x] Synchronize version 1.0.0, local lock entry, dated changelog, and installation instructions. +- [x] Run `bundle exec ruby scripts/check_release_metadata.rb --release` on the candidate. +- [x] Run the full coverage/lint/dogfood suite, build/link-check docs, and check both public-API + smoke scripts. Native symlink skips on Windows must also be exercised in Linux CI. +- [x] Refresh advisory data and pass `bundle exec rake security`, including scanner-health checks. +- [x] Check passing/failing rules and both dependency modes on the pinned Rack/Rake/RSpec corpus. +- [x] Build with `gem build --strict`, install that exact artifact in an isolated gem home, confirm + its version/path, and exercise the installed API from a clean project without the source checkout. + +Preparation evidence (2026-10-26): 614 examples, zero failures, eight native-symlink skips on Windows; +98.48% library line and 91.51% branch coverage; 267 Ruby files lint-clean; 179 validated documentation +pages; 1,269 fresh advisories with no findings and the vulnerable-fixture health check passing. +All six pinned corpus/mode baselines matched. The isolated installed 1.0.0 artifact passed a clean +rule, an intentionally failing one-line import change, conditional-constant policies, exclusion +refresh, and strict malformed-source diagnostics, plus both dependency-analysis smoke scripts. + +## Publication remains a separate approval + +- [ ] Review and merge the preparation PR, then verify the full matrix on that exact `main` revision: + supported Ruby versions, Windows/Linux, library-only coverage, lint, dogfooding, docs, packaging, + installed-gem checks, security, and the downstream RAG fixture. +- [ ] Confirm the changelog date at publication and explicitly authorize the trusted-publisher + `Release` workflow for version `1.0.0` on `main`. Verify the RubyGems account and configured release + environment still belong to the intended maintainers. Never publish merely to run checks. +- [ ] Verify the published 1.0.0 gem and generated tag, install from RubyGems in a clean project, + and rerun passing/failing architecture examples before announcing availability. + +CLI, richer semantic method/protocol rules, presets, and gradual-adoption baselines remain in #66. +They are not prerequisites for the initial stable API baseline. ## Audit coverage added @@ -38,8 +57,8 @@ an actively changing or hostile filesystem. Dense graphs can have exponentially ## Next useful improvements -- Establish repeated real-world performance baselines on pinned Ruby repositories before setting - tighter thresholds. Report cold analysis, warm cache reuse, graph contents, and memory separately. -- Add an opt-in, non-blocking real-world canary once the repository set and update policy are agreed. +- The pinned real-world canary is implemented with manually triggered/relevant-PR checks, reviewed + graph fingerprints, and cold/warm/memory evidence. Review its stability and cost before scheduling + it or tightening thresholds; the small lib-only corpus is not a full Rails benchmark. - Dependency vulnerability scanning is available as a separate task/workflow. Consider mutation testing as another measured addition; high line coverage is not proof of semantic correctness. diff --git a/.github/RELEASING.md b/.github/RELEASING.md index 8f8107e..18c9403 100644 --- a/.github/RELEASING.md +++ b/.github/RELEASING.md @@ -21,6 +21,10 @@ and makes that RubyGems account an owner. ## Publishing a version +Preparation and publication are separate actions. A version commit, successful CI run, or strict +metadata check does not publish a gem. Do not dispatch `Release` for a dry run: its last step uploads +to RubyGems and creates the version tag. Keep publication behind explicit maintainer authorization. + 1. Update `ArchUnit::VERSION` in `lib/archunit/version.rb` and add the release to `CHANGELOG.md`. 2. Refresh the local gem's `Gemfile.lock` entry, date the changelog heading as `## - YYYY-MM-DD`, and update the README installation example to `~> `. diff --git a/API.md b/API.md index b5b0a31..b7f392b 100644 --- a/API.md +++ b/API.md @@ -7,6 +7,20 @@ which entry point to choose and how the stages fit together. All rule builders are immutable and lazy. Constructing a rule does not read the project; `check`, `measure`, `snapshot`, and export methods are the terminals that perform work. +## 1.x compatibility contract + +This guide defines the supported 1.0 public surface: documented entry points, fluent methods, +options, public data/error types, and report formats. Additive capabilities can arrive in minor +versions; incompatible public API changes require a major version and migration notes. Private +helpers and classes marked as implementation details are not part of that compatibility promise. +Correctness fixes can change detected violations; compatibility is not a promise to preserve missed +dependencies or misleading clean results. + +Static extraction remains bounded and does not execute the target application's source or gemspecs. +Import-only is the default; expanded constant analysis is explicit opt-in. The documented unresolved +lookup cases, project source/exclusion policy, strict parser failures, and explicit cache-clearing +behavior remain important when upgrading. See the README's migration notes for changes from 0.0.1. + ## Common rule shape ~~~ruby diff --git a/CHANGELOG.md b/CHANGELOG.md index 931ec52..abd7557 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Changelog -## 0.0.2 (unreleased) +## 1.0.0 - 2026-10-26 + +First stable API baseline. The previously unreleased 0.0.2 development work is included here; +0.0.1 remains the preceding published version. See the README's migration notes before upgrading. - Fail closed on malformed included Ruby in dependency graphs and AST metrics, with structured source diagnostics and profile counters instead of silently treating incomplete analysis as clean. diff --git a/Gemfile.lock b/Gemfile.lock index ba915e0..53ef638 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - archunit (0.0.2) + archunit (1.0.0) csv (>= 3.3, < 4.0) json (>= 2.7, < 3.0) prism (>= 1.0, < 2.0) @@ -112,7 +112,7 @@ DEPENDENCIES yard (~> 0.9.45) CHECKSUMS - archunit (0.0.2) + archunit (1.0.0) ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383 bundler-audit (0.9.3) sha256=81c8766c71e47d0d28a0f98c7eed028539f21a6ea3cd8f685eb6f42333c9b4e9 csv (3.3.6) sha256=aba61e7e507a66f03d45cb1f3c4b6359861c3504038b422962875dce099e4456 diff --git a/README.md b/README.md index 19b965c..a3a5012 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,10 @@ ArchUnit.project_files .in_folder('app/database/**') ~~~ -It is a working executable prototype with file, layer, slice, graph-reporting, and metric APIs. It -is tested on Ruby 3.3, 3.4, and 4.0 on Linux and Ruby 4.0 on Windows. Install the latest release as -[`archunit`](https://rubygems.org/gems/archunit) on RubyGems. +ArchUnitRuby provides file, layer, slice, graph-reporting, and metric APIs with a documented 1.0 +compatibility baseline. It is tested on Ruby 3.3, 3.4, and 4.0 on Linux and Ruby 4.0 on Windows. +The gem is named [`archunit`](https://rubygems.org/gems/archunit); check RubyGems for published-version +availability, since a development checkout can be ahead of the published gem. ArchUnitRuby follows the shared ArchUnitEverything architecture and fluent-API standard used by its siblings [ArchUnitTS](https://github.com/LukasNiessen/ArchUnitTS) and @@ -47,12 +48,13 @@ from `main`, so the published reference follows the repository. ### Installation -ArchUnitRuby requires Ruby 3.3 or newer. Add it to your test dependencies: +ArchUnitRuby requires Ruby 3.3 or newer. These instructions target the 1.0 series. Add it to your +test dependencies once the target version is published: ~~~ ruby # Gemfile group :test do - gem 'archunit', '~> 0.0.1' + gem 'archunit', '~> 1.0.0' end ~~~ @@ -62,7 +64,7 @@ Then install it: bundle install ~~~ -Or install it directly with `gem install archunit`. +Or install it directly with `gem install archunit --version '~> 1.0.0'`. [ClickGems download analytics](https://clickgems.clickhouse.com/dashboard/archunit) show trends by date, gem version, Ruby version, system, and country. Download totals count package fetches rather @@ -530,7 +532,7 @@ than silently returning a partial graph or zero counts. Its immutable `diagnosti `malformed_files`. Fix or explicitly exclude invalid files using the project source policy. Fluent rule selectors do not limit graph discovery. Failed graph builds are not cached; after editing previously cached valid source, the normal explicit `clear_cache: true` policy still applies. -This intentionally changes the prototype's permissive behavior before the stable release. +This intentionally changes the 0.0.1 prototype's permissive behavior in the 1.0 API. Expanded analysis uses a bounded Prism index and adds no runtime dependency. The design spike considered [RubyDEX](https://github.com/Shopify/rubydex), whose semantic index is broader but adds a @@ -608,6 +610,29 @@ those projects or installs their dependencies, and is not scheduled automaticall The implementation conventions and intended dependency directions live in [`AGENTS.md`](AGENTS.md). +## 1.0 compatibility and migration + +The documented entry points, fluent rule methods, options, public data/error types, and report +formats in the [API guide](https://lukasniessen.github.io/ArchUnitRuby/file.API.html) form the 1.x +compatibility baseline. Additive capabilities may be introduced in minor versions; incompatible +public API changes require a new major version and migration notes. Private implementation helpers +are not part of that contract. Correctness fixes can reveal violations that earlier versions missed; +review the changelog when updating. + +When upgrading from 0.0.1: + +- The default remains import-only. Explicitly opt into `dependency_analysis: :imports_and_constants` + when you want the documented static constant-reference model; it may reveal additional violations. +- Included malformed Ruby now raises `SourceParseError < TechnicalError`, rather than silently + passing or returning zero AST counts. Fix or explicitly exclude invalid source files. +- Project `.archignore` exclusions and skipped symlinked source entries can change the discovered + file set. Empty selections are still violations by default; check selectors rather than blindly + allowing empty tests. +- Cached graph results still require explicit clearing after source edits in a long-lived process. + +Stable API compatibility does not mean complete Ruby interpretation or exhaustive runtime detection. +The supported static-analysis boundaries below remain part of the contract. + ## 📅 Plans and Current Limitations - Files are the primary vocabulary; opt-in constant analysis has the lookup limits described above. @@ -616,7 +641,8 @@ The implementation conventions and intended dependency directions live in [`AGEN - `.archignore` supports exclusion globs, not negated gitignore patterns or nested ignore files. - Cycle traversal is iterative and tested on 10,000-node chains and rings. Enumerating every cycle can still be expensive in densely connected graphs; narrow the selected scope when necessary. -- The API is still pre-release and may change before the first stable gem version. +- Method-call/protocol rules, a standalone CLI, presets, and adoption baselines are roadmap work, + not claims made by the current 1.0 API. ## 💟 Community diff --git a/lib/archunit/version.rb b/lib/archunit/version.rb index d3437d3..1246ec3 100644 --- a/lib/archunit/version.rb +++ b/lib/archunit/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module ArchUnit - VERSION = '0.0.2' + VERSION = '1.0.0' end