원클릭으로
protobuf-schema-evolution
Protobuf compatibility, reserved fields, diagnostics wire contracts, schema versions, and goldens.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Protobuf compatibility, reserved fields, diagnostics wire contracts, schema versions, and goldens.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Use this skill to generate well-branded interfaces and assets for RIPDPI (an Android-native, Compose-first VPN and DPI-bypass app), either for production or throwaway prototypes/mocks/etc. Contains essential design guidelines, colors, type, fonts, brand-ship icons, and an interactive UI kit of every public composable from the live ui/components tree.
Use when managing the Rust workspace, adding/removing crates, editing workspace dependencies, running cargo nextest/audit/deny, configuring Cargo profiles for Android cross-compilation, debugging Cargo.lock churn, migrating crate edition, or wiring Gradle to cargo via the ripdpi.android.rust-native plugin.
Use when modifying the diagnostics scan pipeline, ScanRequest/ScanReport types, ProbeTask families, ripdpi-monitor-engine / ripdpi-diagnostics-* crates, strategy-probe candidates, the diagnostics catalog (packs/profiles), wire-schema contracts between Rust and Kotlin, DIAGNOSTICS_ENGINE_SCHEMA_VERSION, golden contract tests, or adding a new probe type / profile. Triggers on diagnostics scans, strategy probes, automatic audit, dpi-detector profiles, or anything in core/diagnostics or native/rust/crates/ripdpi-monitor-*.
Android-specific Rust build, verification, and packaging — per-target 16 KiB page alignment, size-optimized release profile, ELF symbol allowlist, .so size budgets, NDK 29 specifics. Use when modifying .cargo/config.toml for Android targets, the workspace [profile.release] / [profile.android-jni] block, or when verifying a built .so before release.
Telemetry and observability discipline for the RIPDPI Android Rust stack — control-plane vs data-plane logging, bounded flume event queues, atomic counters, snapshot polling, readiness callbacks, and deterministic JSON contracts. Use when authoring or modifying telemetry emission code, the bounded event ring, the Kotlin-side telemetry consumer, or any per-packet logging.
Custom detekt rules, DI/privacy/suppression guardrails, detekt.yml configuration, and false-positive triage.
| name | protobuf-schema-evolution |
| description | Protobuf compatibility, reserved fields, diagnostics wire contracts, schema versions, and goldens. |
AppSettings is serialized as protobuf bytes and persisted on disk via Jetpack DataStore. When the app updates, new code must read bytes written by every older version. A field-number collision silently corrupts data -- the user loses their configuration with no error and no recovery path.
The diagnostics engine adds a second dimension: Kotlin and Rust exchange JSON wire messages whose schemas must stay in lockstep. A field mismatch causes silent data loss or deserialization failures at runtime.
Schema: core/data/model/src/main/proto/app_settings.proto
Reserved field numbers (never reuse): 15, 16, 17, 29, 30, 31, 32, 69, 71, 93, 94, 130
Reserved field names: desync_method, split_position, split_at_host,
tlsrec_enabled, tlsrec_position, tlsrec_at_sni, udp_fake_count,
split_marker, tlsrec_marker, dns_doh_url, dns_doh_bootstrap_ips,
settings_migration_level
Highest field number in use: 129 (freeze_detection_enabled).
Never reuse a field number. Proto3 identifies fields by number. If
field 15 was desync_method and you assign 15 to something new, existing
persisted bytes silently decode as the wrong field.
Reserve removed fields. Add both the number AND name to reserved.
This makes protoc reject future reuse at compile time.
Use the next available number. Do not fill gaps from past removals.
Set defaults in AppSettingsSerializer. Every new field needs a default
in AppSettingsSerializer.defaultValue (core/data/.../AppSettingsSerializer.kt).
Proto3 zero-values (0, false, "") are implicit; if the real default differs
(e.g., proxy_port = 1080), the serializer is the only place it gets set.
Validate string enums on read. Proto stores enum-like fields as plain strings ("vpn", "proxy"). Fall back to a safe default on unrecognized values.
Rust (ripdpi-diagnostics-contracts, re-exported by ripdpi-monitor-engine) and Kotlin exchange JSON wire messages. Schema version
is tracked by a constant that must be equal on both sides:
DIAGNOSTICS_ENGINE_SCHEMA_VERSION in native/rust/crates/ripdpi-diagnostics-contracts/src/wire.rsDiagnosticsEngineSchemaVersion in core/diagnostics/.../contract/engine/EngineContract.ktDiagnosticsContractGovernanceTest enforces equality by parsing the Rust
source with Regex("""DIAGNOSTICS_ENGINE_SCHEMA_VERSION:\s*u32\s*=\s*(\d+)""").
Wire types (all in wire.rs / EngineContract.kt):
| Rust | Kotlin | Direction |
|---|---|---|
EngineScanRequestWire | EngineScanRequestWire | Kotlin -> Rust |
EngineScanReportWire | EngineScanReportWire | Rust -> Kotlin |
EngineProgressWire | EngineProgressWire | Rust -> Kotlin |
Three test files enforce Kotlin/Rust wire compatibility using shared fixtures
in diagnostics-contract-fixtures/:
diagnostics_progress_fields.json, diagnostics_scan_report_fields.json)
match Kotlin wire classes.serde_json, asserts schema version, verifies outcome taxonomy covers all
emitted native outcome tokens.After a wire change: update structs in Rust/Kotlin, run Rust tests to
regenerate golden files (assert_contract_fixture writes on mismatch in
update mode), then run Kotlin tests. Commit updated fixtures with the code.
app_settings.proto.AppSettingsSerializer.defaultValue.toUiState(), toConfigDraft()).app_settings.proto.reserved numbers list.reserved names list.#[serde(default)] in Rust wire struct.@Serializable data class.DIAGNOSTICS_ENGINE_SCHEMA_VERSION in both Rust and Kotlin.app_settings.protoreserved lines (numbers AND names)AppSettingsSerializer.defaultValue#[serde(default)] / Kotlin defaultscargo test --locked -p ripdpi-monitor-engine) and Kotlin contract tests pass