From c2f9d8efc93218d42dc064c572e9ccbbcc050abc Mon Sep 17 00:00:00 2001 From: Loren Eteval Date: Wed, 9 Sep 2026 14:20:16 +0800 Subject: [PATCH] Refine repository guidance Signed-off-by: Loren Eteval --- .github/AGENTS.md | 6 ++++-- AGENTS.md | 7 +++++-- Furious/AGENTS.md | 3 +++ Furious/Actions/AGENTS.md | 11 +++++++---- Furious/Application/AGENTS.md | 11 +++++++---- Furious/Backends/AGENTS.md | 5 +++-- Furious/Backends/ExternalCore/AGENTS.md | 6 ++++-- Furious/Backends/Hysteria1/AGENTS.md | 8 +++++--- Furious/Backends/Hysteria2/AGENTS.md | 7 ++++--- Furious/Backends/Xray/AGENTS.md | 7 ++++++- Furious/Controllers/AGENTS.md | 5 +++-- Furious/Core/AGENTS.md | 11 +++++++---- Furious/Data/AGENTS.md | 6 ++++-- Furious/Extensions/AGENTS.md | 8 +++++--- Furious/Externals/AGENTS.md | 2 ++ Furious/Frozenlib/AGENTS.md | 4 +++- Furious/Interface/AGENTS.md | 4 +++- Furious/Models/AGENTS.md | 3 ++- Furious/Plugins/AGENTS.md | 7 +++++-- Furious/Qt/AGENTS.md | 7 +++++-- Furious/Repository/AGENTS.md | 4 +++- Furious/Service/AGENTS.md | 10 ++++++++-- Furious/Utility/AGENTS.md | 7 ++++--- Furious/Widget/AGENTS.md | 6 ++++-- Furious/Window/AGENTS.md | 5 +++-- Icons/AGENTS.md | 4 +++- tests/AGENTS.md | 10 ++++++++-- 27 files changed, 120 insertions(+), 54 deletions(-) diff --git a/.github/AGENTS.md b/.github/AGENTS.md index 8abaeb5..467aa60 100644 --- a/.github/AGENTS.md +++ b/.github/AGENTS.md @@ -19,8 +19,10 @@ exceptions; it does not define the source test suite or imply that every package ## Workflow engineering - Keep packaging declarations synchronized with `Deploy.py`, `pyproject.toml`, `setup.py`, and `requirements.txt`. - Default-to-newest dependencies still need deterministic assertions at ABI/feature boundaries; pin or checksum external - build tools where the workflow establishes a supply-chain boundary. + The Python floor advertised by package metadata is a separate claim from the interpreter versions exercised by CI; + newer matrix rows cannot prove that floor. Likewise, successful Qt imports do not prove event-loop or binding-call + compatibility. Default-to-newest dependencies/assets still need recorded provenance and deterministic assertions + at ABI/feature boundaries; pin or checksum external build tools where the workflow establishes that boundary. - The workflow default shell is Bash, including Windows jobs. Select PowerShell explicitly for native Windows paths, process APIs, or PowerShell syntax, and keep OS/architecture conditions on the step that owns the difference. - Flatpak checks run inside the installed sandbox, inspect the application's required native closure rather than every diff --git a/AGENTS.md b/AGENTS.md index 85bf289..dbcbe38 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -95,6 +95,8 @@ - Match evidence to the contract: round trips/migrations for models and repositories; exact transitions/signal counts for controllers; stale/cancel/rollback/cleanup paths for services; partial startup and resource reaping for runtimes; mocked OS branches for host helpers; import/discovery and packaged checks for compiler-sensitive changes. + Test a resource that refuses cleanup as well as one that exits normally. A terminal flag, cleared reference, or + 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. @@ -111,8 +113,9 @@ current architecture, tests, verified runtime behavior, explicit design, or an intentional refactor completed in the same change. - Put a rule at the narrowest scope where it helps future decisions; let child guides specialize rather than repeat - parents. Remove obsolete content inside files, distinguish preferred architecture from compatibility paths, and - preserve every established file path while doing so. + parents. For each local rule, identify the decision it protects and the implementation or test that could disprove + it. Remove obsolete content inside files, distinguish preferred architecture from compatibility paths, and preserve + every established file path while doing so. A guidance audit must not turn an observed defect into a required design. - After significant architectural work, re-read the applicable hierarchy as a fresh agent: can it identify the owner, invariant, failure boundary, and relevant tests without relying on conversation history? Challenge rules likely to become stale, circular references, and wording that freezes incidental structure. diff --git a/Furious/AGENTS.md b/Furious/AGENTS.md index fc99f0c..ee70d10 100644 --- a/Furious/AGENTS.md +++ b/Furious/AGENTS.md @@ -49,6 +49,9 @@ domain, persistence, orchestration, platform integration, and presentation; nest every asynchronous workflow. Page visibility may control rendering, never ownership of collection or draining. - Preserve unknown/forward-compatible fields through model, repository, backend editor, and serialization changes. Compatibility normalization must be narrow, intentional, and tested separately from observational loading. + A dict-like profile exposes its connection document through the mapping interface, not its complete persistence + record. Choose the explicit profile, metadata, or connection representation required by each boundary; generic + mapping conversion is not a profile backup. - Import, clipboard, share-link, file, and QR paths reuse the owning plugin codecs and validation. QR is a presentation transport, not a second protocol parser; construct a complete neutral result before repository mutation and never log the secret-bearing payload. diff --git a/Furious/Actions/AGENTS.md b/Furious/Actions/AGENTS.md index 9cec579..2de2b5e 100644 --- a/Furious/Actions/AGENTS.md +++ b/Furious/Actions/AGENTS.md @@ -8,9 +8,10 @@ presentation without becoming a workflow authority. - Actions adapt one user command to presentation. Resolve live controller/repository state when triggered, delegate the operation to its owner, and render the result; an action is not a second connection, routing, subscription, or persistence authority. -- Prefer one shared `QAction` for one semantic command across menus and buttons so checked/enabled state, shortcut, - callback, and translation cannot diverge. A host widget may narrow shortcut context; do not make menu shortcuts - application-wide when focused editors or other controls own the same keys. +- Share a `QAction` across menus/buttons when command target, owner lifetime, and shortcut scope are the same. + Distinct window/tray contexts may need separate actions that observe the same controller; do not force one global + action across incompatible lifetimes. Keep checked/enabled state and translation consistent, and do not make menu + shortcuts application-wide when focused editors or other controls own the same keys. - Routing and connection actions render the shared controllers. Rebuilding a dynamic menu releases the old actions, action group, and callbacks before publishing the new snapshot; user-defined labels remain untranslated. - Existing import actions still combine capture/file/clipboard presentation with incremental repository insertion. Treat @@ -25,7 +26,9 @@ presentation without becoming a workflow authority. diagnostic excerpts and never log or echo a complete secret-bearing payload merely to explain a parse failure. - Screen capture and QR decoding currently run synchronously; batching the resulting imports does not make capture interruptible. If moved to workers, transfer data through an owned GUI-thread continuation without retaining - transient windows. QR export generation belongs to its result window, not a parallel action-owned exporter. + transient windows. Each screen-capture action owns a separate native capture handle, including separate tray/page + instances; type-deduplicated cleanup must not leave one open. QR export generation belongs to its result window, + not a parallel action-owned exporter. - Small profile imports use the direct bulk path; large imports yield between bounded batches. Preserve captured input and one operation context until completion/cancellation, reject deferred calls after teardown, and retain already committed batches when cancellation stops later work. A parser call itself is not preempted by a batch. diff --git a/Furious/Application/AGENTS.md b/Furious/Application/AGENTS.md index fb85e0c..9f0c8e2 100644 --- a/Furious/Application/AGENTS.md +++ b/Furious/Application/AGENTS.md @@ -5,16 +5,19 @@ child-process supervisor and the inner application event loop. - `Furious.__main__` and `AppMainProcess` own the outer process/crash boundary; `DesktopApplication` owns the inner Qt composition. Keep those responsibilities separate and preserve semantic exit codes and original failure context. -- Startup stages begin after singleton election. Plugins are available before repository restoration - interprets persisted profiles; controllers and presentation consume those initialized owners. Register cleanup as - each acquisition succeeds, and preserve these dependencies when changing stage order. +- Plugin, storage, and UI initialization follows singleton election; the Qt application and its initial resource + 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, failure-isolating, idempotent cleanup path. `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 owners remain valid; scheduling `deleteLater()` is not evidence that workers or native resources have finished. - Review cooperative pool drains separately from the cleanup stack's ordering guarantees. + Review cooperative pool drains separately from the cleanup stack's ordering guarantees. The application pool's + timed wait logs unfinished work, whereas subscription preparation waits synchronously after its diagnostic timeout. + Neither policy can be inferred from reverse cleanup order or from the name of a shutdown method. - Singleton election serializes cooperating candidates, re-probes after waiting, recovers only a confirmed stale endpoint, and fails closed when ownership is uncertain, including privilege handoff. A successful Windows local-server listen alone does not establish exclusivity; command delivery and endpoint ownership are separate diff --git a/Furious/Backends/AGENTS.md b/Furious/Backends/AGENTS.md index f64c424..e781f5c 100644 --- a/Furious/Backends/AGENTS.md +++ b/Furious/Backends/AGENTS.md @@ -32,8 +32,9 @@ scope adds rules shared by all bundled proxy backends without making the richest must be bounded, idempotent, and safe after partial acquisition. Report incomplete reaping explicitly; reaching a deadline or changing logical execution state does not prove that native resources have exited. - Runtime factories follow the current plugin contract: fully prepare and return one owned launch whose zero-argument - start is separate from readiness observation. Do not hide readiness waits, Boolean success channels, or controller - policy inside a backend runtime. + start is separate from readiness observation. If preparation fails before a valid launch transfers to the caller, + the factory must release its own partial resources; the caller cannot dispose a runtime it never received. Do not + hide readiness waits, Boolean success channels, or controller policy inside a backend runtime. ## Backend scopes diff --git a/Furious/Backends/ExternalCore/AGENTS.md b/Furious/Backends/ExternalCore/AGENTS.md index 28e5df1..743cf2c 100644 --- a/Furious/Backends/ExternalCore/AGENTS.md +++ b/Furious/Backends/ExternalCore/AGENTS.md @@ -34,5 +34,7 @@ the intentionally different direct-subprocess scope for user-selected executable immediate-exit failure, complete and partial output, exact callback/reader/watcher cleanup, repeated stop/dispose, TUN opt-in and remote-address handling, subscription rejection, and transient editor destruction. Update this guide when the process contract evolves rather than preserving today’s implementation mechanically. Start with - `tests/test_external_core.py` and `tests/test_backend_editor_contract.py`. A failed final reap is a cleanup - failure to report; elapsed stop deadlines alone do not prove that the OS process or all descendants have exited. + `tests/test_external_core.py` and `tests/test_backend_editor_contract.py`. Exercise a child that remains alive + after escalation and readers/watchers that outlast their joins. A failed final reap is a cleanup failure to report; + clearing the runtime's process/thread references must not be used as evidence that those resources exited. + Direct-child exit also does not prove that descendants closed inherited pipes. diff --git a/Furious/Backends/Hysteria1/AGENTS.md b/Furious/Backends/Hysteria1/AGENTS.md index 8684971..391f08c 100644 --- a/Furious/Backends/Hysteria1/AGENTS.md +++ b/Furious/Backends/Hysteria1/AGENTS.md @@ -13,9 +13,11 @@ preserve Hysteria 1's legacy flat schema and lifecycle without importing assumpt - 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 backend’s policy. -- Routing ACL/MMDB launch inputs remain distinct from the stored connection JSON. A prepared runtime advertises its - local HTTP readiness endpoint separately from child liveness. The built-in factory has no statistics provider; - shared UI must handle that absence instead of treating it as a failed connection. +- 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 + preparation responsiveness review. A prepared runtime advertises its local HTTP readiness endpoint separately + from child liveness. The built-in factory has no statistics provider; shared UI handles that absence. - Verify legacy/current URI and mapping compatibility, unknown/tolerated values, stored-copy isolation, MMDB/ACL absence or malformed paths, asynchronous readiness and rollback, core-exit translation, application-TUN policy, and repeated editor/runtime cleanup. Use `tests/test_hysteria1_protocol.py`, diff --git a/Furious/Backends/Hysteria2/AGENTS.md b/Furious/Backends/Hysteria2/AGENTS.md index b35c29c..acb47b0 100644 --- a/Furious/Backends/Hysteria2/AGENTS.md +++ b/Furious/Backends/Hysteria2/AGENTS.md @@ -17,9 +17,10 @@ Hysteria 2's nested upstream document, native-TUN capability, statistics, and ed - Managed native TUN replaces only the runtime copy’s `tun`. Disabled management preserves any explicit `tun`, including malformed data for the core to reject; only absence permits application tun2socks. Linux native TUN - requires the backend’s privilege and server-route-exclusion guarantees. Probe/download copies always remove native - TUN. Managed preparation currently resolves server addresses synchronously; do not describe the whole native-TUN - stage as event-driven merely because connection readiness is asynchronous. + requires the backend’s privilege and server-route-exclusion guarantees. The application's Linux privilege-helper + path does not grant an embedded native-TUN core the same privileges. Test these availability decisions separately. + Probe/download copies always remove native TUN. Managed preparation currently resolves server addresses + synchronously; do not describe the whole native-TUN stage as event-driven merely because readiness is asynchronous. - 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 diff --git a/Furious/Backends/Xray/AGENTS.md b/Furious/Backends/Xray/AGENTS.md index 1c37de5..c4dbe4c 100644 --- a/Furious/Backends/Xray/AGENTS.md +++ b/Furious/Backends/Xray/AGENTS.md @@ -28,7 +28,12 @@ full JSON preservation, routing/assets/statistics, and protocol/transport/TLS pr usable file. Distinguish this updater from `Deploy.py --download`, whose download/integrity behavior must be inspected separately; shared filenames do not make the two mechanisms equivalent. - Routing selection IDs, user routing documents, and translated built-in labels are different contracts. Preserve - custom document content and named-profile identity while composing runtime routing/API statistics. + custom document content and named-profile identity while composing runtime routing/API statistics. Trace the + selected repository routing document separately from the connection's own routing branch; neither may be mutated + as a side effect of preparing a launch. +- 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. - Verify full-document and URI preservation, aliases and unknown values, runtime-copy isolation for routing/log/TUN/tests, multiple TUN inbounds, asset integrity/failure, statistics and process cleanup, compiled-safe UI callbacks, and repeated editor/window destruction. Use `tests/test_xray_asset_download.py`, diff --git a/Furious/Controllers/AGENTS.md b/Furious/Controllers/AGENTS.md index a4fdf09..1f114f2 100644 --- a/Furious/Controllers/AGENTS.md +++ b/Furious/Controllers/AGENTS.md @@ -20,8 +20,9 @@ transitions. Services own execution resources; existing prompts are presentation are not generic connection errors. - `RoutingController` owns available capability options plus selected/persisted routing. Distinguish a newly selected repository profile from the active-profile reference and the independent runtime document; changes use - controlled reconnect, not mutation of the running document. User-defined routing labels are semantic data, not - translatable UI literals. + controlled reconnect, not mutation of the running document. Capability refresh prefers the active profile and + otherwise the repository's activated profile. Normalizing the displayed option does not itself persist a new + preference; explicit selection owns that mutation. User-defined routing labels are not translatable UI literals. - `SettingsController` is the shared policy path used by Home, Settings, tray, and platform integration. Startup registration persists only after host success; other preferences may apply immediately or on the next connection. Preserve each setting's actual application timing instead of imposing one transaction order on all preferences. diff --git a/Furious/Core/AGENTS.md b/Furious/Core/AGENTS.md index b67b998..7f5d862 100644 --- a/Furious/Core/AGENTS.md +++ b/Furious/Core/AGENTS.md @@ -11,10 +11,13 @@ This scope owns reusable embedded execution machinery and application tun2socks; - `CoreRuntime` execution state, typed terminal exit, and readiness are separate contracts. A process becoming alive is not proof that its proxy/TUN endpoint is ready, while a readiness timeout must not overwrite an already observed typed exit. -- A runtime owns and reaps its exact child, process handle, monitor/drain timers, queues, callbacks, and feeder resources. - Stop is bounded, escalates only that child when needed, closes handles, and is safe after partial start or repetition. -- Process-backed runtimes monitor and reap their own child, interpret a raw exit exactly once, and publish one typed exit - event. `isRunning()` is a passive execution-liveness query and must not consume or dispatch lifecycle events. +- 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. +- Process-backed runtimes own exit monitoring and interpretation: publish one typed terminal event per execution, + preserving the raw exit and whether stop was requested. `isRunning()` is a passive liveness query and must not + consume or dispatch lifecycle events. - Child targets never touch Qt widgets. Output transport is non-blocking and bounded in message size, pending volume, and per-turn drain work; draining continues independently of Log-page visibility and backs off only when idle. - Parentless timers are acceptable only with a durable runtime owner and explicit disposal. Leaving the manager pool diff --git a/Furious/Data/AGENTS.md b/Furious/Data/AGENTS.md index 860b24d..6cbcf84 100644 --- a/Furious/Data/AGENTS.md +++ b/Furious/Data/AGENTS.md @@ -5,8 +5,10 @@ application-data or settings directory. ## Boundary and provenance -- This directory ships application assets, not user state: Xray GeoIP/geosite data, Hysteria MMDB/ACL data, the local - MapLibre endpoint map, and the bundled font. Settings, subscriptions, caches, and temporary downloads belong elsewhere. +- This directory ships Xray GeoIP/geosite data, Hysteria MMDB/ACL data, the local MapLibre endpoint map, and the + bundled font. It is not a home for settings, subscriptions, or general caches. The Xray updater currently replaces + assets at the package-resolved data paths, so these files are not necessarily immutable at runtime. Review source, + installed, and packaged write permissions separately; an application refresh may appear as a source-tree change. - Preserve upstream licenses, provenance, binary/text formats, filenames, and paths consumed by constants, backends, tests, setuptools package data, and Nuitka. Do not incidentally reformat generated ACLs or replace binary assets. - Markdown files in this directory are repository metadata, not runtime data. Keep top-level and nested Markdown files diff --git a/Furious/Extensions/AGENTS.md b/Furious/Extensions/AGENTS.md index aaf00b7..08c8e90 100644 --- a/Furious/Extensions/AGENTS.md +++ b/Furious/Extensions/AGENTS.md @@ -17,9 +17,11 @@ host-shipped non-runtime plugins and must not gain private authority merely beca all shared parser state and caches, not merely absence of widgets in the immediate method. Worker preparation also requires the selected protocol handlers to opt in; a safe envelope decoder cannot authorize an unsafe downstream parser. Preserve the GUI compatibility fallback for unclassified capabilities. -- Decoder output is descriptive, not a repository transaction. It cannot assign live profile identity, mutate a - subscription group, cancel tests, reconnect, or publish UI state; those decisions remain at the import/manager commit - boundaries. +- Decoder output is descriptive, not a repository transaction. Supplied names and upstream IDs are input to profile + construction, not permission to overwrite local identity or grant remote ownership. It cannot mutate a group, + cancel tests, reconnect, or publish UI state; those decisions remain at the import/manager commit boundaries. + Test recognized-empty, wholly unsupported, and mixed-validity payloads separately so decoder matching is not + confused with successful profile import or authorization to clear an existing group. - Keep bundled registration deterministic, side-effect-light, and discoverable in source, wheel, and Nuitka builds. Test format selection/fallback, malformed and secret-bearing input, duplicate occurrence identity, unsupported subscription protocols, registration rollback, and absence of repository/UI mutation during decoding. Evolve this diff --git a/Furious/Externals/AGENTS.md b/Furious/Externals/AGENTS.md index 3aaf334..87ce317 100644 --- a/Furious/Externals/AGENTS.md +++ b/Furious/Externals/AGENTS.md @@ -14,6 +14,8 @@ human-reviewed translations. - Preserve existing translation-key and language-field order. The generator retains dictionary order rather than enforcing a universal sort; source traversal can affect newly discovered entries. Do not sort the catalog as cleanup. `source` contains deduplicated fully qualified modules and is rebuilt by extraction rather than manually curated. + Changing a source literal changes catalog identity: extraction may remove the old reviewed entry and introduce a + new unreviewed one. Review wording changes as translation migrations, including reused keys in other modules. - Inspect the full diff. Preserve deliberate translations/review flags, HTML/newline semantics, and natural RU/ZH meaning. Curated, verified translations need `isReviewed` set to the string `'True'`, as the generator compares that literal; a Python Boolean is not equivalent. Review applies to the entry, so inspect its other language values too. diff --git a/Furious/Frozenlib/AGENTS.md b/Furious/Frozenlib/AGENTS.md index c4e27e3..2018584 100644 --- a/Furious/Frozenlib/AGENTS.md +++ b/Furious/Frozenlib/AGENTS.md @@ -18,7 +18,9 @@ for unrelated application orchestration to accumulate in a broad helper namespac failure, and None when policy deliberately leaves host settings unchanged. Startup registration and some routing helpers return Booleans; script-mode startup registration intentionally does nothing. Preserve these distinctions at callers instead of treating absence of an exception as confirmed host state. Check every native command result, - including each enabled macOS network service, and bound host-command waits at this boundary. + including each enabled macOS network service, and bound host-command waits at this boundary. A per-command timeout + is not a deadline for a loop over services or routes. Multi-step host mutation may be partial when a later command + fails; a False result does not establish that earlier effects were rolled back. - Prefer argument vectors over shell strings. Each caller owns any responsiveness/cleanup timeout appropriate to its context; build-time commands and GUI-time host mutation do not share one universal timeout policy. - Windows proxy calls, Linux desktop settings/host bridging, and macOS network-service operations are distinct diff --git a/Furious/Interface/AGENTS.md b/Furious/Interface/AGENTS.md index 5fd7079..df0cfdc 100644 --- a/Furious/Interface/AGENTS.md +++ b/Furious/Interface/AGENTS.md @@ -25,7 +25,9 @@ satisfy without importing application composition or concrete backends. 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. + 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 requirements + must remain meaningful for an in-process implementation as well as a child process that resists termination. - Verify cheap/import-independent contracts plus representative runtime, storage, editor, application-exit, encoding, and configuration implementations. Update this guide when a contract intentionally changes, together with all implementers and compatibility tests. Start with `tests/test_interface.py` and diff --git a/Furious/Models/AGENTS.md b/Furious/Models/AGENTS.md index 6b8c84d..d3e4ee6 100644 --- a/Furious/Models/AGENTS.md +++ b/Furious/Models/AGENTS.md @@ -9,7 +9,8 @@ Qt presentation, plugin discovery, or workflow execution. controllers, plugin registries, or concrete backends into this layer. - `CoreConfiguration` is a dict-like connection document whose construction is deliberately non-throwing: unsupported or malformed input becomes an empty object with `constructionError()`. Keep construction and serialization errors - distinct and preserve useful context through callers. + distinct and preserve useful context through callers. Successful generic mapping construction is not protocol + validation: backend acceptance belongs to the selected capability, and serializability is a separate check. - `ServerProfile` composes an independent connection document with `ProfileMetadata`. Display name, stable profile ID, subscription ownership/key, latency, speed, annotations, and local flags never become core-configuration fields. - Preserve unknown metadata and legacy aliases across load/save. `independentCopy()` creates a manual profile with a new diff --git a/Furious/Plugins/AGENTS.md b/Furious/Plugins/AGENTS.md index 35e30c1..2d6fbee 100644 --- a/Furious/Plugins/AGENTS.md +++ b/Furious/Plugins/AGENTS.md @@ -8,8 +8,11 @@ capability definitions, atomic registration, dispatch, and plugin lifecycle; bac - `Plugins.API` defines independently composable capabilities for protocols/editors, subscription decoding, runtime factories, routing/TUN/probes, statistics, settings, actions, and navigation. Extend the owning capability instead of adding backend-name branches or a parallel registry. -- The registry normalizes and validates a plugin's complete contribution before committing indexes. Duplicate IDs or - schemes, incompatible API versions, invalid descriptors, and initialization failure leave existing providers intact. +- The registry normalizes and validates a plugin's complete contribution before changing indexes. Initialization + runs with the contribution indexed; if it fails, shutdown is attempted and those indexes are removed. This is + rollback of registry publication, not a transaction over arbitrary plugin side effects. Plugins must clean their + own partial acquisitions even when initialization fails. Duplicate IDs/schemes and invalid versions/descriptors + must leave existing providers intact. - Host plugin types register before external entry-point discovery. Bundled registrations are explicit for source, wheel, and Nuitka inclusion. External entries currently follow metadata enumeration order; do not promise sorted discovery or rely on it for precedence. Registration is atomic per plugin, not across a multi-plugin entry point. diff --git a/Furious/Qt/AGENTS.md b/Furious/Qt/AGENTS.md index 9df7189..bb5d25b 100644 --- a/Furious/Qt/AGENTS.md +++ b/Furious/Qt/AGENTS.md @@ -10,7 +10,9 @@ primitives; pages and services consume them without creating parallel registries - Reuse `Furious.Qt` `AppQ*` controls, `AppStyleSheet`, translation/theme mixins, and shared dialog/window infrastructure. Do not create parallel style, theme-transition, translation, or lifetime registries. Shared control styling belongs - in the application stylesheets; component-specific overrides are valid parts of stylesheet composition. + in the application stylesheets; component-specific overrides are valid parts of stylesheet composition. Check + selector specificity for disabled, hover, and selected states: a general disabled-label rule may lose to an + object-name rule even when the widget's enabled state is correct. - Controls that retranslate retain source text; semantic/user-defined values stay untranslated. Preserve keyboard focus, shortcut scope, accessibility, translated-text growth, responsive layout, high-DPI behavior, and both themes. - Application-owned theme transitions commit destination state immediately; snapshots are non-interactive presentation @@ -27,7 +29,8 @@ primitives; pages and services consume them without creating parallel registries `finished` ends interaction, not native lifetime; operation context may be released then only if later callbacks do not need it. - `AppQDialog`/`AppQMainWindow` registries bridge asynchronous presentation/visibility; they are not substitute - application owners. Registry cleanup captures opaque tokens, never the object being released. + application owners. Cleanup captures a unique lifetime token, never the object being released or a reusable + numeric object ID. A delayed destruction callback must not evict a newer wrapper from the registry. - A Qt parent alone does not prove the Python wrapper or logical feature lifetime. Bare Qt `.show()` does not retain an unparented wrapper; `AppQMainWindow.show()` adds its own visible-window retention until accepted close. Do not solve ambiguity by global retention, indiscriminate delete-on-close, routine `gc.collect()`, or broad diff --git a/Furious/Repository/AGENTS.md b/Furious/Repository/AGENTS.md index 8b3099b..7163adc 100644 --- a/Furious/Repository/AGENTS.md +++ b/Furious/Repository/AGENTS.md @@ -11,7 +11,9 @@ This scope owns restoration, migration, ordering, and persistence; workflows and - Preserve stable profile/subscription IDs, subscription ownership/key, ordering, unknown fields, and legacy schemas. Active row/index and display text are compatibility/presentation state, not identity. - A restore failure remains observable. Automatic cleanup must not replace unreadable persisted bytes with an empty - fallback; only an explicit successful replacement may do so. + fallback; only an explicit successful replacement may do so. Root decoding, individual-record hydration, and later + serialization are separate failure boundaries. Test malformed records inside a valid root as well as malformed + roots; the existing root fallback is not a guarantee that every record error is recoverable. - Stage fallible decode/migration before live mutation. Subscription reconciliation currently belongs to `Service/SubscriptionSync.py` and commits through the compatibility live collection: matched managed profiles retain object/profile identity and local metadata, removed profiles become stale, and unrelated groups remain diff --git a/Furious/Service/AGENTS.md b/Furious/Service/AGENTS.md index a537fe3..9e9be6f 100644 --- a/Furious/Service/AGENTS.md +++ b/Furious/Service/AGENTS.md @@ -33,6 +33,8 @@ for lifetime primitives. This scope owns multi-stage workflows and temporary res replacing the runtime callback. Worker-thread exits are queued to the router's Qt thread, delivered at most once, and suppressed after release. Execution liveness and endpoint/TUN readiness remain separate observations. A readiness timeout never replaces a typed exit after execution has already stopped, even when that exit is still queued. + Lease release currently logs stop/dispose errors and completes logical callback release; this is not evidence that + the underlying resource was reaped. Changes to cleanup-failure reporting must cover both runtime and lease owners. - `HttpGetManager` owns reply/error/timeout cleanup. DNS recursion and external-input caches are bounded. Update, connectivity, endpoint, subscription, and asset requests own their exact reply and reject stale generations. - Subscription stages remain separate: decoders return neutral items; import constructs profiles/metadata; @@ -52,14 +54,18 @@ for lifetime primitives. This scope owns multi-stage workflows and temporary res - Log transport, traffic collection, and metric history remain bounded and independent of page visibility. Rendering may be lazy; collection/draining ownership is not. - Logging accepts concurrent producers through one globally ordered model with count, total-character, and per-entry - limits. Whole-stream clearing swaps generations; retired entries are reclaimed in bounded batches under retention - budgets. Selective category clearing can cost O(k); do not claim every clear is constant-time. + limits. Batch input conversions are validated before mutation; compatibility per-entry signals observe the fully + committed batch. Presenters consume coalesced changes/cursors rather than replaying those signals as a second log. + Whole-stream clearing swaps generations; retired entries are reclaimed in bounded batches under retention budgets. + Selective category clearing can cost O(k); do not claim every clear is constant-time. - Log cursors are opaque and filter-specific. A generation change requires a reset; retention-only eviction supplies a new first-retained sequence so presenters can prune their prefix without rebuilding history. Capture entries and the next cursor atomically, and coalesce notifications without losing producer updates. - Metrics sampling owns its worker/future generation and rejects results after disconnect, disablement, replacement, or shutdown. Cancellation cannot stop an already-running plugin query: monitor contracts must bound blocking work. Normalize cumulative-counter resets before history aggregation; clearing usage must not erase speed history. + History contains finite values for registered metrics on a monotonic timeline. A missing metric sample is not a + measured zero; preserve that distinction when adding providers or aggregating sparse series. ## Profile testing diff --git a/Furious/Utility/AGENTS.md b/Furious/Utility/AGENTS.md index 6e22fd0..1cfad98 100644 --- a/Furious/Utility/AGENTS.md +++ b/Furious/Utility/AGENTS.md @@ -14,9 +14,10 @@ general-purpose utility bucket. log-write failure never replaces the primary failure. - The parent entry point joins only the child it created and shows the fallback Qt report only for a nonzero result. Never discover or terminate processes by name, and keep normal/source/packaged command-line entry points equivalent. -- Shared crash status is a synchronized Boolean plus the child's semantic exit result; diagnostic text is written to - a file and may include retained logs plus a traceback. Do not describe the complete crash file as size-bounded by - the Boolean channel. Redaction and crash-write failure are separate from application-exit correctness. +- Shared crash status is a synchronized Boolean plus the child's semantic exit result; set the flag only after the + diagnostic file is written successfully. Text may include retained logs plus a traceback, so the Boolean channel + does not bound the crash file's size or sanitize its contents. Keep crash-write failure separate from the primary + exit result, and 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. diff --git a/Furious/Widget/AGENTS.md b/Furious/Widget/AGENTS.md index acc83ce..6b85d1f 100644 --- a/Furious/Widget/AGENTS.md +++ b/Furious/Widget/AGENTS.md @@ -13,8 +13,10 @@ some service owners; that construction detail does not make every view an indepe keep index/deleted compatibility fields synchronized, and map proxy indexes to source objects before acting. Stable profile/subscription IDs—not display text, object row, or current sort order—preserve selection, focus, activation, and async write-back. -- Sorting/filtering/reordering must retain logical selection and keyboard focus. Recursively scope table-owned menu - shortcuts as `WidgetShortcut` so a focused editor or another surface keeps its own shortcut semantics. +- Sorting/filtering/reordering must retain logical selection and keyboard focus. Capture domain IDs before yielding + to a dialog or event-loop turn; an ordinary QModelIndex/source row may become invalid or refer to another item. + Map the resolved current object back through the proxy when restoring focus. Recursively scope table-owned menu + shortcuts as `WidgetShortcut` so focused editors and other surfaces keep their own shortcut semantics. ## Workflow and lifetime boundaries diff --git a/Furious/Window/AGENTS.md b/Furious/Window/AGENTS.md index 631a183..d3ec05e 100644 --- a/Furious/Window/AGENTS.md +++ b/Furious/Window/AGENTS.md @@ -10,8 +10,9 @@ This scope owns persistent page composition and top-level presentation, not shar Preserve application-facing forwarding APIs until their consumers migrate deliberately. Bulk profile forwarding must retain the bulk mutation boundary through Home and its model, without expanding into per-profile refreshes. - Home, Settings, tray actions, and reusable dialogs render the same connection, routing, and settings controllers. - Platform/capability availability affects presentation but does not authorize an unsupported persisted value or a - duplicate host side effect. + Apply availability and interaction gating to both a control and its associated label, on initial composition and + later state changes. Disabling presentation does not clear a stored preference or authorize a duplicate host side + effect; preserve the controller's platform/capability policy. - The current page composition shares one subscription workflow between server and subscription presentation, records traffic into one history, and derives metrics/endpoint presentation from owned services. These exact locations may evolve, but a refactor retains one durable owner, one scheduler/request path, and one signal path. diff --git a/Icons/AGENTS.md b/Icons/AGENTS.md index 1973936..49a15ef 100644 --- a/Icons/AGENTS.md +++ b/Icons/AGENTS.md @@ -13,7 +13,9 @@ resource-manifest contract; it does not govern general UI layout. environment's `pyside6-rcc Resources.qrc -o Furious/Frozenlib/AppResources.py`. Never hand-edit generated resource code; inspect compiler-version churn separately from the intended alias/asset change. - Treat the alias as the application-facing identity and the source path as an implementation detail. Search both before - replacement so an apparently unused file is not removed while still generated or consumed through an alias. + replacement so an apparently unused file is not removed while still generated or consumed through an alias. Selecting + an already bundled Bootstrap icon normally changes its consumer only; it does not require regeneration or another + SVG copy. Compare the glyph's visible bounds at the actual control size, not only its nominal SVG canvas. - Verify alias uniqueness and source/package resolution, then inspect the actual control or tray use under both themes, high DPI, relevant sizes, disabled/selected states, and platform packaging where applicable. Deployment icons also have direct filesystem consumers in `Deploy.py`; a resource alias search alone cannot prove a PNG is diff --git a/tests/AGENTS.md b/tests/AGENTS.md index 66bcec1..032a2e4 100644 --- a/tests/AGENTS.md +++ b/tests/AGENTS.md @@ -33,8 +33,11 @@ and test-tier selection; test convenience never weakens a production invariant. Rendering regressions may assert targeted pixel/alpha or geometry properties under explicit themes and scaling. Stylesheet selector counts are not rendering invariants: shared rules and component overrides can both be valid. - Prefer exact state, signal counts, destroyed signals, weak references, registry/child counts, thread/process/handle - ownership, and final exit status. RSS/handle trends and repeated lifecycle batches belong in stress tiers; - `gc.collect()` is diagnostic at batch boundaries, never a production fix or per-cycle requirement. + ownership, and final exit status. A mock cleared from its owner does not prove termination: failure-to-reap tests + must independently retain and inspect the fake process. For Qt API compatibility, a permissive Python fake cannot + validate a real binding's accepted argument types; exercise a harmless real object at that boundary. + RSS/handle trends and repeated lifecycle batches belong in stress tiers; `gc.collect()` is diagnostic at batch + boundaries, never a production fix or per-cycle requirement. ## Tiers and maintenance @@ -42,6 +45,9 @@ and test-tier selection; test convenience never weakens a production invariant. tests -v` for full source-suite discovery (opt-in tests still skip). The runner is unittest, not pytest. Run the narrow module first, then the affected tier documented in `tests/README.md`. The release-confidence tier is explicitly opt-in with `FURIOUS_VERY_HEAVY_TESTS=1`; packaged/manual smoke work uses disposable environments. + The historical log comparison additionally requires `FURIOUS_LOG_MANAGER_BASELINE` naming a trusted, compatible + local Git revision; it loads that revision's implementation. Report this opt-in and any skips separately rather + than assuming the very-heavy switch alone executes every discovered case. - Source-only tests and an offscreen platform do not prove a packaged Qt runtime. Compiler-sensitive changes need the relevant native lifecycle module and a separate compiled probe; report skipped or unavailable targets explicitly. The release workflow currently builds/checks artifacts without running this source behavioral suite.