Skip to content

Consume octi-web's published wire-format fixtures#46

Merged
d4rken merged 1 commit into
mainfrom
feat/consume-web-fixtures
May 21, 2026
Merged

Consume octi-web's published wire-format fixtures#46
d4rken merged 1 commit into
mainfrom
feat/consume-web-fixtures

Conversation

@d4rken
Copy link
Copy Markdown
Member

@d4rken d4rken commented May 21, 2026

What changed

No user-facing behavior change. Internal: octi-desktop now consumes octi-web's published wire-format fixtures alongside the existing app-main crypto fixtures. A future octi-web change that drops a required field, retypes a value, or renames an enum entry will fail the matching consumer assertion here — same gate the always-on Tink fixture verify provides for the encryption layer, applied to each module's JSON payloads.

This is B3 of Phase B of the cross-repo wire-format gate. The symmetric upstream-gating workflow on octi-web (which fans out to app-main + octi-desktop tests against an octi-web PR's HEAD) lands in B4 once both consumers are on main.

Technical Context

  • Lockfile schema migrated to v2 multi-source. fixture-lock.json was the v1 flat shape pinning only d4rken-org/octi; it now has a schemaVersion: 2 + sources: { "<owner>/<repo>": { ref, manifest_sha256 } } map with both d4rken-org/octi and d4rken-org/octi-web entries. The parser still accepts the v1 flat shape and normalizes to v2 internally — keeps the migration window robust against a future revert that only touches the lockfile.
  • InteropFixtureSync is multi-source aware. ensureSynced(): Map<source, Path> populates the cache for every locked source; ensureSynced(source: String): Path is a convenience overload for one. Same double-checked-locking singleton so multiple test classes hitting different sources still sync each source once per JVM. Cache layout migrated from .cache/interop-fixtures/<sha>/ to .cache/interop-fixtures/<owner>/<repo>/<sha>/ — old caches get bulldozed on the first new-schema run (gitignored, rebuildable, no concern).
  • Streaming-bounded fetch, real cap. HttpClient.send originally buffered the whole response via BodyHandlers.ofByteArray() before checking the cap — a bad pin or hostile upstream could still consume arbitrary memory before failing. Now uses BodyHandlers.ofInputStream() and aborts during the read loop the moment total > maxBytes. Cap is 2 MiB per fixture file (app-main's streaming-vectors.json is ~1.4 MiB — the two-segment streaming AEAD vector). 64 KiB manifest, 32 files max, 16 KiB lockfile.
  • Override targeting an unknown source fails loudly. A workflow that sends {"d4rken-org/some-future-repo": "<sha>"} for a source not present in fixture-lock.json is a config bug; silent fallback to the locked refs would let a cross-repo gate pass green against a lock that doesn't yet know about it.
  • Per-vector sha256 + byteLength re-verified on read. The producer's self-check pins these at generate time; the consumer re-checks against the actual payloadJson bytes via InteropFixtures.verifyVectorIntegrity(v). A hand-edit to a cached fixture file would fail here, not silently as a green decode.
  • Consumer tests use Serialization.json (the production wire Json instance), not a locally-constructed one — so consumer-side serializer/contextual-config drift is caught at the same interop gate, not just on smoke tests.

Review guidance

  • The Kotlin diff in InteropFixtures.kt / SyncRefResolver.kt / InteropFixtureSync.kt is the cross-repo trust boundary; cross-reference with the sister files at app-common-test/.../testhelpers/interop/ (app-main, B2) and octi-web/src/__interop__/sync-ref-resolver.ts (octi-web, A1) — SOURCE_PATHS entries for shared sources must agree byte-for-byte across every consumer.
  • SyncRefResolverTest.kt expanded from ~17 to 31 tests covering both v1 + v2 lockfile parsing, multi-source resolveAll, every validation path, and the "override targets a source not in the lock" guard.
  • Per-module consumer tests under interop/published/ mirror the structure on app-main's modules-{meta,clipboard,files}/src/test; same canonical-input mirror declared in octi-web's tools/generate-fixtures.ts.

Test plan

  • ./gradlew test green on cold cache (fetched fixtures from d4rken-org/octi@f7e1089 + d4rken-org/octi-web@84b9e57) — 250 tests
  • ./gradlew test green on warm cache (logs "interop fixtures cache hit" for both sources)
  • Pre-existing InteropFixtureVerifyTest, PayloadEncryptionTest, StreamingPayloadCipherTest still green
  • SyncRefResolverTest covers v1 input shape acceptance + v2 multi-source resolve + the override-targets-unknown-source guard
  • Per-module Web consumer tests assert every field of every canonical vector
  • Live cross-repo verify: covered by the symmetric upstream-gating workflow that lands on octi-web in B4 (after this merges).

Sister PRs:

Migrates fixture-lock.json from v1 single-source to v2 multi-source and adds octi-web as a second pinned producer. Per-module consumer tests (Web{Meta,Clipboard,Files}InteropTest) parse each octi-web payloadJson through the production decoder using Serialization.json and assert field-by-field against octi-web's canonical inputs.

InteropFixtureSync was rewritten to be multi-source aware (ensureSynced returns Map<source, Path>; ensureSynced(source) returns one). Cache layout migrated to .cache/interop-fixtures/<owner>/<repo>/<sha>/. The lockfile parser accepts both v1 flat and v2 nested shapes so a hand-edit revert during the migration window still parses.

Pairs with octi-web#26 (producer) and octi#318 (the other consumer).
@d4rken d4rken added Build/Deploy c: sync Component: Synchronization c: module Component: Info Modules c: module/meta Related to meta module (`module-meta`) that contains the basic device infos. c: module/clipboard Related to the clipboard module (`module-clipboard`). c: module/files Related to the file sharing module (`module-files`). labels May 21, 2026
@d4rken d4rken merged commit 2ccdbf2 into main May 21, 2026
5 checks passed
@d4rken d4rken deleted the feat/consume-web-fixtures branch May 21, 2026 13:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Build/Deploy c: module/clipboard Related to the clipboard module (`module-clipboard`). c: module/files Related to the file sharing module (`module-files`). c: module/meta Related to meta module (`module-meta`) that contains the basic device infos. c: module Component: Info Modules c: sync Component: Synchronization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant