diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..aeed56c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,31 @@ +# Changelog + +All notable changes to this project are documented in this file. + +## 1.0.0 - 2026-08-23 + +Initial public release of the generic, thread-safe SFQ(D) scheduler. + +### Included + +- exact rational scheduling tags with bounded, fail-closed numeric handling; +- weighted and cost-aware dispatch with configurable issue depth; +- opaque flow and job handles, cancellation, completion, flow closure, and + atomic snapshots; +- Java 17 runtime compatibility and no third-party runtime dependencies; +- source and JavaDoc artifacts for Maven Central; +- unit, property, differential, concurrency, retention, static-analysis, + reproducibility, and publication-topology verification; +- compiled executor and bounded resource-pool integration examples; +- separate jcstress and JMH harnesses. + +### Boundaries + +- the library schedules work but does not execute it or own external resource + capacity; +- dispatch fairness begins after admission and does not provide admission + isolation; +- queued cancellation uses reserved-cost accounting as documented in the + README and formal specification; +- the repository contains a benchmark protocol, but no published production + throughput or latency result. diff --git a/README.md b/README.md index 1e7f87e..ade3916 100644 --- a/README.md +++ b/README.md @@ -8,15 +8,11 @@ Use it when several tenants, queues, users, or workloads share a bounded number of execution slots and should receive service in proportion to their weights. -Canonical repository: - ## Status -The implementation, tests, JavaDoc, concurrency harness, and benchmark -harness are complete. The source branch uses the pre-release coordinates -`io.github.pzhin:sfqd-core:0.1.0-SNAPSHOT` and Java package -`io.github.pzhin.sfqd`. No artifact has been published to a public Maven -repository yet. +Version 1.0.0 is the first stable release. The library is published to Maven +Central as `io.github.pzhin:sfqd-core:1.0.0` and uses the Java package +`io.github.pzhin.sfqd`. The benchmark harness is an executable measurement protocol, not a benchmark result. This repository intentionally contains no raw machine-specific runs, @@ -47,7 +43,7 @@ On Windows Command Prompt or PowerShell: .\mvnw.cmd --batch-mode --no-transfer-progress clean verify ``` -Install the snapshot into your local Maven repository: +Install the release into your local Maven repository: ```shell ./mvnw --batch-mode --no-transfer-progress install @@ -61,7 +57,7 @@ Then add it to a local consumer: io.github.pzhin sfqd-core - 0.1.0-SNAPSHOT + 1.0.0 ``` @@ -434,4 +430,5 @@ measurement protocol. - [Bounded resource-pool lifecycle example](sfqd-examples/README.md) - [Theory in plain language and full papers](docs/THEORY.md) - [Build, CI, artifact, and publication checks](docs/TOOLING.md) +- [Release history](CHANGELOG.md) - [Benchmark workload guide](sfqd-benchmarks/README.md) diff --git a/docs/TOOLING.md b/docs/TOOLING.md index 07d07f7..a6bdcd0 100644 --- a/docs/TOOLING.md +++ b/docs/TOOLING.md @@ -60,15 +60,15 @@ The Java artifact verifier also inserts the project license into the source and JavaDoc JARs without invoking platform-specific archive tools. Both the unit gate and artifact verifier compare compiled output with `sfqd-core/src/main/api/public-api.txt`; adding a documented public member to an -existing type therefore fails the build. Before the first release, regenerate -the candidate manifest after compilation with: +existing type therefore fails the build. Before an intentional public API +change, regenerate the candidate manifest after compilation with: ```shell java -cp sfqd-core/target/test-classes:sfqd-core/target/classes \ io.github.pzhin.sfqd.build.PublicApiManifest sfqd-core/target/classes ``` -Review and commit the output only for an intentional API change. After `0.1.0`, +Review and commit the output only for an intentional API change. After `1.0.0`, artifact-to-artifact compatibility checking with Revapi or japicmp should use the previous published release as its baseline; the manifest remains the fail-closed exact-surface gate for the current release line. @@ -133,9 +133,39 @@ deleted afterward. There is no external `distributionManagement` target. An ordinary deploy without an explicit alternate repository therefore fails instead of publishing somewhere unexpected. The source branch records the Maven coordinates, Java -package, Apache-2.0 license, project URL, SCM, and developer metadata. A public -release still requires a non-snapshot release decision, destination -configuration, credentials, signing policy, tag, and release notes. +package, Apache-2.0 license, project URL, SCM, and developer metadata. + +## Maven Central release + +The `release` profile signs and publishes only `sfqd-java-parent` and +`sfqd-core`. Examples, coverage, jcstress, and benchmark artifacts retain +`maven.deploy.skip=true` and are not published. The profile uses Sonatype's +Central Publishing Maven Plugin, requests automatic publication after +validation, and waits for the deployment to reach `published`. + +Before running the profile, the release engineer must have: + +- publishing access to the verified `io.github.pzhin` namespace; +- a Maven Central user token in the `central` server entry of the user-level + Maven `settings.xml`; +- a primary PGP signing key available to GnuPG and distributed through a key + server supported by Maven Central; +- an unlocked GnuPG agent, or `MAVEN_GPG_PASSPHRASE` supplied through a secure + environment mechanism. + +Publish the immutable 1.0.0 coordinates from the commit tagged `v1.0.0`: + +```shell +./mvnw --batch-mode --no-transfer-progress -Prelease clean deploy +``` + +The release profile is opt-in. Normal `verify`, `install`, local publication +topology checks, and consumer builds do not need Maven Central credentials or a +PGP secret key. + +Release wiring can be exercised without network publication by adding +`-Dcentral.publish.skip=true`. This switch does not skip compilation, tests, +artifact generation, or PGP signing. ## CI jobs diff --git a/pom.xml b/pom.xml index 4b3ac14..e09dee6 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 io.github.pzhin sfqd-java-parent - 0.1.0-SNAPSHOT + 1.0.0 pom SFQ(D) Java Parent Build parent for the SFQ(D) Java library. @@ -35,7 +35,7 @@ scm:git:https://github.com/pzhin/sfqd-java.git scm:git:ssh://git@github.com/pzhin/sfqd-java.git https://github.com/pzhin/sfqd-java - HEAD + v1.0.0 @@ -52,6 +52,8 @@ false false 12.3.1 + 0.11.0 + false 0.8.15 0.16 1.37 @@ -66,6 +68,7 @@ 3.6.3 3.5.2 3.1.4 + 3.2.8 3.5.0 3.12.0 3.4.0 @@ -250,6 +253,48 @@ + + release + + + + org.apache.maven.plugins + maven-gpg-plugin + ${maven.gpg.plugin.version} + + + sign-release-artifacts + verify + sign + + true + ${maven.deploy.skip} + + + + + + org.sonatype.central + central-publishing-maven-plugin + ${central.publishing.maven.plugin.version} + true + + central + ${central.publish.skip} + + io.github.pzhin:sfqd-examples + io.github.pzhin:sfqd-coverage + io.github.pzhin:sfqd-jcstress + io.github.pzhin:sfqd-benchmarks + + true + published + sfqd-java 1.0.0 + + + + + jcstress sfqd-jcstress diff --git a/sfqd-benchmarks/pom.xml b/sfqd-benchmarks/pom.xml index 2533ae0..5791655 100644 --- a/sfqd-benchmarks/pom.xml +++ b/sfqd-benchmarks/pom.xml @@ -6,7 +6,7 @@ io.github.pzhin sfqd-java-parent - 0.1.0-SNAPSHOT + 1.0.0 sfqd-benchmarks SFQ(D) JMH Harness diff --git a/sfqd-core/pom.xml b/sfqd-core/pom.xml index 38d57fe..858ee45 100644 --- a/sfqd-core/pom.xml +++ b/sfqd-core/pom.xml @@ -6,7 +6,7 @@ io.github.pzhin sfqd-java-parent - 0.1.0-SNAPSHOT + 1.0.0 sfqd-core SFQ(D) Core diff --git a/sfqd-coverage/pom.xml b/sfqd-coverage/pom.xml index ff62194..65a2c42 100644 --- a/sfqd-coverage/pom.xml +++ b/sfqd-coverage/pom.xml @@ -6,7 +6,7 @@ io.github.pzhin sfqd-java-parent - 0.1.0-SNAPSHOT + 1.0.0 sfqd-coverage pom diff --git a/sfqd-examples/pom.xml b/sfqd-examples/pom.xml index 31e19be..7f0f987 100644 --- a/sfqd-examples/pom.xml +++ b/sfqd-examples/pom.xml @@ -6,7 +6,7 @@ io.github.pzhin sfqd-java-parent - 0.1.0-SNAPSHOT + 1.0.0 sfqd-examples SFQ(D) Examples diff --git a/sfqd-jcstress/pom.xml b/sfqd-jcstress/pom.xml index 258bede..39bed25 100644 --- a/sfqd-jcstress/pom.xml +++ b/sfqd-jcstress/pom.xml @@ -6,7 +6,7 @@ io.github.pzhin sfqd-java-parent - 0.1.0-SNAPSHOT + 1.0.0 sfqd-jcstress SFQ(D) jcstress Harness diff --git a/tools/verify-publication-topology.sh b/tools/verify-publication-topology.sh index bb653aa..cdfa54b 100755 --- a/tools/verify-publication-topology.sh +++ b/tools/verify-publication-topology.sh @@ -100,8 +100,8 @@ PY ) readonly GROUP_DIRECTORY="${DEPLOY_REPOSITORY}/io/github/pzhin" -readonly PARENT_DIRECTORY="${GROUP_DIRECTORY}/sfqd-java-parent/0.1.0-SNAPSHOT" -readonly CORE_DIRECTORY="${GROUP_DIRECTORY}/sfqd-core/0.1.0-SNAPSHOT" +readonly PARENT_DIRECTORY="${GROUP_DIRECTORY}/sfqd-java-parent/1.0.0" +readonly CORE_DIRECTORY="${GROUP_DIRECTORY}/sfqd-core/1.0.0" shopt -s nullglob parent_poms=("${PARENT_DIRECTORY}"/*.pom) @@ -143,7 +143,7 @@ import sys import xml.etree.ElementTree as ET namespace = {"m": "http://maven.apache.org/POM/4.0.0"} -expected_parent = ("io.github.pzhin", "sfqd-java-parent", "0.1.0-SNAPSHOT") +expected_parent = ("io.github.pzhin", "sfqd-java-parent", "1.0.0") parent = ET.parse(sys.argv[1]).getroot() parent_coordinates = tuple( @@ -209,7 +209,7 @@ expected_scm = ( "scm:git:https://github.com/pzhin/sfqd-java.git", "scm:git:ssh://git@github.com/pzhin/sfqd-java.git", "https://github.com/pzhin/sfqd-java", - "HEAD", + "v1.0.0", ) if scm_metadata != expected_scm: raise SystemExit( @@ -235,7 +235,7 @@ effective_core_coordinates = tuple( effective_core.findtext(f"m:{name}", namespaces=namespace) for name in ("groupId", "artifactId", "version") ) -expected_core = ("io.github.pzhin", "sfqd-core", "0.1.0-SNAPSHOT") +expected_core = ("io.github.pzhin", "sfqd-core", "1.0.0") if effective_core_coordinates != expected_core: raise SystemExit( "ERROR: effective core coordinates are " @@ -306,14 +306,14 @@ cat >"${CONSUMER_ROOT}/pom.xml" <publication-smoke ${DEPLOY_REPOSITORY_URI} true - truealways + false io.github.pzhin sfqd-core - 0.1.0-SNAPSHOT + 1.0.0 @@ -339,12 +339,12 @@ final class Consumer { EOF LC_ALL=C LANG=C TZ=UTC "${REPOSITORY_ROOT}/mvnw" \ - --batch-mode --no-transfer-progress --update-snapshots \ + --batch-mode --no-transfer-progress \ -Dmaven.repo.local="${CONSUMER_LOCAL_REPOSITORY}" \ -f "${CONSUMER_ROOT}/pom.xml" clean compile -readonly RESOLVED_PARENT="${CONSUMER_LOCAL_REPOSITORY}/io/github/pzhin/sfqd-java-parent/0.1.0-SNAPSHOT" -readonly RESOLVED_CORE="${CONSUMER_LOCAL_REPOSITORY}/io/github/pzhin/sfqd-core/0.1.0-SNAPSHOT" +readonly RESOLVED_PARENT="${CONSUMER_LOCAL_REPOSITORY}/io/github/pzhin/sfqd-java-parent/1.0.0" +readonly RESOLVED_CORE="${CONSUMER_LOCAL_REPOSITORY}/io/github/pzhin/sfqd-core/1.0.0" if [[ ! -f "${RESOLVED_PARENT}/_remote.repositories" ]]; then fail "fresh consumer did not resolve the published parent" fi