Core and desktop comments describe the code to a stranger (#6224)
Android / Build, or is the channel already serving this? (push) Successful in 2s
CI & Build / Build now, or wait for Android? (push) Successful in 2s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Python tests (push) Successful in 12s
CI & Build / Web typecheck and unit tests (push) Successful in 8s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
Android / Core and FFI clippy and tests (push) Successful in 1m3s
CI & Build / integration (push) Successful in 1m37s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Successful in 2m40s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 3m14s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 4m3s
Desktop (Tauri) / Update manifest (push) Successful in 4s
Android / Kotlin + Rust (APK) (push) Successful in 8m42s
Android / Build the server image (push) Successful in 1s
Android / Build, or is the channel already serving this? (push) Successful in 2s
CI & Build / Build now, or wait for Android? (push) Successful in 2s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Python tests (push) Successful in 12s
CI & Build / Web typecheck and unit tests (push) Successful in 8s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
Android / Core and FFI clippy and tests (push) Successful in 1m3s
CI & Build / integration (push) Successful in 1m37s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Successful in 2m40s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 3m14s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 4m3s
Desktop (Tauri) / Update manifest (push) Successful in 4s
Android / Kotlin + Rust (APK) (push) Successful in 8m42s
Android / Build the server image (push) Successful in 1s
Milestone 546 "Bring the repo to the comment standard (rule 32) and compose defaults (rule 198)", step #6224 "Comment standard sweep: Rust core and desktop client". Doc comments and comments across inkwell-core, the Tauri app and desktop/packaging now say what the code does and the non-obvious why in the present tense. Gone: milestone tags (M10.x, M11.3, M13, M304, M315, M314, milestone 325), issue and Scribe-note numbers, family-idea and family-rule citations, the run numbers and commit hashes behind past bugs, and the narration of what used to be (the stable channel before it held its own bundles, CARGO_PKG_VERSION as the shown version, the MANIFEST_TAG split, the store's missing tests, the old PKGBUILD). The schema's migration notes keep what each step does and why, without "until now". The forge is called the forge rather than Forgejo. Hazards stay as facts: the dev-rolling tag that must not shadow the branch, the manifest matched on this build's version, the APK's fixed name surviving the prune, the LIKE guard in v9, -wal/-shm moving with the renamed store, panic = abort ending the app. 34 files, comments only: a comment-stripping diff of every changed file against HEAD is identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+26
-32
@@ -1,8 +1,8 @@
|
||||
//! Client<->server compatibility handshake (M10.6).
|
||||
//! Client<->server compatibility handshake.
|
||||
//!
|
||||
//! The desktop app is local-first: it never *needs* a server. When the user links
|
||||
//! one, this module decides whether the two can actually talk — before a single
|
||||
//! note moves. The sync engine (M10.7) consults it on link and on every sync.
|
||||
//! The app is local-first: it never *needs* a server. When the user links one, this
|
||||
//! module decides whether the two can actually talk — before a single note moves.
|
||||
//! The sync engine consults it on link and on every sync.
|
||||
//!
|
||||
//! The contract is two integers per side, versioning the WIRE PROTOCOL separately
|
||||
//! from either program's release version:
|
||||
@@ -22,28 +22,24 @@ use std::sync::OnceLock;
|
||||
|
||||
/// The sync wire protocol this client speaks.
|
||||
///
|
||||
/// v4 (M315): `color` left the note. NOT a floor raise on either side — see the note
|
||||
/// on [`MIN_SERVER_PROTOCOL_VERSION`].
|
||||
/// v5 (#5168): files attached here upload, and removed attachments and previews are
|
||||
/// pushed. Additive: both go only to a server advertising `attachment_sync`.
|
||||
/// v6 (#5175): notes shared with this account, asked for with `shares`.
|
||||
/// v7 (#5176): this account's own pin, archive and position on a shared note, sent
|
||||
/// v4: `color` left the note. NOT a floor raise on either side — see the note on
|
||||
/// [`MIN_SERVER_PROTOCOL_VERSION`].
|
||||
/// v5: files attached here upload, and removed attachments and previews are pushed.
|
||||
/// Additive: both go only to a server advertising `attachment_sync`.
|
||||
/// v6: notes shared with this account, asked for with `shares`.
|
||||
/// v7: this account's own pin, archive and position on a shared note, sent
|
||||
/// only to a server advertising `shared_state`.
|
||||
pub const CLIENT_PROTOCOL_VERSION: u32 = 7;
|
||||
|
||||
/// The oldest server protocol this client can drive — the symmetric half of the
|
||||
/// server's `min_client_protocol_version`.
|
||||
///
|
||||
/// STAYS AT 3 ACROSS v4, and the v2 precedent is the reason to say why rather than
|
||||
/// leave it looking like an oversight. v2 dropped `kind` and `title` and DID move both
|
||||
/// floors, on the rule that "dropping a field a client sends and expects back is
|
||||
/// breaking". `color` fails that test on the second half: a v3 client reading a v4
|
||||
/// server gets `"default"` from serde's default and draws the colour it derives
|
||||
/// locally, which is a board that looks exactly like the one it drew yesterday. A v3
|
||||
/// client PUSHING `color` to a v4 server has the key ignored — the server reads its
|
||||
/// payload key by key and never validates the shape. Neither direction errors, and
|
||||
/// neither loses anything a person can see; `title` was the note's NAME, and this is a
|
||||
/// field that no longer renders anywhere.
|
||||
/// STAYS AT 3 through v4. Dropping a field a client sends and expects back is
|
||||
/// breaking (v2 dropped `kind` and `title` and moved both floors), but `color` is not
|
||||
/// expected back: a v3 client reading a v4 server gets `"default"` from serde's
|
||||
/// default and draws the colour it derives locally, and a v3 client PUSHING `color` to
|
||||
/// a v4 server has the key ignored, since the server reads its payload key by key.
|
||||
/// Neither direction errors or loses anything a person can see.
|
||||
pub const MIN_SERVER_PROTOCOL_VERSION: u32 = 3;
|
||||
|
||||
/// Capabilities without which syncing is meaningless, so their absence BLOCKS the
|
||||
@@ -64,7 +60,7 @@ pub const OPTIONAL_FEATURES: &[&str] = &[
|
||||
|
||||
/// The handshake fields of `GET /api/config`.
|
||||
///
|
||||
/// Every protocol field is optional because a server predating M10.6 simply won't
|
||||
/// Every protocol field is optional because a server older than the handshake won't
|
||||
/// send them. That case has to read as "this server is too old to sync", not as a
|
||||
/// parse failure — which would look to the user like they mistyped the URL.
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||
@@ -190,7 +186,7 @@ pub fn evaluate(info: &ServerInfo) -> Compatibility {
|
||||
///
|
||||
/// The core can't know this: it is compiled into both the desktop and the Android
|
||||
/// app, and its own crate version is a number no build stamps. The app's build is
|
||||
/// what a reader of the header wants (note 3127 §5).
|
||||
/// what a reader of the header wants.
|
||||
///
|
||||
/// So the host names itself. `OnceLock` because identity is fixed for the life of
|
||||
/// the process and a second caller should be ignored rather than race the first.
|
||||
@@ -208,10 +204,9 @@ pub fn set_client_agent(name: &str, version: &str) {
|
||||
/// Headers this client puts on every request to a linked server, so the server can
|
||||
/// log or gate on client identity without a separate handshake round-trip.
|
||||
pub fn client_headers() -> [(&'static str, String); 2] {
|
||||
// `unidentified/unknown`, never a plausible default. Nothing reads this header
|
||||
// today, which is exactly why a wrong value could sit in it for months: the
|
||||
// first person to look at a server log is the first person who could catch it,
|
||||
// and only if what they see is obviously a host that never introduced itself.
|
||||
// `unidentified/unknown`, never a plausible default: a wrong value in a header
|
||||
// nothing checks would sit unnoticed, while an obviously missing one is caught by
|
||||
// the first person who reads a server log.
|
||||
let agent = CLIENT_AGENT
|
||||
.get()
|
||||
.cloned()
|
||||
@@ -259,7 +254,7 @@ pub fn normalize_base_url(raw: &str) -> Option<String> {
|
||||
|
||||
/// Whether a normalized base URL may carry this device's token, as far as the wire
|
||||
/// goes: true for any `https://` server, and for plain `http://` only when the
|
||||
/// host is private (family idea #5105, practice 13).
|
||||
/// host is private.
|
||||
///
|
||||
/// Plain HTTP on a home network is fine and stays supported. Across the internet,
|
||||
/// anyone on the path could read the token and act as this device until it is
|
||||
@@ -363,7 +358,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn server_without_protocol_fields_is_too_old() {
|
||||
// A pre-M10.6 server: /api/config parses, but carries no protocol block.
|
||||
// A server older than the handshake: /api/config parses, but carries no protocol block.
|
||||
let info = ServerInfo {
|
||||
site_name: Some("Inkwell".into()),
|
||||
version: Some("0.0.9".into()),
|
||||
@@ -473,10 +468,9 @@ mod tests {
|
||||
fn server_info_tolerates_unknown_and_absent_fields() {
|
||||
// Forward compatibility: a NEWER server sending fields we've never heard of
|
||||
// must not break the handshake.
|
||||
// Versions come from the constants, not literals: this test is about unknown
|
||||
// FIELDS, and pinning the numbers made it fail the moment the protocol moved
|
||||
// to v2 — for a reason that has nothing to do with what it checks. The feature
|
||||
// list likewise: a literal one went stale when `attachment_sync` was added.
|
||||
// Versions and features come from the constants, not literals: this test is
|
||||
// about unknown FIELDS, and pinned values would fail it whenever the protocol
|
||||
// moves.
|
||||
let features: Vec<&str> = REQUIRED_FEATURES
|
||||
.iter()
|
||||
.chain(OPTIONAL_FEATURES.iter())
|
||||
|
||||
Reference in New Issue
Block a user