Add requirements traceability gate and Gitea pipelines

Ports JellyTau's traceability tooling to Rust, carrying across the bug it
was repaired for. That gate divided a traced count by frozen literal
denominators; the requirements file outgrew them and it reported 158%
coverage, so it could never fail its own threshold.

Two rules, both enforced by the extractor's own tests:

  - denominators parsed from docs/requirements.md at run time
  - coverage is |traced ∩ defined| / |defined|, never a raw traced count

The gate additionally fails hard on a misconfigured run — zero
requirements parsed or zero files scanned — rather than reporting a
plausible 0%, and on any orphan tag naming a requirement that does not
exist.

Adapted for DarkRoom: IDs are FR-CAT-1 / NFR-P13 / FR-DEV-3a shapes
rather than JellyTau's fixed three digits, and decisions (D), spikes (S),
milestone items (M) and test ids remain taggable while being excluded
from the denominator — counting them inflated it by 25.

Also adds dr-sync: the RemoteBackend trait and capability model, so the
Nextcloud connector is one implementation rather than the only shape the
engine understands. No mature Nextcloud crate exists (reqwest_dav is too
thin), so the connector will be hand-rolled over reqwest per D7.

Gitea workflows follow the same style: containerised, commented with the
reasoning, desktop and Android on every push, plus a CI check that no
core/ crate depends on the UI toolkit (ARCH §6.5a).

Coverage today: 13.3% (19/143). 50 tests passing.
This commit is contained in:
2026-08-09 08:01:32 +02:00
parent 82a5e21ec6
commit 0f202fd3f9
19 changed files with 1913 additions and 22 deletions
+2
View File
@@ -164,6 +164,7 @@ pub fn run() -> Result<()> {
/// maximised 4K canvas costs 4× a 1080p one for detail nobody is looking at
/// while dragging. Real zoom-to-1:1 will render the visible crop at full
/// resolution instead of scaling the whole canvas up.
/// TRACES: FR-DSP-1
const MAX_RENDER_DIM: u32 = 2048;
fn clamp_render_size(w: u32, h: u32) -> (u32, u32) {
@@ -184,6 +185,7 @@ fn clamp_render_size(w: u32, h: u32) -> (u32, u32) {
///
/// A threshold in logical pixels, not a device check — a narrow desktop window
/// gets the compact layout exactly as a tablet in portrait would.
/// TRACES: FR-UI-1 | FR-UI-2
const EXPANDED_MIN_WIDTH: f32 = 820.0;
fn apply_layout_class(window: &AppWindow, width: f32) {