What is actually solid in the Fera workspace — and where the repo is stricter than its own spec
Источник:
dev/fera-research/docs/oc3/008-what-is-actually-solid.md(read-only; сгенерировано scripts/sync-docs.mjs)
What is actually solid in the Fera workspace — and where the repo is stricter than its own spec
Section titled “What is actually solid in the Fera workspace — and where the repo is stricter than its own spec”- kind: question
- area: modules
- severity: low
Evidence
Section titled “Evidence”Everything below was measured in this session, not inferred.
Tests: 42 passing, 0 failing.
$ cargo test --workspace --offline running 11 tests -> 11 passed (protocol) running 7 tests -> 7 passed (ui-contract) running 1 test -> 1 passed (storage) running 12 tests -> 12 passed (ui-engine-vello) running 5 tests -> 5 passed (ui-elm) running 6 tests -> 6 passed (domain)Clippy: completely clean (Finished dev profile in 9.67s, zero warnings) under a lint set that is unusually severe — ~/dev/fera/fera/Cargo.toml:33-70:
all = deny; pedantic = deny; nursery = deny; cargo = denyunwrap_used = deny; expect_used = deny; panic = deny; todo = denyunimplemented = deny; dbg_macro = deny; print_stdout = deny; print_stderr = denyindexing_slicing = deny; string_slice = deny; get_unwrap = denyexit = deny; mem_forget = denywarnings = "deny"; unsafe_code = "deny"Note indexing_slicing = "deny" and string_slice = "deny" — these forbid a[i] and &s[..] outright, so every slice in the codebase is bounds-checked by construction.
The spec corpus does not ask for any of this. A grep of QA.md for unwrap|unsafe|determin|lint|rustfmt|clippy|msrv|edition|nightly|panic|forbid returns zero matches. QA.md’s cross-cutting gates (QA.md:11-33) are entirely behavioral — no network reads in the UI layer, batch APIs at module boundaries, enums over booleans, contract tests. There is no unwrap rule, no unsafe policy, no lint requirement, and no determinism gate anywhere in TECHSPEC.md or QA.md. All of that discipline exists only as repo configuration, not as spec.
CI is real and multi-platform. ~/dev/fera/fera/.github/workflows/ci.yml runs on windows-latest, ubuntu-latest, macos-latest (primary dev platform Windows first, per the comment at :16-18), with cargo build, cargo test, cargo clippy --workspace -- -D warnings, cargo fmt --all -- --check, on a pinned nightly-2026-09-10.
Two contract/typestate patterns are genuinely done, not sketched:
- The storage contract suite is generic over the implementation —
storage/src/engine.rs:103:pub fn run<S: StorageEngine>(mut fresh: impl FnMut() -> S). A second engine is a drop-in with zero changes to the suite. This is exactly the ADR-014 shape, done correctly, one step ahead of the requirement. - The protocol typestate is real:
protocol/src/state.rs:24-38definesStateUnauthenticated/StateAuthenticated { session }/StateConnected { session, dc }, and transitions consumeself, so a client cannot be used from two places and invalid methods do not exist on invalid states (state.rs:1-12).
The doc comments are honest about their own limits. protocol/src/state.rs:13-17: “The concrete MTProto transport is injected through the [Transport] trait, so the state machine can be unit-tested with a fake transport (no network, no grmrs) — the real binding lands in the grmrs integration pass.” That is a developer telling the truth about what is and is not wired, which is why findings like 002-module-system-is-zero-lines were findable at all.
Packaging hygiene is done. All 15 crates carry description, keywords, and categories — added deliberately in commit ae46b55 “chore: add missing package keywords/categories”.
The negative findings in this folder (001-007) all describe missing subsystems. This one records that what exists is of good quality, because the risk in a repository like this is that “everything is a placeholder” becomes a self-fulfilling reading that discards real work.
Three things are worth being explicit about:
-
The offline-first read/write path has correct shape and zero wiring.
domain/src/outbox.rs(201 lines, 4 tests) anddomain/src/reconnect.rs(134 lines, 4 tests — full-jitter backoff) are real implementations of the outbox and reconnect semantics ADR-010 requires. They persist toVec<Message>rather than to disk, andoutbox.rs:23storesnot_before: Option<Instant>, which oc5 has already correctly identified as non-persistable across restart (all entries deserialize toNone→ immediate eligibility → retry storm). The logic is right; the storage behind it is aBTreeMap. -
The lint configuration is the strongest thing in the repo, and it is undocumented in the spec.
unsafe_code = "deny"plus a crate-root convention,indexing_slicing = "deny",warnings = "deny"— this is stricter than the entire design corpus requires, and it is what makes the eventual FFI boundary safe to add. oc4 noted thatclippy.toml:2setsavoid-breaking-exported-api = false, which is the one setting that undercuts the repo’s stated premise (versioned hot-swappable contracts); that is a one-line fix and the only strictness regression found. -
missing_docsand the doc-comment culture are a genuine asset for this project. The security-relevant decisions (ADR-004 warning-not-refusal, the load-bearing nature of the storage seam, the trait being a test seam) are all recorded in comments at the point of use. That is whydocs/oc3/001could be written from the source rather than from a suspicion.
Варианты решения (с tradeoffs)
Section titled “Варианты решения (с tradeoffs)”Not really a decision — a correction to the record. But two concrete actions follow:
Option A — promote the repo’s lint set into the spec. Add a QA cross-cutting gate stating the no-unwrap / no-unsafe / no-indexing baseline, so it stops being a property of one repository that a future contributor (or a future modules/ crate outside this workspace) can quietly drop.
Option B — leave it as repo config. Zero cost. Risk: modules/* cdylibs (TECHSPEC.md:30-39) may not live in this workspace at all, in which case the discipline does not automatically extend to them.
Предлагаемое решение
Section titled “Предлагаемое решение”A, cheaply. The modules/ tree is not built yet, so the moment to decide “is this discipline inherited or per-repo” is now, while it costs one paragraph. ADR.md:18 already requires that every module boundary be “designed as a trait contract (interface crate) shared between host and module” — an interface crate shared between host and module is the natural home for the same [lints] workspace = true inheritance, so the mechanism already exists.
Meanwhile: fix clippy.toml:2 (avoid-breaking-exported-api = true), which is a one-line change that restores the one guard the repo’s own premise depends on.
Cross-references
Section titled “Cross-references”- The measurements here are the baseline for
docs/oc3/002-module-system-is-zero-lines.md— the gap is large, but the code that is there is not throwaway. - oc5/001 (local-id reuse → ack misdelivery) is a concrete correctness bug in
domain/src/chat.rs, which is otherwise among the better-implemented files here.