From 3912bc0d1dcd48734e75d30f44712d6b72d164e0 Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sat, 26 Sep 2026 22:54:22 -0400 Subject: [PATCH] =?UTF-8?q?Point=20architecture=20=C2=A77.1=20at=20the=20e?= =?UTF-8?q?xecutors=20module=20and=20record=20NFR-ARCH-1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit §7.1 now says where its table lives in code, how the UI thread is marked and guarded, and that the counts are a budget rather than a bound until work is pooled by executor. The register's status note says what is met — named, spawned through one module, block_on guarded and tested — and what is not: pooling, a guard for synchronous file reads and catalog queries, the two mask workers, and threads the core crates start. --- docs/dev/architecture.md | 7 +++++++ docs/dev/requirements.md | 13 +++++++++++++ 2 files changed, 20 insertions(+) diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md index ddd1b72..49dff34 100644 --- a/docs/dev/architecture.md +++ b/docs/dev/architecture.md @@ -593,6 +593,13 @@ does not silently become uploadable by existing. The UI executor never blocks — this is the mechanism behind R4 and NFR-P9, which the requirements state as outcomes without saying how. +**In code:** `ui/dr-ui/src/executors.rs`. `Executor` names the five and states each count with its +reason (`Executor::threads`); `executors::spawn(executor, role, f)` starts a worker named +`:` and marks it with its executor. `run` marks its own thread as the UI executor +before the window exists, and `executors::assert_not_ui` — called by `net_runtime`'s `block_on` — +fails a debug or test build that blocks there. The counts are not yet enforced: a job still gets a +thread of its own, and pooling by executor is where NFR-ARCH-2's priority classes will live. + ### 7.2 Cancellation Cooperative, with tokens threaded through every long operation. Observed within 100 ms diff --git a/docs/dev/requirements.md b/docs/dev/requirements.md index bc1ae59..6f91fa6 100644 --- a/docs/dev/requirements.md +++ b/docs/dev/requirements.md @@ -2154,6 +2154,19 @@ pool, I/O pool, network — with stated thread counts and the invariant that **n occurs on the UI executor**. This is the mechanism behind R4 and NFR-P9, which currently assert an outcome with no stated means. +*Status (2026-09-26).* Named and guarded; not yet bounded. `dr_ui::executors` defines the five +executors with the thread counts of architecture.md §7.1 and the reason for each, and every +long-lived worker in `dr-ui` and the Android entry point is started through its `spawn`, which +names the thread `:` (`net:sync`, `decode:thumbs`). `run` marks its thread as the +UI executor, and `net_runtime`'s `block_on` asserts in debug and test builds that it is not called +there; `executors`' tests show the panic on a thread marked as the UI one and the same call passing +on a worker. Outstanding: the counts are a stated budget, not a limit — each job still gets a +thread of its own, and a pool sized from `Executor::threads` is the change NFR-ARCH-2's priorities +need; the guard covers `block_on` only, not a synchronous file read or a catalog query on the UI +thread, several of which the library and People screens make on a click by design (catalog.md +§1); the two mask workers in `masks_ui.rs` still use `std::thread::spawn`; and threads the core +crates start (the inference engine's reaper and probe, already named) are outside the module. + **NFR-ARCH-2 — Scheduler priority.** The tiling scheduler assigns priority classes, with visible-tile work **strictly preempting** background export and thumbnail work. Without this, NFR-P5's slider latency fails during a batch export — the common case, not an edge case.