mirror of
https://github.com/LorenEteval/Furious.git
synced 2026-10-05 05:17:59 +03:00
Add scoped repository guidance
Signed-off-by: Loren Eteval <loren.eteval@proton.me>
This commit is contained in:
@@ -1,38 +1,67 @@
|
||||
# Furious repository guidance
|
||||
|
||||
## Source of truth and change discipline
|
||||
## Working method
|
||||
|
||||
- Treat the checked-out tree as authoritative. Do not resurrect deleted experiments or infer current architecture from old commits or conversations.
|
||||
- Preserve unrelated working-tree and staged changes. Keep edits scoped to the requested behavior.
|
||||
- When `.codegraph/` exists, use `codegraph explore` before text search or broad file reading to locate symbols and understand call paths. Use `rg` for exact follow-up searches.
|
||||
- Before running Python commands, inspect the repository root for an existing environment matching `.venv*` or `venv*`. Prefer its interpreter for project scripts, tests, formatters, generators, and dependency-backed tools whenever usable; do not create or modify an environment unless the task requires it.
|
||||
- Keep the existing GPL header, `from __future__` placement, import grouping, and repository naming style in touched Python files.
|
||||
- Treat the checked-out tree as authoritative. Preserve unrelated staged and unstaged work; do not revive deleted
|
||||
experiments or infer architecture from old history.
|
||||
- If `.codegraph/` exists, use `codegraph explore` before broad text search or file reading. Use `rg` for exact
|
||||
follow-up searches.
|
||||
- Before Python work, inspect the repository root for `.venv*` or `venv*` and prefer its interpreter when usable. Do not
|
||||
create or modify an environment unless required.
|
||||
- Keep edits focused. Preserve GPL headers, `from __future__` placement, import grouping, repository naming style, and
|
||||
public compatibility unless a deliberate migration is part of the task.
|
||||
|
||||
## Architecture boundaries
|
||||
## Pythonic design
|
||||
|
||||
- Keep models/configuration documents independent of presentation. Repositories own persistence, services own workflows, controllers own application state/orchestration, and widgets/actions are thin adapters.
|
||||
- Prefer plugin capabilities and backend factories over protocol/core conditionals in shared application code.
|
||||
- Treat persisted user configuration as input. Connection-time, test-time, routing, logging, and statistics preparation must operate on explicit runtime copies unless an API is documented as mutating persisted state.
|
||||
- Application-wide controllers and repositories may be process-lifetime objects; transient UI and temporary process resources must not become accidental global state.
|
||||
- Keep platform-specific host mutation behind the existing runtime/system abstractions. A feature must remain safe to import and test on unsupported platforms.
|
||||
- Prefer the simplest design that makes ownership, state transitions, failure, and side effects explicit. Readability
|
||||
and one canonical path beat clever indirection or parallel implementations.
|
||||
- Keep policy close to the layer that owns it: models describe data, repositories persist it, services perform
|
||||
workflows, controllers own application state/orchestration, plugins/backends own protocol-specific behavior, and UI
|
||||
adapts those APIs.
|
||||
- Make invalid states and boundary failures visible with specific return values, result objects, or exceptions. Catch
|
||||
broadly only at a genuine isolation boundary, log actionable context, and do not silently convert explicit user input
|
||||
into a different behavior.
|
||||
- Bound external work: network requests, subprocess startup/shutdown, thread joins, and host commands need timeouts or a
|
||||
documented non-GUI execution context. Cleanup must be idempotent and own exact resources, never search by process
|
||||
name.
|
||||
- Prefer immutable metadata, pure transformations, dependency injection, and explicit runtime copies. Avoid global
|
||||
mutable state, hidden mutation, duplicated caches, and UI-owned business state.
|
||||
|
||||
## Generated artifacts and translations
|
||||
## Repository invariants
|
||||
|
||||
- `Furious/Frozenlib/AppResources.py` and `Furious/Externals/GenTranslation.py` are generated artifacts. Do not hand-maintain them as ordinary source.
|
||||
- Add user-facing strings through the existing translation-aware widgets/actions and `_()` extraction conventions. Regenerate translations with `Translation.py` when translation source changes.
|
||||
- Pass only static string literals to `_()`. Runtime-formatted translations such as `_(f'{arg} do something...')` and `_('{arg} do something...'.format(...))` are unsupported; translate static fragments and compose dynamic values outside `_()` instead.
|
||||
- Curly braces in extracted strings are reserved for application-constant substitution: `Translation.py` resolves every `{name}` through `Furious.Frozenlib.Constants`. Do not use braces as ordinary runtime-format placeholders.
|
||||
- Treat persisted user configuration as input. Connection, routing, testing, logging, and statistics preparation operate
|
||||
on explicit runtime copies unless an API is documented as mutating storage.
|
||||
- Prefer plugin capabilities/factories over protocol or core conditionals in shared managers. Registries store classes,
|
||||
factories, descriptors, and immutable metadata—not transient UI instances.
|
||||
- `CoreRuntime` means one managed proxy-core lifecycle regardless of whether its implementation uses a subprocess,
|
||||
multiprocessing, or an in-process binding. Reserve process terminology for actual operating-system processes and
|
||||
handles.
|
||||
- Application-wide controllers and repositories may be process-lifetime. Transient UI, network replies, timers,
|
||||
callbacks, and temporary processes must not become accidental global state.
|
||||
- Keep platform mutation behind `Frozenlib`/runtime abstractions so unsupported platforms remain safe to import and
|
||||
tests can fully mock host operations.
|
||||
- Treat secrets, subscription payloads, paths, URLs, and plugin data as untrusted input. Do not log credentials or full
|
||||
sensitive configurations; validate before host or process use.
|
||||
|
||||
## Verification
|
||||
## Generated files and translations
|
||||
|
||||
- Run the narrowest relevant tests first, then the affected test tier documented in `tests/README.md`.
|
||||
- Format only touched Python files with the repository Black configuration, then run Black check mode on the same files.
|
||||
- For backend/process/platform changes, verify failure cleanup and bounded shutdown as well as the success path.
|
||||
- For Qt ownership changes, follow `Furious/AGENTS.md`, use the `manage-qt-pyside6-lifetimes` skill, and run the relevant lifetime tests; do not use forced garbage collection as a production fix.
|
||||
- `Furious/Frozenlib/AppResources.py` and `Furious/Externals/GenTranslation.py` are generated. Change their source
|
||||
inputs and run the existing generator instead of hand-maintaining them.
|
||||
- Add user-facing text through translation-aware controls and `_()` extraction conventions, then run `Translation.py`.
|
||||
- `_()` normally receives a static string literal. The sole dynamic exception is an f-string made only from bare names
|
||||
in `Furious.Frozenlib.Constants`; the extractor resolves those constants. Runtime values, attributes, calls, format
|
||||
specifications, and `.format(...)` inside `_()` are unsupported.
|
||||
- Curly braces in extracted strings are reserved for application-constant substitution, not ordinary runtime
|
||||
placeholders.
|
||||
|
||||
## Code review rules
|
||||
## Verification and review
|
||||
|
||||
- Flag UI code that becomes a second owner of controller/domain state.
|
||||
- Flag mutation of persisted configuration during runtime preparation.
|
||||
- Flag new protocol-specific branches in shared managers when a plugin capability can own the behavior.
|
||||
- Flag edits to generated artifacts without the corresponding generator workflow.
|
||||
- Run the narrowest relevant tests first, then the affected tier in `tests/README.md`. Tests must not touch production
|
||||
settings, networking, routing, TUN, startup registration, or unrelated processes.
|
||||
- Format only touched Python files with the repository Black configuration and run Black check mode on those files.
|
||||
- For backend/process/platform work, verify error cleanup and bounded shutdown. For Qt ownership work, follow
|
||||
`Furious/AGENTS.md` and `Furious/Qt/AGENTS.md`, use the `manage-qt-pyside6-lifetimes` skill, and run the relevant
|
||||
lifetime tests.
|
||||
- Review for duplicated state authorities, mutation of persisted configuration during runtime preparation, broad
|
||||
swallowed errors, unbounded waits/caches, generated-file edits without regeneration, and protocol branches that belong
|
||||
in a capability.
|
||||
|
||||
+39
-34
@@ -1,46 +1,51 @@
|
||||
# Furious application guidance
|
||||
# Furious package guidance
|
||||
|
||||
These rules apply to all application code below `Furious/` and refine the repository-wide guidance.
|
||||
## Layering and state
|
||||
|
||||
## State and layering
|
||||
- `Models` and `Interface` define core-neutral data and contracts. `Repository` owns persistence, `Service` owns
|
||||
workflows/resources, `Controllers` own shared application state, `Plugins`/`Backends` own protocol behavior, and
|
||||
`Application` composes the runtime. `Qt`, `Widget`, and `Window` present that state.
|
||||
- Existing UI code has compatibility paths that reach repositories or application globals. Do not extend that coupling
|
||||
when a controller/service API can be introduced cleanly; migrate incrementally rather than creating a second state
|
||||
authority.
|
||||
- Long-lived objects may be exposed through `Frozenlib.Globals`, but accessors must tolerate partial startup and
|
||||
shutdown. Never place transient dialogs, replies, workers, or editor instances in application globals.
|
||||
- Keep GUI-thread work short. Worker callbacks publish immutable/result data to the GUI thread; they do not mutate
|
||||
widgets directly.
|
||||
|
||||
- `ConnectionController`, `RoutingController`, and `SettingsController` are the application state authorities. UI consumers observe/delegate; they do not maintain parallel state machines.
|
||||
- Services and controllers may depend on models, repositories, plugin capabilities, and runtime abstractions. They must not strongly own transient dialogs, editors, message boxes, or page-local widgets.
|
||||
- Keep blocking I/O, subprocess waits, DNS/network work, and heavy aggregation off the GUI thread. Marshal presentation updates back through Qt signals/slots.
|
||||
- Cleanup/shutdown methods must be safe on partial startup and repeated calls. Release callbacks, timers, threads, child processes, and native handles owned by the component.
|
||||
## Qt/PySide6 lifetime invariants
|
||||
|
||||
## Qt/PySide6 lifetime
|
||||
Classify every dynamic Qt object before choosing ownership:
|
||||
|
||||
Every `QObject` has an intentional Python owner, Qt parent, lifetime category, and destruction path.
|
||||
- **Application-lifetime:** main window, navigation pages, shared controllers/managers. Give them one durable
|
||||
application owner and idempotent cleanup.
|
||||
- **Reusable:** intentionally hidden and shown again. Retain one explicit Python owner and release it deliberately at
|
||||
final shutdown.
|
||||
- **Transient:** editors, prompts, progress windows, and one-shot dialogs. Use a suitable parent plus normal
|
||||
close/deferred deletion; do not retain them after completion.
|
||||
|
||||
Use the repository `manage-qt-pyside6-lifetimes` skill for any change or audit involving Qt object creation, ownership, signals, timers, filters, caches, windows/dialogs, memory growth, premature collection, or stale wrappers. Read its detailed lifetime reference completely before acting.
|
||||
Use `AppQTransientDialog` for one-shot dialogs. `AppQDialog.open()` and `AppQMessageBox.open()` retain asynchronous
|
||||
dialogs until completion, so local variables are safe; connect `finished` before `open()`. Use `exec()` only where
|
||||
synchronous control flow is required. Do not add `WA_DeleteOnClose` universally or use `gc.collect()` as a production
|
||||
fix.
|
||||
|
||||
- Long-lived pages/controllers are application owned and created once.
|
||||
- Reusable windows retain one explicit strong owner and reset state when shown again.
|
||||
- Transient dialogs/windows retain a strong owner only while visible, use the normal close/accept/reject path, and are released after destruction. Use `WA_DeleteOnClose` only for genuinely transient objects.
|
||||
- A local variable followed by `.show()`/`.open()` is not sufficient ownership for an asynchronous top-level window. Conversely, parenting a closed transient dialog to an application-lifetime widget does not make its destruction correct.
|
||||
- Parent timers, animations, actions, menus, models, delegates, and event filters according to their intended owner. Stop/remove them when Qt automatic teardown is not sufficient.
|
||||
- Prefer QObject-bound slots. Review lambdas, closures, partials, callbacks, and long-lived senders for captures of transient UI.
|
||||
- Never place transient `QObject` instances or bound instance methods in unbounded caches. Static caches may contain immutable metadata, strings, classes/factories, or application-lifetime icons.
|
||||
- Weak registries must not have a parallel strong owner, callbacks that capture the target, or dead entries that accumulate. Check wrapper validity before invoking weakly registered QObjects.
|
||||
- Custom `closeEvent`, `accept`, `reject`, and `done` implementations must preserve the corresponding Qt lifecycle unless intentionally documented.
|
||||
- Do not update widgets from worker threads. Do not mask ownership bugs with routine `gc.collect()`, global window retention, or swallowed deleted-wrapper exceptions.
|
||||
QObject parent ownership and Python references are separate concerns. Parent timers/models/delegates where appropriate,
|
||||
stop/disconnect owned resources on teardown when auto-disconnection is insufficient, remove event filters when lifetimes
|
||||
differ, and clear references after `destroyed`. Never cache a transient QObject instance or an instance method with
|
||||
unbounded `lru_cache`.
|
||||
|
||||
## UI and translation
|
||||
|
||||
- Reuse the application Fluent widgets, action rows, menus, design tokens, and translation-aware controls before creating one-off styling or manual retranslation code.
|
||||
- Keep page/window presentation thin: existing `QAction` or controller/service logic should remain the behavior source when controls are rearranged.
|
||||
- When replacing a dialog/menu/window implementation, preserve shortcuts, default/escape results, enabled/checkable state, translations, and explicit transient/reusable lifetime semantics.
|
||||
- Reuse `AppQ*` Fluent/theme/translation-aware primitives. Prefer layout composition over fixed geometry and preserve
|
||||
keyboard, focus, shortcut, accessibility, and theme behavior.
|
||||
- Pass source text at construction when an `AppQ*` control already retranslates it; avoid parallel manual
|
||||
`retranslate()` logic.
|
||||
- UI shows errors at the interaction boundary, while services/controllers provide structured, testable failures. Do not
|
||||
broadly catch and hide deleted-wrapper or worker failures.
|
||||
|
||||
## Required verification
|
||||
## Verification
|
||||
|
||||
- For transient UI changes, exercise repeated create/open/close cycles and verify `destroyed`, weak-reference clearing, and stable live-object counts.
|
||||
- For reusable windows, verify normal close/show reuse and explicit owner destruction without duplicated actions or signals.
|
||||
- Run `tests.test_qt_lifetime` for ownership changes and the relevant UI behavior tests; use the explicit stress tier only when the change warrants it.
|
||||
|
||||
## Code review rules
|
||||
|
||||
- Flag controllers/services/registries retaining transient widgets or widget-bound callbacks.
|
||||
- Flag asynchronous top-level windows without a durable Python owner.
|
||||
- Flag parentless active timers, stale event filters, instance-method caches on transient UI, or close handlers that only hide a transient object.
|
||||
- Flag direct widget mutation from non-GUI threads.
|
||||
- For changed transient/reusable UI, test open/close/show cycles, weak-reference clearing or deliberate retention,
|
||||
signal/timer stability, and asynchronous completion.
|
||||
- Use offscreen Qt and the isolated settings helpers documented in `tests/README.md`. Distinguish allocator high-water
|
||||
behavior from linear live-object/resource growth.
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Actions guidance
|
||||
|
||||
- Actions are thin presentation adapters: resolve current controller/service state at trigger time, invoke the owning
|
||||
API, and present the result. Do not make an action a second owner of connection, routing, repository, or import state.
|
||||
- Reuse shared `QAction` command logic for menus/buttons. Keep shortcuts, check state, enabled state, translation, and
|
||||
callback semantics synchronized from one source.
|
||||
- `AppQAction.callback` is intentionally a strong reference. Scope actions to a suitable QObject owner; an
|
||||
application-lifetime action must not retain a transient bound method or closure.
|
||||
- Import through `profileFromAny`/plugin capabilities. Treat clipboard, file, URI, QR, and subscription text as
|
||||
untrusted; report per-item failures without logging credentials or whole secret-bearing payloads.
|
||||
- Long or batched work must yield safely or use an owned worker/progress dialog. Do not sleep the GUI thread.
|
||||
- Asynchronous prompts/editors use managed `open()` lifetime and connect completion before opening. Rebuilt dynamic
|
||||
menus must release obsolete `QMenu`/`QAction` objects rather than accumulating them.
|
||||
|
||||
## Code review rules
|
||||
|
||||
- Flag duplicated controller logic, captured transient widgets, unsanitized sensitive logging, and action-local
|
||||
persistence changes.
|
||||
- Verify repeated triggering does not multiply dialogs, callbacks, menus, or workers.
|
||||
@@ -0,0 +1,23 @@
|
||||
# Application composition guidance
|
||||
|
||||
- `DesktopApplication` is the composition root. It creates and durably owns application-lifetime controllers,
|
||||
repositories, services, pages, main window, tray, thread pool, IPC server, and plugin registry integration.
|
||||
- Keep bootstrap order explicit: environment/plugins and storage before consumers, controllers/services before UI, and
|
||||
restoration only after all dependencies exist. Accessors must tolerate partial startup and cleanup.
|
||||
- Each successful startup stage registers its exact cleanup immediately. Partial startup and final shutdown use the
|
||||
same reverse-order, failure-isolating cleanup stack, and cleanup is idempotent without relying on destructor timing.
|
||||
- Keep graceful shutdown distinct from the final base-Qt event-loop exit. Delayed forced-exit callbacks must never
|
||||
recursively re-enter application cleanup.
|
||||
- The tray owns its long-lived actions/menus and reflects controller state. Dynamic submenu rebuilds must not retain
|
||||
stale actions or menus.
|
||||
- Application code may import higher layers to compose them; lower layers must not import `DesktopApplication` to obtain
|
||||
dependencies when injection or a narrow global accessor suffices.
|
||||
- Keep blocking startup checks bounded and event-loop safe. A startup failure must leave enough runtime available to
|
||||
report the error and still clean up.
|
||||
|
||||
## Verification
|
||||
|
||||
- Test partial initialization, repeated cleanup, singleton IPC commands, tray menu rebuilding, startup restoration, and
|
||||
failure before the main window exists.
|
||||
- Do not start the production singleton/host mutation in ordinary tests; compose fakes through the established
|
||||
boundaries.
|
||||
+29
-33
@@ -1,42 +1,38 @@
|
||||
# Backend and core-runtime guidance
|
||||
# Backend and core-integration guidance
|
||||
|
||||
These rules apply to bundled backend implementations and refine `Furious/AGENTS.md`.
|
||||
- A backend owns protocol parsing/export, editor factories, runtime materialization, process integration, statistics,
|
||||
validation, and native-TUN capability for its core. Register these through plugin capabilities instead of adding
|
||||
shared-manager conditionals.
|
||||
- The JSON/document submitted to a core is the runtime authority. Build it from a deep/runtime copy; never mutate the
|
||||
persisted profile while preparing connection, routing, logging, testing, or TUN state.
|
||||
- Preserve full user-authored core documents and unknown supported fields. Report a lossless-compatibility failure
|
||||
instead of silently compiling or deleting unsupported configuration.
|
||||
|
||||
## Configuration ownership
|
||||
## Native TUN policy
|
||||
|
||||
- The configuration passed to a core is authoritative. Preserve the persisted/original document and apply connection, routing, logging, statistics, and test preparation to a runtime/deep copy.
|
||||
- Do not silently repair or delete explicit user core configuration and switch networking modes. Let the core or normal validation surface malformed user configuration.
|
||||
- Protocol-specific parsing, editing, export, runtime construction, and compatibility belong to the backend/plugin capability, not shared connection UI or `ConnectionManager` conditionals.
|
||||
For a normal connection:
|
||||
|
||||
## Native TUN contract
|
||||
- If the Furious native-TUN option is enabled, replace any runtime native TUN with the generated TUN; mark TUN handled
|
||||
and do not start application tun2socks.
|
||||
- If the option is disabled and the user document contains native TUN, preserve it unchanged; mark TUN handled and do
|
||||
not start tun2socks.
|
||||
- If neither exists, do not inject native TUN; global TUN mode may use tun2socks.
|
||||
- Proxy-only operations such as speed/latency tests explicitly strip native TUN from their own temporary copy.
|
||||
|
||||
`KernelFactory.prepareTUN()` is the normal-connection ownership decision:
|
||||
Never remove an explicit user TUN merely because an application toggle is off, and never run native TUN plus application
|
||||
tun2socks together.
|
||||
|
||||
- Native-TUN option enabled: Furious-generated native TUN is authoritative in the runtime copy. Replace existing runtime native TUN, report handled, and do not start application tun2socks.
|
||||
- If requested managed native TUN cannot be prepared safely, fail the connection with a useful error; never silently change to application tun2socks.
|
||||
- Native-TUN option disabled with explicit user native TUN: preserve it unchanged, report handled (including malformed explicit values), and do not start application tun2socks.
|
||||
- Native-TUN option disabled with no native TUN: do not inject native TUN; application tun2socks may be selected when global TUN mode requests it.
|
||||
- Never allow backend native TUN and application tun2socks to run together.
|
||||
## Runtime and UI
|
||||
|
||||
Proxy-only operations such as download-speed tests must derive a separate configuration and explicitly strip/omit native TUN. Do not weaken normal-connection preservation to satisfy a probe/test workflow. Enabling the managed native-TUN option is the explicit user choice that permits replacement in the runtime copy; toggling it off never removes custom native TUN.
|
||||
- Core runtimes expose actionable `startError()`, exact resource ownership, bounded startup/shutdown, and deterministic
|
||||
cleanup. Process-backed runtimes additionally own and reap their exact child process. Keep platform exit codes
|
||||
semantically intact.
|
||||
- Keep runtime modules importable without constructing editor widgets. Use literal, discoverable lazy
|
||||
imports/registrations so Nuitka includes every editor family without per-editor command changes.
|
||||
- Backend editors follow `Furious/Qt/AGENTS.md`; factories create fresh transient editors and registries retain
|
||||
factories/classes, not editor instances.
|
||||
|
||||
## Core lifecycle
|
||||
## Verification
|
||||
|
||||
- Factories return prepared kernel launches; process objects own only their exact child/process resources and callbacks.
|
||||
- Startup failures must expose a useful start error and clean partially created resources. Shutdown must be bounded, reap exact owned children, release readers/queues/timers, and be idempotent.
|
||||
- Do not use shell expansion for core commands. Do not log credentials, full arguments, secrets, or environment values.
|
||||
- Keep lazy editor imports as literal imports inside factories/providers so Qt initialization stays lazy and Nuitka can discover dependencies.
|
||||
|
||||
## Required verification
|
||||
|
||||
- Run `tests.test_native_tun_semantics` after changing native-TUN preparation or application tun2socks selection.
|
||||
- Test both persisted-document immutability and the exact runtime document submitted to the core.
|
||||
- Test normal connection and proxy-only preparation independently; do not share a helper that erases their policy difference.
|
||||
- For process changes, run the relevant external/process stress tests and verify failure cleanup.
|
||||
|
||||
## Code review rules
|
||||
|
||||
- Flag removal of custom native TUN while its backend-managed toggle is disabled.
|
||||
- Flag a handled native-TUN path that can still instantiate application tun2socks.
|
||||
- Flag test/probe TUN stripping implemented inside the normal connection policy.
|
||||
- Flag unbounded process waits, orphaned reader threads/handles, or errors hidden behind a generic fallback.
|
||||
- Test URI/mapping round trips, malformed input, runtime document equality, original-document immutability, all
|
||||
native-TUN matrix cases, proxy-only stripping, failed core startup, and cleanup.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# Controller guidance
|
||||
|
||||
- Controllers are process-lifetime state authorities. Expose observable state/transitions and orchestrate
|
||||
repositories/services; do not retain transient widgets or duplicate service resource ownership.
|
||||
- `ConnectionController` owns the connection state machine and interaction gating. Stable and transitional states,
|
||||
failures, unexpected exits, reconnect preference, `runtimes` snapshots, and signal ordering must remain explicit.
|
||||
Runtime managers are injected for tests.
|
||||
- `RoutingController` owns selected/active routing semantics. Distinguish repository selection from the routing actually
|
||||
applied to a live connection; derive runtime routing through backend capabilities.
|
||||
- `SettingsController` validates, persists, and applies settings through service-level APIs where practical. Host
|
||||
registration or administrator-dependent changes persist only after success; UI pages should not implement settings
|
||||
policy.
|
||||
- Controller signals carry state/results, not widget callbacks. Long work belongs in services/workers, and GUI-thread
|
||||
entry points must not perform unbounded waits.
|
||||
- Treat partial startup/shutdown as normal: global dependencies may be absent and cleanup methods must be repeatable.
|
||||
|
||||
## Code review rules
|
||||
|
||||
- Flag direct ownership of dialogs/pages, duplicated connection/routing state, settings saved after failed side effects,
|
||||
and protocol branches that belong in a capability.
|
||||
- Test success, validation failure, startup failure, unexpected exit, signal order, restoration, cancellation, and
|
||||
idempotent shutdown.
|
||||
@@ -0,0 +1,18 @@
|
||||
# Process-backed core-runtime guidance
|
||||
|
||||
- This package provides low-level process-backed `CoreRuntime`, queue, output-redirection, and tun2socks primitives. It
|
||||
must not own controller, repository, page, or protocol policy.
|
||||
- Own exact child `Process`/handle objects. Startup validates launch specs and readiness; shutdown uses bounded
|
||||
terminate/join/kill escalation, reaps the child, stops timers/queues, clears callbacks, and is idempotent.
|
||||
- Preserve platform exit codes and expose actionable startup errors. Do not convert serialization/start failures to an
|
||||
unexplained success or “Unknown error” when context exists.
|
||||
- Process targets do not touch GUI objects. Queue/monitor callbacks cross to the owning Qt thread through the
|
||||
established timer/signal boundary.
|
||||
- A timer without a QObject parent requires an explicit durable Python owner and `dispose()` path. Never rely on wrapper
|
||||
finalization for process or timer cleanup.
|
||||
- Temporary output files/streams close on every success and error path; avoid unbounded queues and blocking reads.
|
||||
|
||||
## Verification
|
||||
|
||||
- Test invalid specs, failed spawn, early exit, normal output, bounded stop escalation, repeated dispose, exact-child
|
||||
cleanup, and no residual timers/threads/handles.
|
||||
@@ -0,0 +1,15 @@
|
||||
# Bundled extension guidance
|
||||
|
||||
- Extensions are bundled plugins, not exceptions to the plugin contract. Declare stable metadata and contribute
|
||||
capability objects through `Furious.Plugins` APIs.
|
||||
- Store factories, handlers, descriptors, and immutable metadata; never retain transient UI or active runtime instances.
|
||||
- Subscription decoders recognize and normalize one representation. Treat remote payloads as untrusted, return “not
|
||||
matched” distinctly from “matched but invalid,” and leave profile materialization/import policy to the shared
|
||||
pipeline.
|
||||
- Imports must stay lightweight and deterministic so plugin discovery and Nuitka inclusion work without side effects.
|
||||
- Initialization/shutdown must support registry rollback and repeated process cleanup.
|
||||
|
||||
## Verification
|
||||
|
||||
- Test discovery order, malformed/ambiguous payloads, capability registration, rollback, and shutdown without network or
|
||||
production state.
|
||||
Vendored
+16
-53
@@ -1,56 +1,19 @@
|
||||
# Translation catalog guidance
|
||||
# Generated translation catalog guidance
|
||||
|
||||
These instructions apply to `Furious/Externals/` and refine the repository-level generated-artifact and translation
|
||||
rules.
|
||||
- `GenTranslation.py` is generated by the repository-root `Translation.py`; do not hand-edit it. Change source strings
|
||||
or the translation data and regenerate.
|
||||
- Each catalog entry uses this key order: `source`, supported language keys in the generator's canonical order, then
|
||||
`isReviewed`.
|
||||
- `source` is a sorted, deduplicated list of fully qualified Python module names that contain the extracted source text.
|
||||
Remove stale sources through regeneration, not manual cleanup.
|
||||
- `_()`/`gettext()` extraction accepts static literals. The only f-string exception consists exclusively of bare names
|
||||
defined in `Furious.Frozenlib.Constants`; the extractor substitutes those values before catalog lookup.
|
||||
- Do not put runtime values, attribute expressions, calls, format specifications, `.format(...)`, or ordinary brace
|
||||
placeholders inside a translatable expression.
|
||||
- New or changed translations remain unreviewed until a human verifies meaning. Preserve Unicode, HTML/newline
|
||||
semantics, and natural RU/ZH wording rather than literal word order.
|
||||
|
||||
## Generated catalog ownership
|
||||
## Verification
|
||||
|
||||
- `GenTranslation.py` is generated by the repository-root `Translation.py`; do not hand-maintain catalog entries for
|
||||
routine source changes.
|
||||
- Add or change extracted source strings at their call sites, run the translation generator for every supported
|
||||
language, review the translations, and regenerate the catalog.
|
||||
- If generated record structure or key ordering needs correction, fix `Translation.py` rather than applying a one-off
|
||||
rewrite to `GenTranslation.py`.
|
||||
|
||||
## Translation record structure
|
||||
|
||||
- `TRANSLATION` maps each exact English source string to one record.
|
||||
- `source` is the generator-maintained list of fully qualified modules where that string is extracted.
|
||||
- Each supported non-English language has one abbreviation key, such as `RU` or `ZH`, whose value is the reviewed
|
||||
user-facing translation.
|
||||
- `isReviewed` is the string `"True"` or `"False"`, not a JSON/Python boolean. Mark it `"True"` only after every
|
||||
language value in the record has been reviewed.
|
||||
- Preserve this preferred serialized key sequence in every record: `source`, language 1, language 2, ..., `isReviewed`.
|
||||
Keep `source` first and `isReviewed` last; use the catalog's stable language order between them.
|
||||
- Do not add ad-hoc metadata fields that the generator and runtime do not understand.
|
||||
|
||||
For example:
|
||||
|
||||
```python
|
||||
"Delete": {
|
||||
"source": [
|
||||
"Furious.Backends...",
|
||||
"Furious.Backends...",
|
||||
],
|
||||
"RU": "Удалить",
|
||||
"ZH": "删除",
|
||||
"isReviewed": "True"
|
||||
}
|
||||
```
|
||||
|
||||
## Extraction and review rules
|
||||
|
||||
- Keep translation source keys as literal strings discoverable by the existing `_()` extractor. Do not pass formatted
|
||||
strings, f-strings, or `.format(...)` results to `_()`.
|
||||
- Braces in extracted strings are reserved for application-constant substitution by `Translation.py`; they are not
|
||||
general runtime-format placeholders.
|
||||
- Let the generator derive `source`; do not fabricate or retain stale module names manually.
|
||||
- Review natural terminology and meaning in every supported language, not only literal word correspondence. Do not
|
||||
approve source-language placeholders as completed translations.
|
||||
|
||||
## Code review rules
|
||||
|
||||
- Flag direct catalog edits that should have been made through source extraction and regeneration.
|
||||
- Flag records whose key sequence is not `source`, language keys, then `isReviewed`.
|
||||
- Flag `"isReviewed": "True"` when any language is missing or unreviewed.
|
||||
- Flag dynamic formatting inside `_()` and changes that treat braces as ordinary formatting syntax.
|
||||
- Run `Translation.py` for the affected languages, inspect the generated diff for source/key ordering and stale entries,
|
||||
and ensure a second generation is stable.
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# Frozenlib foundation guidance
|
||||
|
||||
- `Frozenlib` is the compatibility/platform foundation and a broad public import surface. Keep imports cheap,
|
||||
cross-platform, and free of GUI/application construction side effects. Preserve exported names unless a migration
|
||||
covers all wildcard consumers.
|
||||
- `Constants`, enums, version, and pure helpers stay dependency-light. `Globals` contains narrow accessors for
|
||||
deliberate application-lifetime owners and must return safely during partial startup/shutdown.
|
||||
- `AppSettings` is the centralized settings boundary. Preserve defaults, value types, migrations, and compatibility
|
||||
aliases; write requested state only after required host side effects succeed.
|
||||
|
||||
## Platform and process safety
|
||||
|
||||
- Host mutation (proxy, DNS, startup registration, session, routing) is platform-isolated, returns/logs actionable
|
||||
failure, uses bounded commands/joins, and can be fully mocked. Never test against real host state.
|
||||
- Own exact daemon threads/processes. Clear dead references so restart is possible; cleanup is bounded and idempotent.
|
||||
Do not suppress a failed shutdown or leave persisted state claiming success.
|
||||
- `parseHostPort` and other externally keyed caches must be bounded. Unbounded caches are limited to finite application
|
||||
metadata and must not capture QObject instances or bound methods.
|
||||
- Rate limiting on GUI-callable paths must not sleep the caller. Network helpers support IPv4/IPv6 and use bounded
|
||||
resolution/connect operations.
|
||||
|
||||
## Mixins and resources
|
||||
|
||||
- Weak instance pools must not be paired with hidden strong references or callbacks that capture the target. Remove dead
|
||||
entries and tolerate already-deleted Qt wrappers.
|
||||
- Context managers restore the exact prior enabled/signal-block state and remain safe when nested.
|
||||
- `AppResources.py` is generated from resource inputs. Do not hand-edit generated bytes or bypass the
|
||||
resource-generation workflow.
|
||||
|
||||
## Code review rules
|
||||
|
||||
- Flag GUI/high-level imports, unbounded host commands or joins, state persisted after host failure, broad process-name
|
||||
cleanup, sensitive logging, unbounded external-input caches, and globals holding transient objects.
|
||||
- Run direct mocked platform/helper tests plus affected controller/service tests.
|
||||
@@ -0,0 +1,20 @@
|
||||
# Interface contract guidance
|
||||
|
||||
- This package defines small, low-level contracts shared across layers. Keep imports cheap and avoid depending on UI,
|
||||
controllers, services, repositories, or concrete backends.
|
||||
- Abstract methods state observable behavior, ownership, mutation, and failure contracts; concrete implementations may
|
||||
add detail but must not weaken them.
|
||||
- `CoreRuntime` is the canonical mechanism-neutral lifecycle contract. Preserve its semantic exit codes, `startError()`,
|
||||
callback order, serialization behavior, and bounded stop expectations.
|
||||
- Do not introduce mechanism-specific aliases for `CoreRuntime` or mistake the semantic runtime contract for an
|
||||
operating-system process.
|
||||
- Serialization uses the shared `Furious.Models` encoders. Preserve supported dict subclasses such as `CoreConfiguration`;
|
||||
return/raise behavior must be documented and failures must retain useful diagnostics.
|
||||
- Storage contracts intentionally expose live mutable collections. State that explicitly—do not label them copies—and
|
||||
keep persistence/ordering semantics in concrete repositories.
|
||||
- Editor bindings translate between widgets and configuration but do not decide process/runtime policy.
|
||||
|
||||
## Verification
|
||||
|
||||
- Contract tests cover representative implementations, serialization failures, lifecycle/error behavior, mutable-storage
|
||||
semantics, and import independence.
|
||||
@@ -0,0 +1,20 @@
|
||||
# Model guidance
|
||||
|
||||
- Models are core-neutral Python data and transformations. Do not import Qt, application globals, controllers,
|
||||
repositories, services, or concrete backend plugins.
|
||||
- Preserve meaningful user configuration and unknown metadata fields across load/save/copy. Promote legacy fields
|
||||
through explicit, backward-compatible migrations without ambiguous duplicates.
|
||||
- `ServerProfile` separates connection data from metadata. Stable profile IDs, subscription ownership/key fields,
|
||||
display metadata, and connection fingerprints each have distinct semantics; do not substitute row position or display
|
||||
text for identity.
|
||||
- Fingerprints must be deterministic for supported JSON-compatible connection documents. If compatibility requires a
|
||||
fallback, make its stability/diagnostics explicit rather than silently changing identity across runs.
|
||||
- Encoders are the canonical JSON/ujson boundary. Preserve supported mappings/dict subclasses and surface useful failure
|
||||
context at the caller boundary.
|
||||
- `toURI()` dispatch belongs to plugin protocol capabilities; model methods may remain compatibility shims but must not
|
||||
grow new protocol-specific branches.
|
||||
|
||||
## Verification
|
||||
|
||||
- Test legacy/current mappings, unknown-field round trips, copies, deterministic identity, subscription migration,
|
||||
malformed serialization, and plugin-based export.
|
||||
+21
-20
@@ -1,24 +1,25 @@
|
||||
# Plugin architecture guidance
|
||||
|
||||
These rules apply to plugin APIs, registries, discovery, and capability dispatch.
|
||||
- `Plugins.API` defines stable capability contracts; `Registry` owns registration, selection, materialization,
|
||||
initialization, rollback, and reverse-order shutdown.
|
||||
- Use `CoreRuntimeFactory`, `CoreRuntimeRequest`, and `CoreRuntimeLaunch` consistently across capabilities, registry
|
||||
dispatch, statistics providers, and tests.
|
||||
- Plugins contribute factories, handlers, descriptors, immutable metadata, and service providers—not live transient
|
||||
widgets, active core instances, or controller state.
|
||||
- Protocol parse/export/editor, backend runtime, routing/TUN, statistics, subscription decoding, and navigation behavior
|
||||
belongs behind capabilities. Shared code must not add core-name conditionals when capability dispatch can express the
|
||||
policy.
|
||||
- Registration is deterministic and validates every capability family through focused validators before committing
|
||||
any index changes. A plugin failure is isolated, logged with plugin/capability context, and does not corrupt already
|
||||
registered providers.
|
||||
- Initialization is transactional: partially initialized plugins are rolled back; shutdown is reverse-order and
|
||||
idempotent.
|
||||
- Keep discovery imports literal and side-effect-light for source and Nuitka builds. Avoid circular dependencies from
|
||||
API/model layers into concrete plugins.
|
||||
- UI factories create fresh owned widgets. Invalid QObject results are explicitly destroyed; registries never retain
|
||||
rejected objects.
|
||||
|
||||
## Capability model
|
||||
## Verification
|
||||
|
||||
- Plugins declare metadata and stable capability objects. Registries index protocol handlers, editor providers, kernel factories, traffic providers, settings/page providers, and subscription decoders by stable IDs.
|
||||
- Register classes/factories/descriptors and immutable metadata, not transient editors, dialogs, menus, or pages. A provider may create UI on demand, with ownership left to the UI caller.
|
||||
- Put protocol/core behavior behind the closest capability. Shared UI/services query the registry rather than branching on protocol names or importing official backend internals.
|
||||
- Keep headless discovery free of eager Qt editor/window imports. Use literal lazy imports in editor factories so static packagers still see every dependency.
|
||||
|
||||
## Registry lifecycle and compatibility
|
||||
|
||||
- Validate all IDs, schemes, configuration types, kernel types, and duplicates before committing registration. A failed registration must roll back every index and initialized resource.
|
||||
- The registry owns plugin initialization and shuts plugins down once in reverse registration order. Plugin shutdown must tolerate partial initialization.
|
||||
- Avoid package-level import cycles: API/model layers stay lower-level; UI-specific imports occur only when a presentation capability is invoked.
|
||||
- Subscription decoders return data/configuration, never executable or live UI/runtime objects. Keep untrusted subscription payloads outside executable-core capabilities.
|
||||
|
||||
## Code review rules
|
||||
|
||||
- Flag live transient `QObject` instances stored in a plugin/capability registry.
|
||||
- Flag new global protocol conditionals or direct official-plugin imports from shared services/UI.
|
||||
- Flag dynamic string imports that Nuitka cannot discover when literal lazy factories are practical.
|
||||
- Flag partially registered plugins after validation/initialization failure or non-idempotent shutdown.
|
||||
- Test order, duplicate/invalid registration, dynamic dispatch, rollback, shutdown, compiled discovery, and factories
|
||||
returning invalid objects.
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# Qt foundation guidance
|
||||
|
||||
Use the `manage-qt-pyside6-lifetimes` skill for any Qt ownership or lifecycle change.
|
||||
|
||||
## Public UI primitives
|
||||
|
||||
- `Furious.Qt` is the canonical Fluent/theme/translation-aware UI surface. Extend/reuse `AppQ*` controls instead of
|
||||
styling raw Qt controls at call sites.
|
||||
- Construction-time source text should be retained by the control for retranslation. Do not duplicate manual
|
||||
`retranslate()` code where an `AppQ*` widget/action/menu already supports it.
|
||||
- Preserve public exports and wildcard-import compatibility carefully; keep optional/heavy facilities lazily imported
|
||||
where practical.
|
||||
- `AppStyleSheet` remains the sole public stylesheet authority. Internal `StyleSheets` modules are data-oriented QSS
|
||||
fragments that consume the centralized semantic palette; application consumers must not import fragments directly.
|
||||
|
||||
## Ownership and destruction
|
||||
|
||||
- `AppQDialog` provides an asynchronous open-dialog registry. `AppQMessageBox` has an additional registry cleanup layer;
|
||||
it is redundant but harmless. Keep both registries balanced if either implementation changes.
|
||||
- `AppQTransientDialog` is delete-on-close. Connect completion before `open()` and never access it after destruction.
|
||||
Reusable dialogs/windows instead need a durable owner and must not be delete-on-close.
|
||||
- `AppQAction.callback` is a deliberate strong reference; owner scope must be no longer than the callback receiver.
|
||||
Application-lifetime actions cannot capture transient bound methods.
|
||||
- Parent child widgets/models/delegates/timers where their lifetimes match. Explicitly stop/disconnect timers, remove
|
||||
mismatched event filters, abort/delete network replies, and clear references when wrappers can outlive C++ objects.
|
||||
- Do not cache QObject instances or instance-bound methods in global/unbounded caches. Weak callbacks must not close
|
||||
over their target.
|
||||
|
||||
## Threading and event loops
|
||||
|
||||
- Only the GUI thread mutates widgets. Workers return immutable/result data through queued signals or established
|
||||
managers.
|
||||
- Never sleep or perform unbounded host/network/process work in a slot. Timers and debounce/coalescing must have one
|
||||
owner and must not multiply across show/hide cycles.
|
||||
- `exec()` is reserved for genuinely synchronous control flow; prefer managed `open()` when continuation logic can live
|
||||
in `finished` callbacks.
|
||||
|
||||
## Network replies and presentation
|
||||
|
||||
- Give each reply one manager/context owner, reject stale generations, handle success/error/abort exactly once, and call
|
||||
`deleteLater()` on every terminal path. Do not attach ad-hoc application attributes to third-party Qt objects when a
|
||||
manager mapping suffices.
|
||||
- Preserve keyboard, focus, shortcuts, accessibility, light/dark theme, layout responsiveness, and translated-text
|
||||
growth.
|
||||
|
||||
## Verification
|
||||
|
||||
- Run focused UI behavior and lifetime tests. Repeated open/close/show/refresh cycles must stabilize object, signal,
|
||||
timer, reply, handle, and callback counts.
|
||||
@@ -1,24 +1,19 @@
|
||||
# Repository and persistence guidance
|
||||
# Repository guidance
|
||||
|
||||
These rules apply to storage adapters and persisted application data.
|
||||
- Repositories are the only persistence authority for profiles, subscriptions, routing, and TUN settings. Keep
|
||||
Qt/UI/workflow concerns out of repository implementations.
|
||||
- Preserve stable IDs, ordering, unknown compatible fields, legacy migrations, and subscription ownership. Display names
|
||||
and row indexes are not identities.
|
||||
- Subscription synchronization may update only profiles explicitly managed by that subscription and identified by stable
|
||||
profile keys. Never delete user-created or another subscription's data.
|
||||
- Public collection access currently returns live mutable application-owned collections for compatibility. Document this
|
||||
honestly and avoid introducing a second cached copy; new mutations should flow through named repository operations
|
||||
when practical.
|
||||
- Load failures retain recoverable data where possible and log actionable context. Never silently replace malformed
|
||||
explicit configuration with unrelated defaults when doing so loses user intent.
|
||||
- Singleton repository caches are application-lifetime finite objects and must be reset/sandboxed in tests.
|
||||
|
||||
## Persistence contracts
|
||||
## Verification
|
||||
|
||||
- Repository objects are the persistence boundary. UI/controllers/services use repository APIs rather than writing their own `QSettings` keys for domain records.
|
||||
- Preserve stable identities: profile IDs identify profiles, subscription group IDs identify sources, and subscription profile keys link upstream members to their owner. Do not match ownership by display name, URL, or table position.
|
||||
- Subscription synchronization is group scoped. Updating/removing one group must not affect manual profiles or profiles owned by another group; retained profiles keep local metadata and stable IDs.
|
||||
- Migrations must be conservative and non-destructive. Keep legacy keys registered/read when required, normalize incompatible metadata safely, and preserve unrelated/unknown data where the current format supports it.
|
||||
- Copies intended as manual profiles receive a new identity and clear subscription ownership. Routine edits must not accidentally detach or reassign ownership.
|
||||
- Application-lifetime cached repositories are intentional; do not place transient UI or short-lived runtime resources in them.
|
||||
|
||||
## Required verification
|
||||
|
||||
- Run repository/model tests with the isolated temporary `QSettings` namespace.
|
||||
- Add migration tests for legacy input and round-trip tests for current data before changing serialized shapes.
|
||||
- For subscription changes, test add/update/remove, stable order/identity, other-group isolation, and manual-profile preservation.
|
||||
|
||||
## Code review rules
|
||||
|
||||
- Flag persistence writes outside the repository/settings abstraction for domain data.
|
||||
- Flag subscription reconciliation based only on names, URLs, or row indices.
|
||||
- Flag migrations that delete unrelated data or overwrite a legacy value before successful conversion.
|
||||
- Test old/current schemas, unknown fields, ordering, stable identity, subscription isolation, malformed persisted data,
|
||||
round trips, and isolated temporary settings.
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# Service guidance
|
||||
|
||||
- Services own workflows and temporary resources; controllers own shared application state. Services may use Qt for
|
||||
asynchronous I/O/signals but must not own pages or encode presentation policy.
|
||||
- Inject repositories, runtimes, clients, clocks, and callbacks where practical. One service owns each worker, reply,
|
||||
timer, executor, process, and cache; cleanup is bounded and idempotent.
|
||||
|
||||
## Connection and configuration
|
||||
|
||||
- `ConnectionManager` coordinates plugin capabilities, core runtimes, proxy/TUN/routing, and rollback. Its `runtimes`
|
||||
collection contains semantic runtime owners, not necessarily operating-system processes. It consumes runtime copies
|
||||
and never mutates persisted profiles.
|
||||
- Preserve the backend native-TUN decision reported by capabilities. Start application tun2socks only when no native TUN
|
||||
is handled; proxy-only operations strip TUN explicitly.
|
||||
- Connection startup is one private staged attempt over a runtime configuration copy. Track each exact runtime as soon
|
||||
as it is acquired; failures roll back only that attempt in reverse order, and commit transfers ownership to the
|
||||
manager's normal lifecycle.
|
||||
- Startup either reaches a valid running state or rolls back every process/host mutation with an actionable error.
|
||||
Shutdown and unexpected-exit paths are bounded and safe to repeat.
|
||||
|
||||
## Async, network, and background work
|
||||
|
||||
- Each asynchronous request has an explicit generation/context. Partial results may publish independently, while
|
||||
stale/aborted replies are ignored and deleted exactly once.
|
||||
- Timeouts apply to network, DNS, executor, process, and host work. Executor callbacks must not retain a manager forever
|
||||
after shutdown; GUI updates cross via signals.
|
||||
- Logging and metrics collect while pages are hidden but avoid hidden-page rendering. Raw time-series samples are
|
||||
immutable; stable timestamp buckets are derived display data.
|
||||
- Log retention is owned by `LogManager`, not a text document. Category pruning/reset notifications must keep lazy UI
|
||||
sequence state valid.
|
||||
- Endpoint inspection must enforce the active proxy path, reject stale connection results, use neutral request metadata,
|
||||
and disclose actual external providers without sending profile secrets.
|
||||
- `SubscriptionManager` owns download, decoding, filtering, reconciliation, persistence effects, stale-request
|
||||
rejection, and stable-ID auto-update timers. Subscription views invoke commands and render semantic results; they do
|
||||
not own this workflow. Remote data is untrusted.
|
||||
|
||||
## Code review rules
|
||||
|
||||
- Flag widgets retained by services, unbounded executor/network/process work, callbacks that capture service owners
|
||||
after shutdown, UI-only cache invalidation, and swallowed provider failures.
|
||||
- Test success, partial/stale/timeout/cancel/failure, hidden-page behavior, repeated cleanup, and worker/reply lifetime
|
||||
with fakes—never real host mutation.
|
||||
@@ -0,0 +1,16 @@
|
||||
# Utility process guidance
|
||||
|
||||
- This package contains the outer application-process wrapper, not general miscellaneous helpers. Keep its surface small
|
||||
and avoid adding business/UI policy that belongs in application, controller, or service layers.
|
||||
- `AppMainProcess` owns its exact child/application runner, signal handlers, exit-code translation, and crash-log
|
||||
attempt. Signal/exception paths must tolerate partial application startup.
|
||||
- Crash reporting is best effort but must not hide the original exception; avoid logging secrets from application
|
||||
history and bound all cleanup before exit.
|
||||
- Do not introduce process-name cleanup or unmanaged `multiprocessing.Manager`/thread resources. Explicitly shut down
|
||||
auxiliary process resources when no longer needed.
|
||||
- Preserve semantic `ApplicationRunner.ExitCode` values and cross-platform spawn behavior.
|
||||
|
||||
## Verification
|
||||
|
||||
- Test normal exit, assertion/unknown exception mapping, crash-log write failure, signals before/after app creation, and
|
||||
no orphaned manager/child resources.
|
||||
@@ -0,0 +1,23 @@
|
||||
# Reusable widget guidance
|
||||
|
||||
- Widgets are reusable presentation components below full pages/windows. Prefer controller/service/repository
|
||||
dependencies passed explicitly; do not add new `AppMainWindow()` reach-through or duplicate application state.
|
||||
- Subscription views delegate download, decoding, reconciliation, persistence effects, and recurring scheduling to
|
||||
`SubscriptionManager`; keep view code limited to user intent, presentation, and repository-backed table refresh.
|
||||
- Models, delegates, menus, actions, spinners, animations, timers, and network-backed helpers need explicit owners.
|
||||
Persistent page widgets are constructed once; refresh/show cycles toggle state rather than recreate/connect
|
||||
indefinitely.
|
||||
- Table selection operates on stable repository IDs, not visual rows after sort/filter. Keep model begin/end
|
||||
notifications, timer collections, and repository order synchronized.
|
||||
- Use `AppQ*` controls and responsive layouts. Preserve translated-text growth, shortcuts, focus, accessibility, theme
|
||||
changes, high-DPI rendering, and hidden-page lazy behavior.
|
||||
- Expensive parsing, syntax highlighting, map/network work, metrics aggregation, and subscription synchronization must
|
||||
not freeze the GUI. Publish results through owned signals and reject stale generations.
|
||||
- Transient editors/progress dialogs use managed `open()` lifetime; reusable top-level windows retain one explicit
|
||||
owner.
|
||||
|
||||
## Code review rules
|
||||
|
||||
- Flag direct global/window reach-through, duplicated persistence logic, row-index identity, repeated signal/timer
|
||||
creation, hidden-page rendering, and callbacks retaining closed widgets.
|
||||
- Run relevant behavior plus Qt lifetime tests for repeated refresh/show/open/close cycles.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Window and page guidance
|
||||
|
||||
- `MainWindow` owns long-lived built-in pages, navigation, page-level managers, and compatibility aliases. Pages remain
|
||||
stable for the window lifetime; plugin pages are owned by navigation plus `PluginNavigationManager`.
|
||||
- Pages and dialogs adapt controllers/services/repositories to user interaction. Do not create a competing state
|
||||
authority; prefer controller/service APIs over new cross-page reach-through.
|
||||
- Long-lived pages create controls, timers, and signal connections once. Show/hide activates lazy rendering or refresh
|
||||
intent without multiplying objects or background work.
|
||||
- One-shot editors/prompts inherit `AppQTransientDialog`/`AppQMessageBox`, connect `finished` before `open()`, and are
|
||||
not retained afterward. Reusable `TextEditorWindow` keeps an explicit owner, survives normal close/show, and is
|
||||
destroyed only by that owner.
|
||||
- Close buttons route through the normal `close()`/`closeEvent` path so save/discard/cancel and cleanup remain
|
||||
canonical. Base event handlers are called unless intentionally documented.
|
||||
- Keep file/network/core work bounded and off the GUI thread when it can block. Present structured failures without
|
||||
swallowing them or exposing secrets.
|
||||
- Use Fluent `AppQ*` controls, normal layouts, translation-aware construction, and theme callbacks. Preserve shortcuts,
|
||||
default/escape actions, focus, resizing, navigation overlay behavior, and light/dark presentation.
|
||||
|
||||
## Code review rules
|
||||
|
||||
- Flag local top-level windows shown without a durable owner, transient dialogs cached by pages/controllers, repeated
|
||||
show-time connections, direct worker-thread UI mutation, and manual translation already handled by controls.
|
||||
- Test navigation/page restoration, async dialog continuations, unsaved-close flow, hidden-page behavior, and repeated
|
||||
lifecycle stability.
|
||||
@@ -0,0 +1,16 @@
|
||||
# Icon asset guidance
|
||||
|
||||
- This tree contains source assets consumed by the Qt resource workflow. Reuse an existing semantic icon before adding a
|
||||
near-duplicate.
|
||||
- Keep SVGs vector, compact, theme-compatible, and free of embedded raster data, scripts, remote resources, editor
|
||||
metadata, or hard-coded backgrounds.
|
||||
- Follow the established monochrome/current-color convention for UI icons; add explicit light/dark variants only when
|
||||
the design cannot be expressed through tinting.
|
||||
- Preserve upstream license/attribution requirements and stable resource paths. Renaming/removing an asset requires
|
||||
updating all references and regenerating `Furious/Frozenlib/AppResources.py` through the existing workflow.
|
||||
- Do not hand-edit the generated resource module.
|
||||
|
||||
## Verification
|
||||
|
||||
- Search all references, regenerate resources, test light/dark and high-DPI rendering, and visually check icon
|
||||
size/alignment in the target Fluent control.
|
||||
+41
-15
@@ -1,25 +1,51 @@
|
||||
# Furious test guidance
|
||||
|
||||
These rules apply to the isolated `unittest` suite and refine repository guidance.
|
||||
|
||||
## Isolation
|
||||
|
||||
- Tests must never affect an already-running Furious instance or production user data. Set `QT_QPA_PLATFORM=offscreen` before importing Qt and use helpers in `tests/support.py`.
|
||||
- Route `QSettings` to the temporary INI sandbox. Never read/write the production organization/application namespace.
|
||||
- Do not change the real system proxy, routing table, TUN devices, startup registration, tray, or network interfaces. Patch host-mutation APIs and inject fake controllers/managers.
|
||||
- Do not discover, signal, terminate, or clean up processes by name. Own exact subprocess handles/PIDs and threads, use bounded waits, and reap only resources the test created.
|
||||
- Tests must not require external network access or installed proxy-core executables unless explicitly marked/documented as an optional smoke procedure.
|
||||
- Tests must never affect a running Furious instance or production data. Set `QT_QPA_PLATFORM=offscreen` before Qt
|
||||
import and use `tests/support.py` for one small application and temporary INI-backed settings.
|
||||
- Never mutate real proxy, DNS, routing, TUN, startup registration, tray, network interfaces, or external services.
|
||||
Patch host/network APIs and inject fake controllers, runtimes, repositories, clocks, and clients.
|
||||
- Own exact subprocess handles/PIDs and threads. Use bounded waits and clean up only resources the test created; never
|
||||
discover or terminate by process name.
|
||||
- Normal tests require no external network or installed proxy core. Keep packaged/manual smoke procedures explicit and
|
||||
disposable.
|
||||
|
||||
## Test design
|
||||
|
||||
- Keep deterministic logic/behavior tests in the normal tier. Put repeated live-object/native-handle/RSS checks in the explicit stress tier.
|
||||
- Test persisted input and runtime copies separately for configuration preparation. A helper must not make normal connection and proxy-only behavior accidentally identical.
|
||||
- Qt lifetime tests use real close/deferred-delete paths, weak references, and live-object counts. `gc.collect()` is allowed only at diagnostic batch boundaries, never as production behavior or once-per-operation masking.
|
||||
- Threshold increases are not a leak fix. Investigate linear object/handle growth and distinguish it from allocator/native high-water caching.
|
||||
- Update `tests/README.md` when adding a test module or changing tiers/required environment setup. Commands in documentation use the active `python` environment.
|
||||
- Test public behavior and architectural contracts, not implementation trivia. Cover success, validation failure,
|
||||
timeout, cancel, partial/stale result, cleanup, and backward-compatible persisted input.
|
||||
- Use canonical `CoreRuntime` vocabulary in runtime factories, registry fixtures, and traffic-statistics providers.
|
||||
- Separate persisted configuration from runtime-copy assertions. Normal connection, generated native TUN, preserved user
|
||||
TUN, and proxy-only stripping must not share a helper that erases their differences.
|
||||
- Keep deterministic logic/UI behavior in the normal tier. Put repeated live-object, native-handle, thread, subprocess,
|
||||
and RSS trends in explicit stress tiers.
|
||||
- Qt lifetime tests use real close/deferred-delete paths, weak references, destroyed signals, and live counts.
|
||||
`gc.collect()` is diagnostic at batch boundaries only; threshold increases or production collection are not leak
|
||||
fixes.
|
||||
- Avoid timing-only assertions. Drive events deterministically and assert final ownership/state plus absence of
|
||||
duplicate connections/timers/replies.
|
||||
- Update `tests/README.md` when modules, tiers, or environment requirements change. Documentation commands use the
|
||||
active `python` environment.
|
||||
|
||||
## Real lifecycle and process-boundary regressions
|
||||
|
||||
- Apply the highest-fidelity safe test boundary throughout the suite. Unit tests remain appropriate for deterministic
|
||||
logic, but bugs involving Qt event loops, native callbacks, interpreter finalization, subprocess teardown, or wrapper
|
||||
destruction need a focused integration test that exercises the real boundary that failed.
|
||||
- For application-lifecycle regressions, start a clean child Python process, force `QT_QPA_PLATFORM=offscreen` before
|
||||
importing Qt, construct the smallest real `QApplication`/`DesktopApplication` and real Qt window needed, run the real
|
||||
event loop, request shutdown through the public path, and assert the child process exits normally. Repeat the cycle
|
||||
when the defect is intermittent.
|
||||
- A lifecycle child must be hermetic: bypass single-instance discovery and IPC, use temporary settings and application
|
||||
identity where relevant, disable tray and startup restoration, mock all host/network integrations, and never attach to,
|
||||
signal, inspect, or change a potentially running Furious instance.
|
||||
- Child-process tests own only the windows, threads, handles, and processes they create. Give every wait and child a
|
||||
bounded timeout, capture diagnostics, and terminate only that exact child on timeout. Never use process-name cleanup.
|
||||
- Visible diagnostic windows are for an explicit manual smoke procedure only. Automated tests always use the offscreen
|
||||
platform so they cannot flash, steal focus, or interact with the desktop session.
|
||||
|
||||
## Code review rules
|
||||
|
||||
- Flag any test that can touch production `QSettings` or host networking.
|
||||
- Flag broad process cleanup, unbounded waits, timing-only assertions, or dependence on an existing GUI session.
|
||||
- Flag tests that assert only stored configuration when the bug concerns the runtime document submitted to a core.
|
||||
- Flag production settings/host mutation, broad process cleanup, unbounded waits, external network dependence, shared
|
||||
mutable fixtures, and tests that only check storage when runtime output is the contract.
|
||||
|
||||
Reference in New Issue
Block a user