Skip to content

Search is only available in production builds. Try building and previewing the site to test it out locally.

QA — Quality Gates & Acceptance Criteria

Источник: dev/fera/project-design/context/QA.md (read-only; сгенерировано scripts/sync-docs.mjs)

QA — Quality Gates & Acceptance Criteria

Section titled “QA — Quality Gates & Acceptance Criteria”

Companion docs: ADR.md, RFC.md, TECHSPEC.md, OQ.md.

This document defines what “done” and “safe to merge” mean for each subsystem. Intended for both future-self review and AI agent self-checks before considering a workstream complete.


Cross-cutting gates (apply to every module/PR)

Section titled “Cross-cutting gates (apply to every module/PR)”
  • No code path in the UI/domain layer reads directly from the network; all reads go through local storage (ADR-010). Verified by: a test that runs the app with network access blocked and confirms cached history still renders.
  • Any new trait crossing a nylon-ring module boundary at high/unbounded frequency has a batch-shaped API and, if it’s a read-heavy path, a host-side cache in front of it (ADR-005). Verified by: boundary-crossing count under the fixed benchmark scene does not scale linearly with UI-visible item count.
  • Any new persisted data type has an explicit answer to “which encryption tier” (metadata vs content, ADR-016) recorded in code comments or the relevant ADR addendum — not left implicit.
  • Any new multi-state data (status, connection state, etc.) is modeled as an enum or typestate, not a combination of independent booleans/Options (ADR-015), unless a documented reason exists for the exception.
  • Contract test suite exists and passes for any trait with more than one implementation (ADR-014) before the second implementation merges.
  • No inter-actor message is serialized (ADR-007) — raw types only, unless the message is actually crossing a module/process/network boundary.

  • send_message and other authenticated operations are not callable on ProtocolClient<Unauthenticated> — verified at compile time, not by a runtime check (typestate, ADR-015).
  • Reconnect backoff includes jitter; a test simulates N=100 simultaneous reconnect events and confirms requests are not synchronized to a single instant.
  • Health-check completes faster than the MTProto request timeout in the simulated-network-loss test case.
  • Session data is only ever written/read through the Session/Auth actor — no ad-hoc file access to session data elsewhere in the codebase.
  • Every actor has at least one ractor harness test covering: normal message handling, and behavior under a simulated crash/restart.
  • ChatActor ReadState transitions are covered by tests for all three states (Synced, Pending, Offline) and their valid transitions; invalid transitions do not compile or are rejected.
  • Outbox entries persist across a simulated app restart while in Pending state, and are retried on reconnect — covered by an integration test that kills and restarts the process mid-flight.
  • StorageEngine contract test suite passes against sanakirja.
  • Search results from the milli-fork-on-sanakirja are verified equivalent (same ranking, same result set) to upstream milli-on-LMDB for a fixed reference corpus, before the fork is trusted for anything beyond experimentation.
  • Two-phase regex search returns identical results to a naive full-scan PCRE2 baseline on the reference corpus (correctness), and is measurably faster on a corpus above a defined size threshold (performance) — threshold TBD, see OQ.md.
  • Encrypted<T> values are never observed in plaintext outside the decrypt boundary — enforced by the phantom-type design; additionally spot-checked by a test that inspects raw on-disk bytes for known plaintext content and asserts absence.
  • Argon2id parameters (memory/iterations) are documented with the rationale for the chosen cost, not left at library defaults without review.
  • MediaDecoder contract test suite passes against the pure-Rust baseline decoder.
  • Sticker mmap cache: a test confirms that re-displaying a previously cached animated sticker does not re-invoke the decoder.
  • Fixed benchmark scene (parameters per OQ.md) runs under criterion for both tlottie and velato backends before a default is chosen; the decision and its measured basis are recorded in ADR.md as an addendum once made.
  • Optional FFmpeg module: a test confirms the app functions correctly (falls back to “format unsupported” UI, not a crash) when the module is absent.
  • Predictor-issued prefetch requests are verified, under load, to never delay an explicit user-driven fetch already queued or arriving concurrently (priority ordering test at the FetchActor queue).
  • update: &mut State, Msg -> Vec<Effect> has unit test coverage for every Msg variant, runnable with no GPUI context.
  • Pixel-diff regression suite exists per Style module, run against reference screenshots from the corresponding official OS client, with a documented acceptable diff threshold (TBD, see OQ.md).
  • Swapping the Engine module (even to a stub/no-op implementation for testing) does not require changes to ui-elm or domain-layer code — verified by actually performing such a swap in a test build.
  • Feature-module local state (e.g. scroll physics) is confirmed to not appear in the central State type — code review gate, not automatable directly.
  • Native axis absent or failed to load: every slot falls back to an own-renderer equivalent and the app runs (no crash) — explicit test per platform that has a Native module.
  • Native text-input slot passes a basic IME interaction test on each platform where the slot is implemented.
  • Frame-rate budgets are independent: under the fixed benchmark scene, each path (UI ~24 fps, message updates ~45 fps, stickers 60–75 fps) meets its own budget, and a saturated sticker path does not degrade UI-chrome frame timing.
  • Loading a module with a mismatched hash produces a non-blocking UI warning and the module still loads (ADR-004) — explicit test for both halves of this behavior (warning shown AND load proceeds).
  • Loading a module with an incompatible declared version falls back to the built-in default implementation (where one exists) rather than crashing the app — explicit test.
  • A module can be hot-reloaded while a concurrent stream of calls is in flight, with zero dropped calls (relies on nylon-ring’s draining guarantee — write a test that actually exercises this, not just an assumption that the library provides it).
  • The trust manifest itself is signature-verified before any of its contents (including the update endpoint) are trusted — a test confirms a tampered-but-unsigned-modification manifest is rejected.
  • Adding/removing a trusted key via the in-app UI persists correctly and takes effect without requiring an app restart.
  • Translator rights only narrow: a translator attempting to widen the original plugin’s capabilities yields rights = original ∩ user-granted (no escalation path exists).
  • Level 1 translator chains are statically validated at load: cyclic and over-depth chains are rejected before any plugin code runs.
  • Level 2 behavioral translation is fail-closed: without an explicit per-capability user opt-in, flagged functions are not behaviorally translated (the plugin runs untranslated or is refused — never silently behavioral).
  • The plugin-rights UI shows the original plugin’s requested rights, not translator-mapped ones — code review gate.
  • Manifest signature covers the entire entry: a tampered-but-unsigned modification of any field (including host.max_version, fallback, depends_on) is rejected.
  • Downgrade protection: a module below the manifest’s minimum allowed version is refused even with a valid signature; an expired manifest is surfaced, not silently honored.
  • Multi-variant artifacts (avx2 / baseline) select correctly by CPU detect at launch.
  • Struct-layer load order follows the manifest dependency graph (layer + depends_on): a module whose dependencies are not yet loaded is never initialized (topological-order test).
  • Launcher successfully replaces an outdated core module on a clean restart, on all three target OSes.
  • Update process is non-blocking: the app remains usable (on the previous core version) while a new core module downloads in the background; the user is prompted to restart, not forced.
  • Explicit test: no plaintext, user-editable file controls the update endpoint — confirm the endpoint is only ever read from the signature-verified manifest.
  • rstgcalls bindings are isolated behind their own module boundary; a build without the calls module compiles and runs the rest of the client normally (calls feature is not load-bearing for anything else).

Definition of “architecture skeleton complete” (this document’s own

Section titled “Definition of “architecture skeleton complete” (this document’s own”

scope milestone)

This QA document, together with ADR.md/RFC.md/TECHSPEC.md, is considered a complete architectural baseline once:

  • Every ADR has a corresponding section in RFC.md and/or TECHSPEC.md (no decision left undocumented downstream).
  • Every “open question” flagged inline across these docs is also present in OQ.md (no orphaned TODOs).
  • Phase 1 of the sequencing plan (TECHSPEC.md §10) is achievable using only crates/decisions already recorded here — i.e., no hidden unresolved dependency blocks even the first implementation step.