Rust Core foundation + DeepSeek route + transport/pairing/offline + UniFFI + workflow core (Units 2–5a, 9-core)#455
Merged
Conversation
Unit 2 of the Friday Rust/mobile rewrite (goal folder 2026-06-01, gate 21). - friday-core: pure domain types + state machines (incl. offline-queue ack!=completion invariant). - friday-crypto: XChaCha20-Poly1305 field/blob encryption + KEK wrap/rotation + SecureStore (in-memory; native Keychain/Keystore deferred to Unit 5). - friday-storage: SQLite (bundled) schema + forward migrations + destructive backup guard + refuse-when-newer; hash-chained append-only audit ledger; token ledger (fallback=false); encrypted blob store; atomic multi-table write; Hub-vs-Phone schema split (phone omits secret/audit tables). - friday-deepseek / friday-ffi: dependency-boundary stubs; friday-arch-tests asserts friday-ffi excludes friday-deepseek (no provider secret on phone, compile-time). DeepSeek route -> Unit 3; UniFFI bindings -> Unit 5. 51 tests pass; clippy -D warnings clean; fmt clean. Overall Friday v1: NO-GO (greenfield). Not pushed / no PR. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
friday-deepseek: runtime /models discovery + chat/completions through a Transport seam (ureq blocking client), usage->LedgerEntry mapping with fallback=false hard-wired. No fallback to any other provider/local/mock — a failed route returns DeepSeekError (Auth/ProviderUnavailable/...). Credential read only from FRIDAY_DEEPSEEK_API_KEY on the Hub; never printed/logged. Tests: 11 offline (mock transport: discovery, usage mapping, fallback=false, call-counting no-hidden-call, provider-error-does-not-fallback, auth/credential adverse, JSON shape errors) + 1 gated live route smoke (run with the locked key sourced) proving real fallback=false from real usage, persisted to token_ledger (fallback=0). Direct-API probe (GET /models 200, POST /chat 200) captured secret-safe. Dep boundary unchanged: friday-ffi still excludes friday-deepseek and ureq. Closes the Friday-provider-route DeepSeek gate (was NO-GO at intake). Overall Friday v1 remains NO-GO; the 10 sec4 token-safety gate (full lifecycle sweep) is deferred to Units 4/5, not claimed closed. Not pushed / no PR. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Versioned E2E envelope (schema_version per message), first-slice Message kinds
(Pair/PairAck/HubStatus/AskFriday{Request,Stream,Result}/LedgerEntry/ActivityItem/
OfflineQueueAck/Error), serde-JSON encode/decode, highest-common-version
negotiation (errors, never silent downgrade), explicit ErrorCode set,
IdempotencyTracker (msg_id dedup => execute exactly once), and ResumableStream
(replay only missed seq frames). 7 tests incl. forward-compat unknown-field
tolerance + explicit unknown-kind rejection.
Pure types + logic; no networking/encryption (transport seals the serialized
payload). Phone-safe (no provider secret); friday-ffi dep-boundary unchanged.
Unit 4 remains IN PROGRESS: offline-queue execution engine, E2E payload
encryption + relay-cannot-decrypt (X25519), pairing/revoke, and the live
networked WebSocket transport are the remaining sub-slices. Overall v1: NO-GO.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
friday-storage::offline — enqueue (idempotent on msg_id; resend returns the existing row), ack (Queued->Acked), execute_once: requires Acked (an ack is NOT completion), idempotent (second execute on an Executed action is a no-op), fails closed when the original approval is no longer valid (no side effect), and on success flips Acked->Executed while writing an offline_result activity receipt atomically. Enforces 02 sec15 / gate 21 sec4.4. 4 integration tests: ack-is-not-completion + execute-requires-ack, exactly-once on re-delivery (side effect runs once, one receipt), approval-invalid fails-closed (no run, state Failed, no receipt), msg_id dedup. Workspace: 73 tests pass; clippy -D warnings + fmt clean. Unit 4 still IN PROGRESS (E2E payload/relay-cannot-decrypt, pairing/revoke, live transport remain). Overall v1: NO-GO. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
friday-crypto::session — X25519 ECDH device keypairs + HKDF-SHA256 session-key derivation; envelope payloads sealed under the session key with the existing AEAD. Proves the relay-cannot-decrypt property (09 sec7/sec8): two paired devices derive the same key and exchange sealed payloads, while a relay holding only the public keys cannot derive the key and cannot decrypt forwarded ciphertext; the legitimate peer can. Private key has no Debug and StaticSecret zeroizes on drop. 4 new tests (13 total in friday-crypto): shared-key agreement, distinct keys for distinct pairs, relay-cannot-decrypt-but-peer-can, secret-bytes determinism. Workspace: 77 tests pass; clippy -D warnings + fmt clean. x25519 reaches the phone (E2E is a phone capability); friday-deepseek still excluded from ffi. Unit 4 still IN PROGRESS: pairing/revoke (slice d) + live networked transport (slice e) remain. Overall v1: NO-GO. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- relay-decrypt asserts tightened to == Err(CryptoError::Open) (lock out the BadNonce path so a regression cannot pass silently); - zeroize the intermediate HKDF okm buffer in derive_session_key; - name x25519-dalek 'zeroize' feature explicitly (guard StaticSecret wipe-on-drop against a future default-features change); - doc note: relay-cannot-decrypt = passive relay; active MITM is prevented by authenticated QR pairing (slice d). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
friday-crypto::pairing — HMAC-SHA256(qr_secret, device_pubkey) pairing proof + constant-time verify. friday-storage::pairing — pair_device (verifies the proof binds the device pubkey to the out-of-band QR secret; rejects otherwise), is_trusted, revoke_device, rotate_device_key; each writes an audit_ledger entry atomically with the trusted_device change. This discharges the active-MITM property the E2E session module (slice c) deferred to pairing: a relay substituting its own pubkey without the QR secret cannot forge a valid proof and is rejected (tested). 9 new tests (crypto 17 total; storage pairing 5) incl. MITM-substituted-pubkey rejection, wrong-secret rejection, revoke-blocks + double-revoke error, rotation + audit, rotate-revoked error. Workspace: 86 tests pass (+1 ignored live DeepSeek); clippy -D warnings + fmt clean. Unit 4: library slices a-d done; only live networked transport (slice e) remains (next session: confirm whether a localhost socket harness is buildable here before labeling it gated). Overall v1: NO-GO. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
friday-transport: length-prefixed frames carrying friday-protocol envelopes sealed under friday-crypto X25519/HKDF session keys; recv/send helpers + a relay model. Proven over REAL loopback TCP (loopback bind/connect confirmed available in this env): - direct E2E round-trip (phone<->hub derive the same session key, exchange); - relay-forwards-ciphertext-but-cannot-decrypt: a real relay hop forwards frames while holding no session key; the plaintext never appears in forwarded bytes and the relay (own keypair vs the public keys) cannot decrypt a captured frame; - reconnect + resumable catch-up: after a dropped connection the phone reconnects, reports its last-acked seq, and the hub replays exactly the missed frames. 6 tests (3 unit + 3 socket integration). Workspace: 92 tests pass; clippy -D warnings + fmt clean; friday-ffi still excludes friday-deepseek. Scope: proves the transport's security/reconnect/resume PROPERTIES over a real socket; the WebSocket upgrade/handshake framing is a mechanical wrapper around the same frame+seal contract (the only remaining transport detail). Overall v1: NO-GO. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…view nits) - README: update to Units 2-4 (crate table, 92-test count, security properties, accurate deferred list) — was stale at the Unit-2 '52 tests' snapshot. - friday-transport doc: WS framing is *a* remaining transport detail, not the *only* one (real-network LAN/Tailscale/SSH transports + Direct|Relay|Stale connection-state machine are also first-slice-deferred per gate 21 §4). Doc-only; no behavior change. Overall v1: NO-GO. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
friday-ffi: UniFFI 0.31 proc-macro/library mode (cdylib + lib) exposing a first-slice, FFI-safe interface (ConnStateFfi enum; initial_connection_state, connection_is_online, connection_is_stale_or_offline, protocol_schema_version, negotiate_schema_version) over friday-core + friday-protocol. Added a uniffi-bindgen bin for host binding generation. Generated Swift + Kotlin bindings from the built cdylib; a host swiftc-compiled sample client called into the Rust core through the generated Swift bindings and returned correct results (schema=1, conn-state + version-negotiation) -- 'Swift bindings exist and are exercised by a sample client' (gate 03 §8). Kotlin generation succeeded; Kotlin run-smoke is gated (no kotlinc). Native app shells + simulator/emulator screenshots + device proof remain operator-gated (no full Xcode/Android SDK/rustup mobile targets). Trust boundary preserved: friday-ffi still excludes friday-deepseek (asserted). Workspace: 93 tests pass; clippy -D warnings + fmt clean. Overall v1: NO-GO. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
friday-core::workflow — WorkflowRunState machine (Pending/Running/ AwaitingCheckpoint/Done/Failed, checkpoints pause the run); StepStatus + resolve_step_completion encoding the load-bearing invariant (08 §6 / 10 §6 / 00 §2): a side-effect step is Verified ONLY with deterministic evidence, else ProofPending -- a model self-claim never marks a side-effect verified; only no-side-effect steps may complete on a model result. NeedsMeItem + aggregate_needs_me (urgency-first, stable; preserves provider detail). 4 new friday-core tests. Workspace: 97 passed / 0 failed (+1 ignored live DeepSeek); clippy -D warnings + fmt clean. Scope: Unit-9 CORE logic (evidence-gating + needs-me invariants). Workflow/activity PERSISTENCE + Activity inbox UI are remaining Unit-9 work. Overall v1: NO-GO. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…int) .github/workflows/rust-core.yml: runs cargo fmt --check, clippy -D warnings, and cargo test --workspace for rust-core/** on PRs and main pushes (paths-filtered; the live DeepSeek test is #[ignore]d so no network/secrets needed). rust-core/rust-toolchain.toml pins 1.95.0 + clippy/rustfmt so CI matches local. Gives the merged all-Rust workspace a real CI gate. Overall v1: NO-GO. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First landing of the all-Rust Friday Core (the v1 source-of-truth) per the Rust/mobile rewrite goal folder. Purely additive: a new
rust-core/Cargo workspace + one paths-filtered CI workflow; no TypeScript changed. Overall Friday v1 status remainsNO-GO(greenfield) — this is foundational, not v1.Included (committed, tested, reviewed)
ZeroizeOnDrop, noDebug.friday-deepseek, Hub-only): runtime/modelsdiscovery, chat, usage→ledgerfallback=false, no fallback to any provider/mock; credential read only from the locked env, never logged. Live route smoke proven (gated#[ignore]), direct API probe, no-hidden-call + adverse-credential tests.friday-protocol(versioned envelope, version negotiation, idempotency execute-once, resumable replay); offline-queue engine (ack≠completion, exactly-once, approval-fails-closed, atomic receipt); X25519/HKDF E2E session keys with relay-cannot-decrypt proven over real loopback sockets; authenticated pairing (HMAC binds device pubkey to QR secret; MITM-substituted-pubkey rejected) + revoke + rotation; live framed transport over loopback (direct E2E, relay-blind forwarding, reconnect + resumable catch-up).friday-ffiUniFFI interface; Swift+Kotlin bindings generated; a hostswiftcclient exercised the Rust core over FFI.proof_pending) + Needs-Me urgency-first aggregation..github/workflows/rust-core.yml(cargo fmt/clippy-D warnings/test onrust-core/**) + pinned toolchain.Tests / checks
cargo test --workspace→ 97 passed / 0 failed (+1#[ignore]d live DeepSeek route test, run separately with the locked key).cargo clippy --workspace --all-targets -- -D warningsclean;cargo fmt --all -- --checkclean;git diff --checkclean.friday-ffi(phone) excludesfriday-deepseek(provider-secret-bearing) — "no provider secret on phone" is a compile-time property.Commits
0ca9d121,21417322(Unit 2);07999266(Unit 3);3c99759a,34fbc2d8,aeb81c6d,3e4485bf,ef61f7ca,e6b870b7,733a1aaa(Unit 4);aae27f44(Unit 5a);c4641547(Unit 9 core);0d0c3244(CI).Honestly NOT done (deferred / gated — NOT claimed PASS)
Direct|Relay|Staleconn-state machine over live sockets. (Gate §4 is "first slice only"; loopback proves the security/reconnect/resume properties.)10§4 token-safety full-lifecycle no-hidden-call sweep (Unit 3 proved the library-level property only).Why merging this partial is safe + useful
Purely additive (
rust-core/+ one paths-filtered CI workflow); no TS touched; existing CI unaffected; the new workspace is locally proven and now CI-gated. It establishes the v1 Rust source-of-truth foundation later units build on. Overall Friday v1 remainsNO-GO.🤖 Generated with Claude Code