Refine repository guidance

Signed-off-by: Loren Eteval <loren.eteval@proton.me>
This commit is contained in:
Loren Eteval
2026-09-19 12:52:51 +08:00
parent 28807cdf81
commit 8fb02d3b59
27 changed files with 91 additions and 51 deletions
+4 -2
View File
@@ -49,5 +49,7 @@ exceptions; it does not define the source test suite or imply that every package
source verification. Follow actual `needs` and tag gates back to required checks; upload success alone does not
establish release eligibility. A diagnostic Nuitka build that changes compiler/runtime flags is separate evidence
from the ordinary release configuration; record and exercise the latter before claiming a packaged defect resolved.
- Revalidate version/architecture claims against the current matrix instead of duplicating all pins here. When build
topology intentionally changes, update this scope and follow every consumer through upload and publication.
- Revalidate version/architecture claims against the current matrix instead of duplicating all pins here. Record
which workflow invocation and effective dependency set produced an artifact; a passing standalone binary job
does not inherit source-test evidence from a different invocation. When topology changes, follow every consumer
through upload and publication and update this scope.
+3 -1
View File
@@ -105,7 +105,9 @@
elapsed timeout is not evidence of native resource release; distinguish that observation from the intended guarantee.
- Report source inspection, executed tests, mocked platform evidence, and packaged validation separately. A passing
source suite does not prove native distributions or every declared Python/Qt floor. Release import checks do not
replace behavioral tests; record untested targets and compatibility gaps explicitly.
replace behavioral tests; record untested targets and compatibility gaps explicitly. Match verification to the
changed contract: guidance-only work checks claims, references, scope, and path preservation; formatting-only work
checks the promised structural equivalence. Neither warrants unrelated code changes or generated-file refreshes.
- Use real Qt semantics when focus, selection, keyboard modifiers, proxy mapping, event delivery, queued callbacks,
geometry, or QObject destruction matters. Prefer semantic state and destroyed/resource counts; use targeted
rendering assertions when pixels are the defect, without relying on whole-window snapshots or arbitrary sleeps.
+3 -2
View File
@@ -14,8 +14,9 @@ place.
presentation in `Qt`, `Widget`, `Window`, or `Actions`.
- `Interface` and `Models` stay dependency-light and must not import UI, controllers, services, repositories, or concrete
backends. Backend/runtime modules remain importable without constructing editors or the application.
- Package `__init__.py` files are curated compatibility surfaces, not mirrors. Import order can register settings or
affect lazy plugin/Nuitka discovery; search public-import and packaging tests before changing exports.
- Package `__init__.py` files are curated compatibility surfaces, not mirrors. Import-time settings registration and
lazy capability imports are distinct from application construction or plugin discovery. Preserve that distinction
when changing exports; trace transitive imports and public-import/packaging tests, not just the edited module.
## State, data, and ownership
+4 -3
View File
@@ -36,9 +36,10 @@ owned commands and presentation without becoming a workflow authority.
- Batch limits bound work between event-loop yields; the minimum progress interval throttles status refreshes at
those boundaries. It is not an independent paint timer. Keep terminal feedback accurate and choose scale policies
from measured responsiveness rather than freezing a batch count into the command contract.
- Resolve the live target when a command is triggered, then capture intended identities/input before yielding. On
confirmation, resolve those captured targets again rather than adopting a later selection. Progress reports actual
completed work; rejecting a progress dialog stops later batches and does not undo already inserted profiles.
- Capture intended identities/input before yielding. On confirmation, resolve those identities against current
repository/controller state; keep the captured target set even if selection changes, and skip targets that no
longer exist. Progress reports actual completed work; rejecting a progress dialog stops later batches and does
not undo already inserted profiles.
- Verify command state and delegation, cancellation/error presentation, shortcut scope in the real focused widget,
menu rebuild cleanup, and repeated dialog/capture/action lifetimes. Use
`tests/test_qt_interactions.py`, `tests/test_ui_behavior.py`, and `tests/test_qt_lifetime.py` for focused
+5 -4
View File
@@ -9,10 +9,11 @@ boundary between the outer child-process supervisor and the inner application ev
owners already exist during election. Plugins are available before repository restoration interprets persisted
profiles. Register cleanup as each acquisition succeeds, including election-failure paths, and preserve these
dependencies when changing stage order.
- Partial startup, normal exit, signals, and event-loop failure converge on one reverse-order cleanup path. Each
registered stage is attempted once and one failure does not skip later stages. This stack does not retry a failed
callback: service-level retry/retention obligations must be satisfied before its owner disappears. `exit()` requests
Qt termination; action/window/session handlers do not run cleanup directly.
- Partial startup, normal exit, signals, and event-loop failure converge on one reverse-order cleanup path.
`aboutToQuit` and the event-loop `finally` may both reach it; repeated entry must not repeat registered stages.
One callback failure does not skip later stages, but the stack does not retry it. Service-level retry/retention
obligations must be satisfied before the owner disappears. `exit()` requests Qt termination;
action/window/session handlers do not run cleanup directly.
- A stage that fails before its cleanup callback is registered must release its own partial acquisitions. The outer
cleanup stack releases completed stages; it cannot discover half-built controllers, UI, logging handlers, or
native listeners. Restore logging configuration as well as closing handlers. Run service shutdown while its
+3 -2
View File
@@ -45,8 +45,9 @@ generic default.
- Read the selected backend's nested guide before changing its configuration, editor, protocol codec, runtime, TUN,
routing, asset, statistics, or process behavior. Those child guides own backend-specific compatibility details; keep
this parent focused on rules that every backend must satisfy.
- A shared backend-contract change must be checked against Xray, Hysteria 1, Hysteria 2, and External Core rather than
making the most feature-rich backend the implicit default for the others.
- Check a shared backend-contract change against Xray, Hysteria 1, Hysteria 2, and External Core, including an absent
optional capability and a present capability that cannot perform the requested operation. Those are different
outcomes; neither permits shared code to substitute another backend's policy.
## Verification
+5 -2
View File
@@ -10,8 +10,11 @@ preserves the intentionally different direct-subprocess scope for user-selected
TUN address, and application-tun2socks opt-in distinct while preserving unknown top-level fields.
- Loading is observational: do not silently absolutize or rewrite relative paths. Validation before spawn owns path
existence/type, argument and environment types/NULs, endpoint requirements, and a finite bounded shutdown timeout.
- Execute an argument vector with `shell=False`. Never concatenate a shell command, search or kill by process name, or
log arguments/environment values that may contain credentials.
Finite validation must reject non-finite numbers explicitly; range comparisons alone do not reject NaN.
`shutdownTimeout()` currently accepts NaN: this is a validation gap, not a supported timeout.
- Execute an argument vector with `shell=False`. Environment overrides apply to a copy of the inherited process
environment; preparation must not mutate the host's `os.environ`. Never concatenate a shell command, search or
kill by process name, or log arguments/environment values that may contain credentials.
## Runtime and TUN ownership
+3 -3
View File
@@ -10,9 +10,9 @@ exists to preserve Hysteria 1's legacy flat schema and lifecycle without importi
normalize the represented field; runtime validation may reject values that observational loading must preserve.
- Subscription import is allowed only through supported Hysteria 1 protocol handlers. Subscription identity and test
metadata stay in `ServerProfile`, and validation diagnostics never disclose passwords or complete links.
- Runtime and download-test preparation use independent configuration copies. This backend uses application tun2socks
when global TUN requires it and owns the MMDB/ACL inputs used by its routing launch; it does not gain native TUN by
falling through another backends policy.
- This backend participates in application tun2socks through the shared startup workflow; its factory does not own
host routing or connection commit. Keep MMDB/ACL launch preparation here and application-TUN acquisition/rollback
with that workflow. Hysteria 2 native-TUN policy does not apply to this legacy backend.
- Routing ACL/MMDB launch inputs remain distinct from the stored connection JSON. Optional files are read into
launch data before the child starts; a missing/unreadable file is logged and falls back to empty input. Preserve
that observable fallback unless deliberately changing the contract, and include this synchronous file work in
+2 -1
View File
@@ -22,7 +22,8 @@ owns Hysteria 2's nested upstream document, native-TUN capability, statistics, a
Failure to establish required managed server-route exclusions is terminal: use `TUNPreparationError` so registry
dispatch cannot interpret it as permission to fall back to another TUN path. Probe/download copies always remove
native TUN. Managed preparation currently resolves server addresses synchronously; asynchronous readiness does not
make that preparation interruptible.
make that preparation interruptible. Test resolved addresses and explicit route exclusions as separate inputs to
the exclusion guarantee; a resolution failure alone does not prove that valid manual exclusions are absent.
- The statistics provider is a process-lifetime capability; the runtime captures a configured server-API target and
sampling owns its monitor/query lifetime. API URL, client ID, and authorization secret are distinct from client
connection credentials. Keep requests bounded, validate counters, and never log the secret or infer statistics
+5 -4
View File
@@ -34,10 +34,11 @@ owns Xray's full JSON preservation, routing/assets/statistics, and protocol/tran
as a side effect of preparing a launch.
- Routing-rule row moves mutate the live profile's rule list in matching order, with Qt move notifications preserving
selection. Internal drag-and-drop, the Move menu, and list-scoped Ctrl+Up/Ctrl+Down shortcuts use this same model
mutation and preserve selected-row order. Pending rule editors/confirmations use persistent model indexes so moving or deleting
a rule cannot retarget their completion. Verify this through `tests/test_ui_behavior.py` and repository/runtime order
round trips. Rule-editing confirmations share the transient rules dialog as their Qt owner on every platform,
so owner destruction also ends pending confirmation callbacks.
mutation and preserve selected-row order. Pending rule editors/confirmations use persistent indexes in that exact
model: moves preserve their targets, while removal/reset can invalidate them and must suppress write-back.
Persistent indexes are not identities across model replacement. Verify this through `tests/test_ui_behavior.py`
and repository/runtime order round trips. Rule-editing confirmations share the transient rules dialog as their Qt
owner on every platform, so owner destruction also ends pending confirmation callbacks.
- Statistics preparation is optional and may leave a valid runtime without a statistics target. Preserve that
distinction from connection failure; later sampling uses the target captured for this runtime, not newly edited
settings or an assumption based solely on the backend name. `configureXrayStats()` merges the required API service
+4 -1
View File
@@ -15,7 +15,10 @@ compatibility paths.
the active profile. Disconnect/reconnect cancels the exact in-flight generation and ignores stale completion.
- Preserve state and signal ordering, interaction gating, the exact selected `ServerProfile`, runtime snapshots,
reconnect preference, and rollback after validation, runtime, TUN, System Proxy exceptions, cancellation, or unexpected-exit
failure. Worker/native callbacks cross to the controllers Qt thread before transition.
failure. Worker/native callbacks cross to the controllers Qt thread before transition. Signal listeners and queued
actions can synchronously disconnect or replace a start. Required invariant: revalidate current state/operation
after invoking them before completing the connection or applying further host effects; a check before signal
emission alone cannot establish freshness afterward.
- The active live profile is not the prepared document used by an already-started runtime. Resolve identity and
generation before changing state or host effects, and preserve typed runtime failures; cancellation and supersession
are not generic connection errors. Runtime commit, host-effect success, and visible connection state are distinct
+4 -2
View File
@@ -16,8 +16,10 @@ connection policy remains outside it.
exit.
- Required cleanup covers the exact child, process handle, monitor/drain timers, queues, callbacks, and feeder
resources. Stop must bound waits, escalate only the owned child, and remain safe after partial start or repetition.
A join timeout or failed handle close is not a successful reap. Verify actual child liveness before describing a
terminal execution state as complete resource release; include failed escalation in ownership tests.
Execution exit, terminal-event delivery, and monitor/transport disposal need separate assertions; success at one
boundary must not hide a leak at another. A join timeout or failed handle close is not a successful reap. Verify
actual child liveness before describing a terminal execution state as complete resource release; include failed
escalation in ownership tests.
`MultiprocessingRuntime._closeProcess()` currently discards its process reference even when handle close fails.
This is a cleanup-contract gap, not a permissible ownership transfer: a fix must preserve observability of the
outstanding child/handle and agree with the service lease's cleanup-failure semantics.
+3 -2
View File
@@ -26,8 +26,9 @@ provenance; it is not an application-data or settings directory.
- Linux Essentials-only builds deliberately operate without WebEngine; map consumers must retain their non-WebEngine
fallback. macOS/Windows packaged paths may include WebEngine and must resolve all local resources from the bundle.
Audit map assets together with `Furious/Widget/EndpointInfoWidget.py`: local loading, the WebChannel bridge, remote
tile permissions, and external attribution navigation form one boundary. A CSP change alone does not establish
that arbitrary navigation or remote executable code is allowed by the host.
tile permissions, and external attribution navigation form one boundary. Validate both the renderer payload and
host-side acceptance when that bridge changes; editing bundled JavaScript alone cannot establish host behavior.
A CSP change alone does not establish that arbitrary navigation or remote executable code is allowed by the host.
## Verification
+3 -3
View File
@@ -11,9 +11,9 @@ is bundled.
`SubscriptionResult` envelope; nested mappings are not necessarily deeply immutable. Profile construction/metadata
belongs to `SubscriptionImportService`, and group reconciliation, request generations, timers, persistence, and
post-commit effects belong to the subscription service/repository path.
- Automatic detection probes decoders by priority; explicit selection does not authorize format substitution. Return
`None` for a mismatch. Recognizing a share-link envelope does not validate its URI schemes or protocols; the importer
owns that decision. Preserve useful names/upstream IDs and never log a complete payload or link. Current
- Automatic detection probes decoders by priority. An explicit decoder ID restricts dispatch to that decoder;
an unknown ID or a mismatch must not silently resume automatic detection. Return `None` for a mismatch. Recognizing
a share-link envelope does not validate its URI schemes or protocols; the importer owns that decision. Preserve useful names/upstream IDs and never log a complete payload or link. Current
standard formats are plain/Base64 share-link envelopes; linear parsing is not an input-size bound. Introduce
explicit size/depth/work limits before adding richer recursive or nested formats.
- Worker safety is a property of the whole preparation path. Standard decoders opt in, but the selected protocol
+3 -1
View File
@@ -22,7 +22,9 @@ structure and human-reviewed translations.
Do not clear approved review flags or hand-maintain the generated `source` module list. Runtime lookup reverse-maps
translated text to a source key through a shared reverse index across languages. Equal translations for different
source keys can therefore affect later retranslation, including after a language switch. Exercise lookup and
retranslation under explicit locales rather than treating collision diagnostics as cosmetic.
retranslation under explicit locales rather than treating collision diagnostics as cosmetic. A collision-free
extraction report does not prove reverse lookup is unambiguous across every language; inspect the runtime index
and language-switch behavior when two source keys share translated text.
## Extractable source text
+3 -2
View File
@@ -9,8 +9,9 @@ boundaries, not a license for unrelated application orchestration to accumulate
- `Globals` exposes only deliberate application-lifetime owners. Accessors may be absent during partial startup,
isolated tests, or teardown; do not add fallback global owners that create competing lifecycles.
- `AppSettings` keys include preferences and encoded repository blobs. Preserve names, defaults, string/binary
encodings, migrations, and import-time registration. Distinguish desired preferences from confirmed host effects;
startup-registration success is persisted only after its helper reports success. Settings storage and cached
encodings, migrations, and import-time registration. Distinguish desired preferences, helper-reported success,
and independently observed host state; a Boolean success is not an OS read-back guarantee. Startup-registration
success is persisted only after its helper reports success. Settings storage and cached
repository objects are distinct lifetimes: changing a QSettings identity does not reconstruct `Storage` backends.
Tests that replace settings must isolate both boundaries before exercising cleanup or restoration.
- Keep proxy, DNS, routing, TUN, startup registration, session callbacks, external commands, and platform detection here
+3 -2
View File
@@ -26,8 +26,9 @@ implementations can satisfy without importing application composition or concret
contracts.
- Runtime liveness is observational: querying it must not consume an exit, transfer ownership, or dispatch
callbacks. A zero process exit can still be an unexpected connection failure; requested stop and raw exit success
are different facts. Keep semantic startup errors separate from process codes and readiness timeouts. Define
cleanup-failure semantics without assuming every runtime owns a subprocess. Bounded stop/dispose is a contract to
are different facts. Preserve both in terminal events so orchestration can interpret the exit in its current
attempt/connection context without making the runtime own controller policy. Keep semantic startup errors separate
from process codes and readiness timeouts. Define cleanup-failure semantics without assuming every runtime owns a subprocess. Bounded stop/dispose is a contract to
verify, not a guarantee supplied by the base class: third-party work may be non-cooperative. Report known violations
at their implementation/owner boundary rather than weakening the interface to bless an unreleased resource.
- Verify cheap/import-independent contracts plus representative runtime, storage, editor, application-exit,
+4 -2
View File
@@ -34,8 +34,10 @@ never live persistence, Qt presentation, plugin discovery, or workflow execution
## Compatibility and verification
- Protocol construction/export belongs to plugin capabilities. Compatibility shims may remain while callers migrate,
but new protocol-name branches do not belong in core models.
- Protocol construction/export belongs to plugin capabilities. Profile mapping access and `toJSONString()` expose
the connection document, not a complete profile record; persistence must encode metadata explicitly through its
repository contract. A URI is the selected codec's projection. Compatibility shims may remain while callers
migrate, but new protocol-name branches do not belong in core models.
- Verify malformed/current/legacy/unknown-field round trips, metadata/connection separation, copy/identity
semantics, deterministic fingerprints, construction/serialization diagnostics, and capability-based import/export.
Revise this guide with intentional domain changes; do not preserve a legacy identity rule after migration replaces
+2
View File
@@ -52,6 +52,8 @@ remains in each implementation.
- Capability instances default to GUI-thread-only for background subscription preparation. A decoder or protocol
handler opts into worker execution only after its parsing, validation, caches, globals, and Qt usage are audited as
safe for concurrent copied inputs; keep unclassified third-party capability execution on the GUI thread.
`workerSafe` authorizes concurrent execution, not bounded duration or interruptibility. Cancellation can reject a
result while the provider still runs; define resource retention and shutdown separately from that opt-in.
## Verification
+3 -1
View File
@@ -49,7 +49,9 @@ behavior, and lifetime primitives; pages and services consume them without creat
native destruction/disconnection boundary and both owner-first and sender-first teardown.
- Detaching a child ends the shared QObject-tree lifetime assumption. Disconnect the registrations owned by that
feature before reparenting, preserve unrelated listeners, and remove default/escape/selection references when the
child dies. `AppQMessageBox` button reuse and native-destruction regressions exercise this boundary.
child dies. Signal delivery is also a reentrancy boundary: a listener may delete the sender or its owner before
the emitting method resumes. Recheck validity before later native calls. `AppQMessageBox` button reuse and
native-destruction regressions exercise both boundaries.
- Direct connections are appropriate for deliberately shared persistent lifetimes; syntax alone does not prove a
leak. Recheck the selected Nuitka/PySide6 callback protection when the toolchain changes. Static weak method names
are runtime contracts, so renames must update registrations and tests. Weak dispatch itself does not marshal
+3 -1
View File
@@ -35,4 +35,6 @@ outside it.
- Verify legacy/current/unknown-field round trips, malformed roots, restore-failure preservation, ordering/stable
identity, group isolation, reconciliation commit behavior, and persistence in temporary QSettings namespaces. Use
`tests/test_repository_contracts.py` and `tests/test_subscription_sync.py` to revalidate this scope. Reordering a
filtered view must preserve hidden slots and relocate activation by profile ID, not by its former row.
filtered view must preserve hidden slots, selected relative order, and unrelated profiles, then relocate activation
by profile ID. Test the complete repository order as well as the visible projection; a correctly painted view can
conceal a wrong persisted ordering.
+5 -3
View File
@@ -49,9 +49,11 @@ for execution, and Qt for lifetime primitives. This scope owns multi-stage workf
revision, commits while preserving live profile identity/local metadata, then publishes coalesced status/structure.
Post-commit reconnect/test invalidation failure is reported without undoing committed profiles. This is live
reconciliation; repository flush and status persistence are separate boundaries, not one disk transaction.
- User-requested subscription stop invalidates pending generations and marks unfinished groups cancelled. Keep
completed commits/results and automatic update schedules; future updates remain admissible. Logical batch
completion does not release a still-running preparation worker or its relay.
- User-requested subscription stop invalidates pending generations and marks unfinished groups cancelled. Publish
old group cancellation state before aborting replies: abort can synchronously finish a batch whose observers start
another update. Finish only captured old operation contexts, never overwrite a newer generation's status. Keep
completed commits/results and automatic schedules; future updates remain admissible. Logical batch completion
does not release a still-running preparation worker or its relay.
- Provider-reported subscription usage/expiry metadata is untrusted advisory input. Parse it with strict bounds at the
network boundary and commit or clear it only alongside a successful current synchronization; failed synchronization
preserves the last successful metadata.
+3 -2
View File
@@ -20,8 +20,9 @@ protocol and is not a general-purpose utility bucket.
exit result: the flag proves only that a file write completed, not that the child succeeded or the report can be
parsed as an exit protocol. Test reporting both with and without a constructed application/log manager.
- Fallback presentation runs in the parent after a nonzero child result. It constructs a Qt application for the
report but does not call the ordinary application `run()` initialization. Keep that constructor dependency in
failure-path tests, and preserve the original result when evolving reporting failures rather than adding a supervisor.
report but does not call the ordinary application `run()` initialization. Do not assume plugin, storage, controller,
or main-window initialization occurred merely because the fallback has a Qt application. Keep its constructor
dependencies in failure-path tests and preserve the original result when evolving reporting failures.
- Verify normal return, exception, assertion, signal, pre-application failure, crash-log failure, command dispatch,
cross-platform spawn, exact child joining, and absence of manager servers or orphaned resources. If this process
topology changes intentionally, rewrite this guide rather than layering another supervisor over the old one.
+3 -2
View File
@@ -37,8 +37,9 @@ view an independent workflow authority.
window parent can outlive the view, and an unparented prompt can outlive both. Native view destruction must end
the prompt without running its mutation; `test_qt_lifetime.py` exercises this with the containing window still alive.
- Model notifications describe the real source mutation. Structural replacement may legitimately use a model reset;
metadata-only test results should update the exact cell. Do not use resets/full repaints to mask broken mapping or
missing identity restoration. Test selected identities and the current keyboard index independently.
metadata-only test results should update the exact cell. A persistent model index is valid only within its model
and can be invalidated by removal/reset; use domain IDs across collection/model replacement. Do not use resets or
full repaints to mask broken mapping. Test selected identities and the current keyboard index independently.
- Bulk profile mutations validate/prepare a batch before beginning structural notifications. Resolve captured IDs
again after confirmation and between deferred batches, report actual source ranges, and preserve activation before
observers see completed removal. Forward bulk insert/delete operations through the model instead of replaying a
+3 -2
View File
@@ -29,8 +29,9 @@ state.
cleanup path through the containing window/application. Moving a service between pages must not duplicate schedules,
histories, requests, or controller connections during the transition.
- One-shot editors/prompts use managed transient dialogs and weak compiled-safe continuations. Reusable text/editor
windows and retained settings dialogs need an explicit owner and reopen policy. A settings label or Qt parent does
not determine lifetime: check the actual base class and close/accept/reject path before changing deletion policy.
windows and retained settings dialogs need an explicit owner and reopen policy. Classify a plugin-created page or
dialog by the lifetime transferred to its caller, not by the registry's process lifetime. A settings label or Qt
parent does not determine lifetime: inspect the base class and close/accept/reject path before changing deletion policy.
- Empty-state presentation distinguishes an empty repository from a filtered view with no matches. Recovery changes
view filters only; reuse existing import/edit/test actions instead of creating page-specific workflow owners.
- Use normal layouts and `AppQ*` controls. Restore top-level geometry only after persistent composition and through the
+2
View File
@@ -8,6 +8,8 @@ resource-manifest contract; it does not govern general UI layout.
- Use the shared icon helpers and the bundled monochrome/default and white variants as appropriate. An SVG's
`currentColor` alone does not establish Qt theme behavior; verify how `Furious/Qt/QtGui.py` resolves and masks the
chosen asset. Reuse that path instead of adding control-specific recoloring, and do not rely on color alone.
Mask/opacity helpers cache shared icon values: keep cache size bounded and keys independent of widgets, and avoid
mutating a cached icon as if it belonged to one control.
- Preserve license/provenance and the `Resources.qrc` alias contract. Any add, removal, rename, or alias change
updates all consumers and the manifest, then regenerates `Furious/Frozenlib/AppResources.py` with the selected
environment's `pyside6-rcc Resources.qrc -o Furious/Frozenlib/AppResources.py`. Never hand-edit generated resource
+3 -1
View File
@@ -59,7 +59,9 @@ and test-tier selection; test convenience never weakens a production invariant.
relative scaling or resource bounds; document the measured contract and environment rather than treating one
machine's absolute timing as a portable product requirement.
- Update `tests/README.md` when coverage ownership, modules, commands, tiers, opt-ins, or environment requirements change.
The final unittest status and process exit code are authoritative even when negative paths intentionally log errors.
Expected negative-path logs do not themselves mean failure. However, an exception raised inside a Qt-dispatched
callback may reach `sys.excepthook` without failing the surrounding unittest. Reentrant/lifetime tests must also
capture and assert callback exceptions, restoring the hook afterward; a successful runner exit alone is insufficient.
- Review new tests for production-state mutation, live network dependence, process-name cleanup, unbounded waits,
shared mutable fixtures, order dependence, timing-only assertions, and storage assertions where runtime output is
the contract. For guidance-only changes, verify path preservation, changed-file scope, referenced commands/tests,