Skip to content

Commit 49a9b63

Browse files
authored
feat: add Rust regression release gates
Add 0.8.4 Rust/Python release-gate matrix, fail-closed policy coverage, public release scan, and non-interactive Claude review workflow cleanup.
1 parent 218da33 commit 49a9b63

13 files changed

Lines changed: 795 additions & 10 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ on:
77
branches: [main]
88

99
jobs:
10+
public-release-scan:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
- uses: actions/setup-python@v5
15+
with:
16+
python-version: "3.11"
17+
- name: Run public release scan
18+
run: python voscript-api/scripts/public_release_scan.py --root .
19+
1020
lint:
1121
runs-on: ubuntu-latest
1222
steps:

‎.github/workflows/claude-code-review.yml‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ on:
77

88
permissions:
99
contents: read
10-
id-token: write
1110
pull-requests: write
1211
issues: write
1312

@@ -80,12 +79,14 @@ jobs:
8079
- Synchronized English/Chinese documentation
8180
8281
The PR branch is already checked out in the current working directory.
83-
Post feedback only through the official Claude Code Action GitHub integration.
82+
Use only the configured ANTHROPIC_API_KEY and ANTHROPIC_BASE_URL for Claude access.
83+
Do not start browser login or any interactive authorization flow.
84+
Post feedback only through this GitHub Actions run.
8485
Do not use the GitHub CLI and do not use a user-owned GitHub token.
85-
If the official Claude GitHub App integration is unavailable, fail instead of posting as the repository owner.
86-
If there are no actionable findings, post the standard no-findings confirmation through the action integration.
86+
If non-interactive API-key review is unavailable, fail instead of falling back.
87+
If there are no actionable findings, post the standard no-findings confirmation through the action.
8788
Avoid formatting-only comments.
8889
8990
claude_args: |
9091
--model ${{ env.CLAUDE_MODEL }}
91-
--max-turns 30
92+
--max-turns 8

‎Cargo.lock‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎app/providers/kernel_bridge/__init__.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,31 @@
1313
status_payload_contract,
1414
voiceprint_score,
1515
)
16+
from .release_gates import (
17+
REQUIRED_CI_GATES,
18+
REQUIRED_HARD_FAIL_MODES,
19+
RUST_KERNEL_MODE_ROLLBACK,
20+
RustKernelReleaseGate,
21+
release_gate_matrix,
22+
validate_release_gate_matrix,
23+
)
1624

