Skip to content

Commit 5671f0d

Browse files
authored
Merge pull request #122 from Tuntii/stabilize-facade-api
core: stabilize facade API surface, feature taxonomy, and public-api CI gate
2 parents f268d40 + 3724bbd commit 5671f0d

36 files changed

+1376
-557
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
# Auto detect text files and perform LF normalization
22
* text=auto
3+
api/public/*.txt text eol=lf
4+
.github/scripts/*.sh text eol=lf

.github/BRANCH_PROTECTION.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Branch Protection Setup
2+
3+
Configure branch protection for `main` so public API checks are required.
4+
5+
## Required Status Checks
6+
7+
Add these checks as required:
8+
9+
- `Public API / Snapshot Drift`
10+
- `Public API / Label Gate`
11+
12+
## GitHub UI Path
13+
14+
1. Repository `Settings`
15+
2. `Branches`
16+
3. Edit rule for `main`
17+
4. Enable `Require status checks to pass before merging`
18+
5. Add the two checks above
19+
20+
## API Automation (optional)
21+
22+
Use a fine-grained token with `Administration: Read and write` for the repository.
23+
24+
```powershell
25+
$owner = "Tuntii"
26+
$repo = "RustAPI"
27+
$token = $env:GITHUB_TOKEN
28+
29+
$body = @{
30+
required_status_checks = @{
31+
strict = $true
32+
contexts = @(
33+
"Public API / Snapshot Drift",
34+
"Public API / Label Gate"
35+
)
36+
}
37+
enforce_admins = $true
38+
required_pull_request_reviews = @{
39+
required_approving_review_count = 1
40+
}
41+
restrictions = $null
42+
} | ConvertTo-Json -Depth 10
43+
44+
Invoke-RestMethod `
45+
-Method Put `
46+
-Uri "https://api.github.com/repos/$owner/$repo/branches/main/protection" `
47+
-Headers @{
48+
Authorization = "Bearer $token"
49+
Accept = "application/vnd.github+json"
50+
"X-GitHub-Api-Version" = "2022-11-28"
51+
} `
52+
-Body $body `
53+
-ContentType "application/json"
54+
```

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Please include a summary of the changes and the related issue. Please also inclu
2424
- [ ] I have added tests that prove my fix is effective or that my feature works
2525
- [ ] New and existing unit tests pass locally with my changes
2626
- [ ] Any dependent changes have been merged and published in downstream modules
27+
- [ ] If `api/public/*` snapshots changed, this PR has `breaking` or `feature` label
2728

2829
## Related Issues
2930

@@ -44,4 +45,4 @@ Add screenshots to help explain your changes.
4445

4546
## Additional Notes
4647

47-
Add any other context about the pull request here.
48+
Add any other context about the pull request here.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
base_sha="${BASE_SHA:?BASE_SHA is required}"
5+
head_sha="${HEAD_SHA:?HEAD_SHA is required}"
6+
7+
changed_snapshots="$(
8+
git diff --name-only "$base_sha" "$head_sha" -- \
9+
api/public/rustapi-rs.default.txt \
10+
api/public/rustapi-rs.all-features.txt
11+
)"
12+
13+
if [[ -z "$changed_snapshots" ]]; then
14+
echo "No public API snapshot changes detected."
15+
exit 0
16+
fi
17+
18+
# Collect labels from env first, then fall back to GitHub event payload.
19+
labels_csv="${PR_LABELS:-}"
20+
if [[ -z "$labels_csv" && -n "${GITHUB_EVENT_PATH:-}" && -f "${GITHUB_EVENT_PATH}" ]]; then
21+
if command -v jq >/dev/null 2>&1; then
22+
labels_csv="$(jq -r '.pull_request.labels[].name' "$GITHUB_EVENT_PATH" 2>/dev/null | paste -sd ',' -)"
23+
fi
24+
fi
25+
26+
labels_normalized=",$(echo "$labels_csv" | tr '[:upper:]' '[:lower:]'),"
27+
echo "Detected PR labels: ${labels_csv:-<none>}"
28+
29+
if [[ "$labels_normalized" == *",breaking,"* || "$labels_normalized" == *",feature,"* ]]; then
30+
echo "Public API snapshots changed and required label is present."
31+
exit 0
32+
fi
33+
34+
echo "::error::Public API snapshots changed but PR is missing required label: breaking or feature."
35+
echo "Changed snapshot files:"
36+
echo "$changed_snapshots"
37+
exit 1

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Changed
11+
- **Facade-first CORE stabilization**:
12+
- `rustapi-rs` public surface is now explicitly curated (`core`, `protocol`, `extras`, `prelude`).
13+
- Internal wiring moved behind `rustapi_rs::__private` for macro/runtime integration.
14+
- `rustapi-core` internal modules tightened (`pub(crate)`/private where applicable).
15+
- `Handler` trait sealed to prevent external implementation leakage.
16+
- **Feature taxonomy refresh**:
17+
- Canonical naming is now `core-*`, `protocol-*`, `extras-*`.
18+
- Meta features standardized: `core`, `protocol-all`, `extras-all`, `full`.
19+
- Legacy feature names remain as compatibility aliases and are deprecated.
20+
21+
### Added
22+
- **Public API governance**:
23+
- Snapshot files under `api/public/` for `rustapi-rs` (default + all-features).
24+
- New CI workflow `.github/workflows/public-api.yml`:
25+
- snapshot drift check
26+
- PR label gate requiring `breaking` or `feature` when snapshot changes.
27+
- **Compatibility contract**:
28+
- New `CONTRACT.md` defining SemVer, MSRV (1.78), deprecation and feature policies.
29+
30+
### Deprecated
31+
- Legacy facade paths and feature aliases are soft-deprecated and scheduled for removal no earlier than two minor releases after announcement.
32+
1033
## [0.1.300] - 2026-02-06
1134

1235
### Added

CONTRACT.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# RustAPI Contract
2+
3+
This document defines compatibility guarantees for the RustAPI workspace.
4+
5+
## 1. Scope
6+
7+
- Stable public contract:
8+
- `rustapi-rs` (facade crate)
9+
- `cargo-rustapi` (CLI surface)
10+
- Internal implementation crates (best-effort, no stability guarantee):
11+
- `rustapi-core`, `rustapi-openapi`, `rustapi-validate`, `rustapi-macros`
12+
- `rustapi-extras`, `rustapi-ws`, `rustapi-toon`, `rustapi-view`, `rustapi-grpc`
13+
- `rustapi-testing`, `rustapi-jobs`
14+
15+
Do not depend on internal crate APIs for long-term compatibility.
16+
17+
## 2. SemVer Policy
18+
19+
- `rustapi-rs` follows strict SemVer:
20+
- Breaking changes: major
21+
- Additive changes: minor
22+
- Fixes/internal-only changes: patch
23+
- Public API surface is tracked by committed snapshots:
24+
- `api/public/rustapi-rs.default.txt`
25+
- `api/public/rustapi-rs.all-features.txt`
26+
- Pull requests that change snapshots must be labeled:
27+
- `breaking` (if compatibility breaks)
28+
- `feature` (if additive API surface change)
29+
30+
## 3. MSRV Policy
31+
32+
- Workspace MSRV is pinned to Rust `1.78`.
33+
- MSRV increases are allowed only in minor or major releases.
34+
- MSRV changes must be called out in changelog/release notes.
35+
- Patch releases must not raise MSRV.
36+
37+
## 4. Deprecation Policy
38+
39+
- Deprecations are soft-first:
40+
- `#[deprecated]` attribute
41+
- explicit migration path in docs/release notes
42+
- Minimum deprecation window before removal: 2 minor releases.
43+
- Removals occur only in major releases.
44+
- Current compatibility window for legacy aliases introduced in this cycle:
45+
- First eligible removal: `v0.3.0` (assuming deprecation introduced in `v0.1.x`).
46+
47+
## 5. Feature Flag Policy
48+
49+
- New facade feature names must follow taxonomy:
50+
- `core-*`
51+
- `protocol-*`
52+
- `extras-*`
53+
- Meta features:
54+
- `core` (default)
55+
- `protocol-all`
56+
- `extras-all`
57+
- `full`
58+
- Legacy aliases may exist temporarily for migration but must be treated as deprecated and eventually removed on a published timeline.
59+
- Published timeline for this migration set:
60+
- `v0.1.x`: aliases available, deprecation warnings/documentation.
61+
- `v0.2.x`: aliases still available, migration reminders.
62+
- `v0.3.0+`: aliases may be removed.
63+
64+
## 6. Internal Leakage Rule
65+
66+
- Public facade signatures should not expose internal crate paths.
67+
- Macro/runtime internals are allowed only via `rustapi_rs::__private` and are excluded from stability guarantees.

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,22 @@ async fn list_users() -> &'static str { "ok" }
114114
***Multi-threaded Runtime**
115115
***Zero Config**
116116

117+
## Feature Taxonomy (Stable)
118+
119+
RustAPI now groups features into three namespaces:
120+
121+
| Namespace | Purpose | Examples |
122+
|:--|:--|:--|
123+
| `core-*` | Core framework capabilities | `core-openapi`, `core-tracing`, `core-http3` |
124+
| `protocol-*` | Optional protocol crates | `protocol-toon`, `protocol-ws`, `protocol-view`, `protocol-grpc` |
125+
| `extras-*` | Optional production middleware/integrations | `extras-jwt`, `extras-cors`, `extras-rate-limit`, `extras-replay` |
126+
127+
Meta features:
128+
- `core` (default)
129+
- `protocol-all`
130+
- `extras-all`
131+
- `full = core + protocol-all + extras-all`
132+
117133
## ✨ Latest Release Highlights (v0.1.335)
118134

119135
***Dual-Stack Runtime**: Simultaneous HTTP/1.1 (TCP) and HTTP/3 (QUIC/UDP) support

RELEASES.md

Lines changed: 0 additions & 48 deletions
This file was deleted.

0 commit comments

Comments
 (0)