diff --git a/CHANGELOG.md b/CHANGELOG.md
index 24ffab2be..0b33d552e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,25 @@ follow semantic versioning; release dates are ISO 8601.
## v2.2.1 — Planned
+### Public API
+
+- **The SVG surface graduates from `@Beta` to Stable.** `SvgPath`, `SvgIcon`,
+ `PathBuilder.svg(svgPath)`, both `addSvgIcon(...)` flow adders,
+ `ShapeContainerBuilder.path(w, h, svgPath)`, and the gradient paints the
+ reader emits (`DocumentPaint.LinearAxis` / `RadialCircle`) drop the
+ annotation and join the Stable tier — additive-only changes in minors from
+ here on. The surface shipped in 1.8.0 marked `@Beta` "while it hardens
+ against real-world exporter output"; that hardening is done — the stroke,
+ colour and unit work, per-element error context, the clip-path support
+ added in 1.9.0, and the opacity-family + warning pass in this release —
+ and the API shape itself has not moved since 1.9.0, four minors of real
+ use. The annotation drop also closes an inconsistency: `inlineSvgIcon` /
+ `RichText.svgIcon` and the emoji pipeline were built on `@Beta` `SvgIcon`
+ without carrying the marker themselves; now no SVG entry point does. No
+ binary or source change for callers — the remaining `@Beta` carriers are
+ the `NodeDefinition` Extension SPI seam and the PPTX backend, exactly as
+ [docs/api-stability.md](docs/api-stability.md) lists them.
+
### Fixed
- **The SVG reader honours the opacity family.** `opacity`, `fill-opacity` and
diff --git a/core/src/main/java/com/demcha/compose/document/dsl/AbstractFlowBuilder.java b/core/src/main/java/com/demcha/compose/document/dsl/AbstractFlowBuilder.java
index e5aa793db..d0c4911c7 100644
--- a/core/src/main/java/com/demcha/compose/document/dsl/AbstractFlowBuilder.java
+++ b/core/src/main/java/com/demcha/compose/document/dsl/AbstractFlowBuilder.java
@@ -626,7 +626,6 @@ public T addPath(Consumer spec) {
* @return this builder
* @since 1.8.0
*/
- @com.demcha.compose.document.api.Beta
public T addSvgIcon(com.demcha.compose.document.svg.SvgIcon icon, double width) {
Objects.requireNonNull(icon, "icon");
return add(icon.node(width));
@@ -643,7 +642,6 @@ public T addSvgIcon(com.demcha.compose.document.svg.SvgIcon icon, double width)
* @return this builder
* @since 1.8.0
*/
- @com.demcha.compose.document.api.Beta
public T addSvgIcon(com.demcha.compose.document.svg.SvgIcon icon, double width,
com.demcha.compose.document.node.HorizontalAlign align) {
Objects.requireNonNull(icon, "icon");
diff --git a/core/src/main/java/com/demcha/compose/document/dsl/PathBuilder.java b/core/src/main/java/com/demcha/compose/document/dsl/PathBuilder.java
index 5140620b7..2847c2c9b 100644
--- a/core/src/main/java/com/demcha/compose/document/dsl/PathBuilder.java
+++ b/core/src/main/java/com/demcha/compose/document/dsl/PathBuilder.java
@@ -1,6 +1,5 @@
package com.demcha.compose.document.dsl;
-import com.demcha.compose.document.api.Beta;
import com.demcha.compose.document.node.PathNode;
import com.demcha.compose.document.style.DocumentColor;
import com.demcha.compose.document.style.DocumentDashPattern;
@@ -171,7 +170,6 @@ public PathBuilder closePath() {
* @return this builder
* @since 1.8.0
*/
- @Beta
public PathBuilder svg(SvgPath svgPath) {
Objects.requireNonNull(svgPath, "svgPath");
segments.addAll(svgPath.segments());
diff --git a/core/src/main/java/com/demcha/compose/document/dsl/ShapeContainerBuilder.java b/core/src/main/java/com/demcha/compose/document/dsl/ShapeContainerBuilder.java
index f071b551c..619a2e12a 100644
--- a/core/src/main/java/com/demcha/compose/document/dsl/ShapeContainerBuilder.java
+++ b/core/src/main/java/com/demcha/compose/document/dsl/ShapeContainerBuilder.java
@@ -225,7 +225,6 @@ public ShapeContainerBuilder path(double width, double height,
* @return this builder
* @since 1.8.0
*/
- @com.demcha.compose.document.api.Beta
public ShapeContainerBuilder path(double width, double height,
com.demcha.compose.document.svg.SvgPath svgPath) {
Objects.requireNonNull(svgPath, "svgPath");
diff --git a/core/src/main/java/com/demcha/compose/document/style/DocumentPaint.java b/core/src/main/java/com/demcha/compose/document/style/DocumentPaint.java
index 0d8b1863e..0d35fb669 100644
--- a/core/src/main/java/com/demcha/compose/document/style/DocumentPaint.java
+++ b/core/src/main/java/com/demcha/compose/document/style/DocumentPaint.java
@@ -1,6 +1,5 @@
package com.demcha.compose.document.style;
-import com.demcha.compose.document.api.Beta;
import java.util.List;
import java.util.Objects;
@@ -134,9 +133,6 @@ public DocumentColor primaryColor() {
* exact: colour runs from the first stop at {@code (x0, y0)} to the last
* stop at {@code (x1, y1)} and clamps beyond (pad spread).
*
- * Marked {@link Beta} — emitted by the beta SVG gradient reader; the
- * endpoint normalization contract may shift while that reader hardens.
- *
* @param stops ordered colour stops, offsets in [0,1]; at least two
* @param x0 axis start x, normalized to the box width
* @param y0 axis start y, normalized to the box height
@@ -144,7 +140,6 @@ public DocumentColor primaryColor() {
* @param y1 axis end y, normalized to the box height
* @since 1.8.0
*/
- @Beta
record LinearAxis(List stops, double x0, double y0, double x1, double y1)
implements DocumentPaint {
/**
@@ -179,16 +174,12 @@ public DocumentColor primaryColor() {
* a circle when the box preserves the source's aspect ratio (the SVG
* icon frame contract). Colour clamps beyond the last stop (pad spread).
*
- * Marked {@link Beta} — emitted by the beta SVG gradient reader; the
- * centre/radius normalization contract may shift while that reader hardens.
- *
* @param stops ordered colour stops, offsets in [0,1]; at least two
* @param cx centre x, normalized to the box width
* @param cy centre y, normalized to the box height
* @param r radius as a fraction of the box width; positive
* @since 1.8.0
*/
- @Beta
record RadialCircle(List stops, double cx, double cy, double r)
implements DocumentPaint {
/**
diff --git a/core/src/main/java/com/demcha/compose/document/svg/SvgIcon.java b/core/src/main/java/com/demcha/compose/document/svg/SvgIcon.java
index 6d75bd948..f2afa5bae 100644
--- a/core/src/main/java/com/demcha/compose/document/svg/SvgIcon.java
+++ b/core/src/main/java/com/demcha/compose/document/svg/SvgIcon.java
@@ -1,6 +1,5 @@
package com.demcha.compose.document.svg;
-import com.demcha.compose.document.api.Beta;
import com.demcha.compose.document.node.LayerStackNode;
import com.demcha.compose.document.node.PathNode;
import com.demcha.compose.document.style.DocumentColor;
@@ -69,13 +68,9 @@
* card.center(logo.node(48)); // node form for layer anchors
* }
*
- * Beta: the SVG surface is new in 1.8.0 and marked {@link Beta}
- * while it hardens against real-world exporter output.
- *
* @author Artem Demchyshyn
* @since 1.8.0
*/
-@Beta
public final class SvgIcon {
private final List layers;
diff --git a/core/src/main/java/com/demcha/compose/document/svg/SvgPath.java b/core/src/main/java/com/demcha/compose/document/svg/SvgPath.java
index 813362df2..45caa303f 100644
--- a/core/src/main/java/com/demcha/compose/document/svg/SvgPath.java
+++ b/core/src/main/java/com/demcha/compose/document/svg/SvgPath.java
@@ -1,6 +1,5 @@
package com.demcha.compose.document.svg;
-import com.demcha.compose.document.api.Beta;
import com.demcha.compose.document.style.DocumentPathSegment;
import java.util.ArrayList;
@@ -34,14 +33,9 @@
* .fillColor(crimson));
* }
*
- * Beta: the SVG surface is new in 1.8.0 and marked {@link Beta}
- * while it hardens against real-world files — the API may still adjust in a
- * minor release based on feedback.
- *
* @author Artem Demchyshyn
* @since 1.8.0
*/
-@Beta
public final class SvgPath {
private static final double EPS = 1e-9;
diff --git a/core/src/main/java/com/demcha/compose/document/svg/package-info.java b/core/src/main/java/com/demcha/compose/document/svg/package-info.java
index 955d7fd53..7dca20a1a 100644
--- a/core/src/main/java/com/demcha/compose/document/svg/package-info.java
+++ b/core/src/main/java/com/demcha/compose/document/svg/package-info.java
@@ -8,9 +8,6 @@
* {@code PathBuilder.svg(...)} / {@code PathNode}. Curves render as native
* PDF operators; nothing is tessellated.
*
- * Beta: the whole package is marked beta for the 1.8 cycle while
- * it hardens against real-world exporter output.
- *
* @since 1.8.0
*/
package com.demcha.compose.document.svg;
diff --git a/core/src/test/java/com/demcha/compose/document/svg/SvgPathTest.java b/core/src/test/java/com/demcha/compose/document/svg/SvgPathTest.java
index e90c820a7..17e12caf6 100644
--- a/core/src/test/java/com/demcha/compose/document/svg/SvgPathTest.java
+++ b/core/src/test/java/com/demcha/compose/document/svg/SvgPathTest.java
@@ -205,7 +205,7 @@ void strayTokenAfterCloseIsRejectedAndDoesNotHang() {
// Regression: an operand-less Z/z followed by a non-command token used
// to spin forever (the close op consumes no characters, so the scanner
// never advanced), appending a close op per iteration until OOM. A
- // single malformed/hostile 'd' string would DoS the @Beta reader.
+ // single malformed/hostile 'd' string would DoS the reader.
// Each call must fail fast; the assertTimeout pins that it cannot hang.
Assertions.assertTimeoutPreemptively(
Duration.ofSeconds(2), () -> {