1725
__all__ = [
26+
"REQUIRED_CI_GATES",
27+
"REQUIRED_HARD_FAIL_MODES",
1828
"RUST_KERNEL_MODE_OFF",
1929
"RUST_KERNEL_MODE_REQUIRED",
30+
"RUST_KERNEL_MODE_ROLLBACK",
2031
"RustKernelBridgeError",
32+
"RustKernelReleaseGate",
2133
"artifact_manifest_contract",
2234
"core_smoke",
2335
"postprocess_segments",
36+
"release_gate_matrix",
2437
"require_rust_core",
2538
"rust_kernel_mode",
2639
"rust_provider_paths_enabled",
2740
"status_payload_contract",
41+
"validate_release_gate_matrix",
2842
"voiceprint_score",
2943
]
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
"""Internal release-gate matrix for selected Rust-backed provider paths."""
2+
3+
from __future__ import annotations
4+
5+
from dataclasses import dataclass
6+
from typing import Final
7+
8+
RUST_KERNEL_MODE_ROLLBACK: Final = "RUST_KERNEL_MODE=off"
9+
10+
HARD_FAIL_IMPORT_FAILURE: Final = "import_failure"
11+
HARD_FAIL_CALL_FAILURE: Final = "call_failure"
12+
HARD_FAIL_INVALID_PAYLOAD: Final = "invalid_payload"
13+
HARD_FAIL_INVALID_RESPONSE: Final = "invalid_response"
14+
HARD_FAIL_PARITY_MISMATCH: Final = "parity_mismatch"
15+
16+
REQUIRED_HARD_FAIL_MODES: Final = frozenset(
17+
{
18+
HARD_FAIL_IMPORT_FAILURE,
19+
HARD_FAIL_CALL_FAILURE,
20+
HARD_FAIL_INVALID_PAYLOAD,
21+
HARD_FAIL_INVALID_RESPONSE,
22+
HARD_FAIL_PARITY_MISMATCH,
23+
}
24+
)
25+
26+
REQUIRED_CI_GATES: Final = frozenset(
27+
{
28+
"python_unit_security_tests",
29+
"kernel_bridge_smoke_tests",
30+
"rust_fmt",
31+
"rust_clippy",
32+
"rust_tests",
33+
"rust_wheel_smoke",
34+
"docker_packaging_smoke",
35+
"public_release_scan",
36+
}
37+
)
38+
39+
40+
@dataclass(frozen=True, slots=True)
41+
class RustKernelReleaseGate:
42+
"""Audit contract for one selected Rust-backed implementation path.
43+
44+
The runtime switch stays intentionally small: Python owns orchestration and
45+
public API shape; Rust owns only selected pure kernels/helpers. This matrix
46+
makes the selected paths and their rollback/fail-closed evidence explicit.
47+
"""
48+
49+
name: str
50+
bridge_function: str
51+
python_owner: str
52+
rust_owner: str
53+
rollback: str
54+
regression_matrix: tuple[str, ...]
55+
hard_fail_modes: frozenset[str]
56+
ci_gates: frozenset[str]
57+
performance_baseline: str
58+
public_api_change: bool = False
59+
60+
61+
SELECTED_RUST_KERNEL_GATES: Final = (
62+
RustKernelReleaseGate(
63+
name="voiceprint_scoring",
64+
bridge_function="voiceprint_score",
65+
python_owner="voiceprints.scoring.score_voiceprint_candidates",
66+
rust_owner="voscript_core::voiceprint::score_voiceprint_candidates",
67+
rollback=RUST_KERNEL_MODE_ROLLBACK,
68+
regression_matrix=(
69+
"raw_cosine_adaptive_threshold",
70+
"asnorm_active_with_margin_guard",
71+
"small_cohort_raw_fallback",
72+
"non_finite_embedding_rejection",
73+
"db_required_mode_payload_export",
74+
"db_off_mode_python_scoring",
75+
),
76+
hard_fail_modes=REQUIRED_HARD_FAIL_MODES,
77+
ci_gates=REQUIRED_CI_GATES,
78+
performance_baseline="internal_scoring_only_synthetic",
79+
),
80+
RustKernelReleaseGate(
81+
name="postprocess_segments",
82+
bridge_function="postprocess_segments",
83+
python_owner="postprocess.segments.build_result_segments",
84+
rust_owner="voscript_core::postprocess::build_result_segments",
85+
rollback=RUST_KERNEL_MODE_ROLLBACK,
86+
regression_matrix=(
87+
"word_normalization",
88+
"adjacent_text_segment_merge",
89+
"word_payload_merge_block",
90+
"duplicate_display_name_disambiguation",
91+
"stable_speaker_label_preservation",
92+
),
93+
hard_fail_modes=REQUIRED_HARD_FAIL_MODES,
94+
ci_gates=REQUIRED_CI_GATES,
95+
performance_baseline="internal_postprocess_only_synthetic",
96+
),
97+
RustKernelReleaseGate(
98+
name="artifact_manifest_contract",
99+
bridge_function="artifact_manifest_contract",
100+
python_owner="pipeline.contracts.artifacts.build_artifact_manifest",
101+
rust_owner="voscript_core::contracts::artifact_manifest_contract",
102+
rollback=RUST_KERNEL_MODE_ROLLBACK,
103+
regression_matrix=(
104+
"public_safe_manifest_build",
105+
"path_and_url_rejection",
106+
"legacy_unknown_entry_tolerance",
107+
"stable_optional_experimental_categories",
108+
),
109+
hard_fail_modes=REQUIRED_HARD_FAIL_MODES,
110+
ci_gates=REQUIRED_CI_GATES,
111+
performance_baseline="internal_helper_only_synthetic",
112+
),
113+
RustKernelReleaseGate(
114+
name="status_payload_contract",
115+
bridge_function="status_payload_contract",
116+
python_owner="pipeline.contracts.status.build_status_payload",
117+
rust_owner="voscript_core::contracts::status_payload_contract",
118+
rollback=RUST_KERNEL_MODE_ROLLBACK,
119+
regression_matrix=(
120+
"known_status_normalization",
121+
"unknown_legacy_status_to_failed",
122+
"basename_only_filename",
123+
"legacy_status_payload_compatibility",
124+
),
125+
hard_fail_modes=REQUIRED_HARD_FAIL_MODES,
126+
ci_gates=REQUIRED_CI_GATES,
127+
performance_baseline="internal_helper_only_synthetic",
128+
),
129+
)
130+
131+
132+
def release_gate_matrix() -> tuple[RustKernelReleaseGate, ...]:
133+
"""Return the selected Rust-backed release gates as an immutable tuple."""
134+
135+
return SELECTED_RUST_KERNEL_GATES
136+
137+
138+
def validate_release_gate_matrix(
139+
gates: tuple[RustKernelReleaseGate, ...] = SELECTED_RUST_KERNEL_GATES,
140+
) -> tuple[str, ...]:
141+
"""Return policy gaps that would block a 0.8.x Rust-backed release."""
142+
143+
gaps: list[str] = []
144+
names: set[str] = set()
145+
bridge_functions: set[str] = set()
146+
for gate in gates:
147+
if gate.name in names:
148+
gaps.append(f"{gate.name}: duplicate gate name")
149+
names.add(gate.name)
150+
if gate.bridge_function in bridge_functions:
151+
gaps.append(f"{gate.name}: duplicate bridge function")
152+
bridge_functions.add(gate.bridge_function)
153+
if not gate.regression_matrix:
154+
gaps.append(f"{gate.name}: missing regression matrix")
155+
missing_hard_fail = REQUIRED_HARD_FAIL_MODES.difference(gate.hard_fail_modes)
156+
if missing_hard_fail:
157+
gaps.append(
158+
f"{gate.name}: missing hard-fail modes {sorted(missing_hard_fail)}"
159+
)
160+
missing_ci = REQUIRED_CI_GATES.difference(gate.ci_gates)
161+
if missing_ci:
162+
gaps.append(f"{gate.name}: missing CI gates {sorted(missing_ci)}")
163+
if gate.rollback != RUST_KERNEL_MODE_ROLLBACK:
164+
gaps.append(f"{gate.name}: rollback must be {RUST_KERNEL_MODE_ROLLBACK}")
165+
if gate.public_api_change:
166+
gaps.append(f"{gate.name}: public API change is not allowed in 0.8.4")
167+
return tuple(gaps)
168+
169+
170+
__all__ = [
171+
"HARD_FAIL_CALL_FAILURE",
172+
"HARD_FAIL_IMPORT_FAILURE",
173+
"HARD_FAIL_INVALID_PAYLOAD",
174+
"HARD_FAIL_INVALID_RESPONSE",
175+
"HARD_FAIL_PARITY_MISMATCH",
176+
"REQUIRED_CI_GATES",
177+
"REQUIRED_HARD_FAIL_MODES",
178+
"RUST_KERNEL_MODE_ROLLBACK",
179+
"RustKernelReleaseGate",
180+
"SELECTED_RUST_KERNEL_GATES",
181+
"release_gate_matrix",
182+
"validate_release_gate_matrix",
183+
]

‎crates/voscript_core/Cargo.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "voscript_core"
3-
version = "0.8.3"
3+
version = "0.8.4"
44
edition = "2021"
55
license = "Apache-2.0"
66
publish = false

‎crates/voscript_core/src/lib.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ fn voscript_core(module: &Bound<'_, PyModule>) -> PyResult<()> {
447447
mod tests {
448448
#[test]
449449
fn package_version_is_set() {
450-
assert_eq!(super::PACKAGE_VERSION, "0.8.3");
450+
assert_eq!(super::PACKAGE_VERSION, "0.8.4");
451451
}
452452

453453
#[test]

‎doc/changelog.en.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@
5252
- Extended contract tests for legacy / unknown artifact manifests, persisted
5353
status payloads, optional schema versions, and Rust artifact helper bridge
5454
validation.
55+
- Added a 0.8.4 Rust-kernel release-gate matrix covering selected
56+
voiceprint, post-process, artifact, and status helper paths with explicit
57+
hard-fail, rollback, CI, and internal performance-baseline evidence.
58+
- Added a repository-owned public release scan and CI gate so PR/release checks
59+
fail before private paths, raw validation material, real IDs, or secret-like
60+
values reach public release text.
5561

5662
## 0.7.6 — Health, alignment, and embedding runtime fixes (2026-05-07)
5763

‎doc/changelog.zh.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@
4242
消歧和 word normalization。
4343
- 扩展 contract 测试,覆盖旧版 / 未知 artifact manifest、持久化 status
4444
payload、可选 schema version,以及 Rust artifact helper bridge 校验。
45+
- 新增 0.8.4 Rust-kernel release-gate matrix,覆盖已选择的声纹计分、结果
46+
后处理、artifact 与 status helper 路径,并明确 hard-fail、rollback、CI
47+
和内部性能基线证据。
48+
- 新增主仓自带的 public release scan 与 CI gate,避免 private path、原始验证材料、
49+
真实 ID 或疑似密钥值进入公开 PR / release 文案。
4550

4651
## 0.7.6 — 健康检查、alignment 与 embedding 运行时修复 (2026-05-07)
4752

‎tests/unit/test_kernel_bridge.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def _core_smoke(payload):
2525
return {
2626
"ok": True,
2727
"echoed": payload,
28-
"version": "0.8.3",
28+
"version": "0.8.4",
2929
"capabilities": {"core_smoke": True, "rust_extension": True},
3030
}
3131

@@ -39,7 +39,7 @@ def test_core_smoke_round_trips_safe_payload_through_imported_extension():
3939

4040
assert result["ok"] is True
4141
assert result["echoed"] == payload
42-
assert result["version"] == "0.8.3"
42+
assert result["version"] == "0.8.4"
4343
assert result["capabilities"]["core_smoke"] is True
4444

4545

0 commit comments

Comments
 (0)