Refine repository guidance

Signed-off-by: Loren Eteval <loren.eteval@proton.me>
This commit is contained in:
Loren Eteval
2026-10-08 17:38:59 +08:00
parent 2fbf353b95
commit af8e5a5205
27 changed files with 81 additions and 22 deletions
+3
View File
@@ -64,6 +64,9 @@ Read `.github/workflows/deploy-pypi.yml` with `tests/README.md`; paths are relat
interpreter-version checks. The latter use compatible Qt/native wheel pins, dependency consistency, native-binding
imports without starting runtimes, application compilation, cold imports and real compatibility behavior. These
checks do not certify the entire suite on every version.
Default source discovery includes regular stress but leaves the explicitly enabled very-heavy classes skipped.
Standalone benchmarks and compiled lifecycle probes are separate entry points; neither runs merely because the
source job or binary matrix succeeds. Check `tests/README.md` for the effective opt-ins and invocation boundaries.
The reusable workflow is a required dependency of PyPI publication through `workflows/deploy-pypi.yml`, so its
version matrix must also pass. It can run manually. Hourly binary builds retain their separate artifact scope. Source tests do not establish packaged behavior or Python/Qt
floors beyond their matrix. Do not call an artifact build a regression-test pass; use `tests/README.md` for
+8 -3
View File
@@ -2,7 +2,8 @@
## Learn before changing
- Treat the checked-out tree, tests, build configuration, and verified runtime behavior as the immediate source of truth.
- Treat the checked-out tree, tests, build configuration, and verified runtime behavior as the immediate source of
truth.
Existing guidance is a maintained model, not an authority that can make itself true.
- If `.codegraph/` exists, use CodeGraph before broad text searches for structural questions; use `rg` for exact
follow-up. Inspect callers, tests, persisted formats, platform branches, and packaging consumers before changing a
@@ -65,7 +66,8 @@
copies unless an API deliberately mutates storage. A failed pre-commit stage leaves persistence unchanged; a failed
post-commit side effect is reported without pretending the commit rolled back. Identify the unit of commit:
cancellation of a batched operation may preserve completed batches rather than roll back the entire command.
- Use stable domain identity, not table rows, proxy indexes, display text, or object position. Async results additionally
- Use stable domain identity, not table rows, proxy indexes, display text, or object position. Async results
additionally
prove that the target generation/fingerprint is still current before mutation.
- Distinguish profile identity, subscription membership, remote synchronization ownership, and execution snapshots.
Moving a profile into a group does not transfer remote ownership; a running core uses its prepared document even
@@ -101,7 +103,8 @@
- Centralize supported standard-library API differences in `Frozenlib.PythonCompatibility`; select implementations
once and preserve result/error semantics. Keep pure domain imports independent of the Qt-backed foundation by
using minimum-compatible typing/runtime APIs at that boundary. Verify both legacy API shapes and actual supported
interpreters; `tests/test_python_compatibility.py` anchors the shared behavior, not a complete minimum-version guarantee.
interpreters; `tests/test_python_compatibility.py` anchors the shared behavior, not a complete minimum-version
guarantee.
- Generated and curated artifacts have separate sources of truth: never hand-edit
`Furious/Frozenlib/AppResources.py`; update `Resources.qrc`/resource inputs and regenerate it. Follow
`Furious/Externals/AGENTS.md` for the translation catalog and `Furious/Data/AGENTS.md` for bundled assets.
@@ -158,4 +161,6 @@
path as well as its successful caller; a test name is an investigation anchor, not proof of unexercised behavior.
Keep run-specific counts, versions, diagnostic experiments, and defect inventories in the work report; guidance
retains the required invariant and a source/test anchor. Do not repeatedly append symptoms to a local guide.
Separate an implemented safeguard from a required but unfulfilled contract. Documentation must neither claim
a missing safeguard exists nor redefine the defect as intended behavior merely because its tests currently pass.
During guidance-only work, report defects separately instead of changing production code to satisfy the prose.
+2
View File
@@ -22,6 +22,8 @@ Read `Furious/__init__.py` with `tests/test_public_api.py`; paths are relative t
separately. Importability means preserving the actual side-effect boundary, not merely avoiding a syntax error.
Python export aliases, distribution names, native-module names, and persisted identifiers serve different consumers;
inspect each affected surface before renaming one. An import alias does not migrate stored data or transfer ownership.
Standard-library imports and child-only native binding imports have different side-effect boundaries. Moving one
import must preserve both cold package import and actual spawned-child execution, not only a mocked factory path.
## State, data, and ownership
+2 -1
View File
@@ -47,7 +47,8 @@ Read `Furious/Actions/Import.py` with `tests/test_qt_interactions.py`; paths are
- Native action destruction also releases its screen-capture handle through the same idempotent cleanup path as
application shutdown. Destruction callbacks retain plain resource state, not the action. Failed close is diagnosed
and retains the handle while that state has a surviving owner; native destruction does not provide a retry scheduler.
A top-level progress widget borrowed by an action needs explicit native deletion when that action dies.
An action-created top-level progress widget is owned by that action even though a QAction cannot be its QWidget
parent. Native action destruction must schedule its deletion; ordinary progress close remains reusable.
Verify native teardown while intentionally retaining action wrappers/bound methods.
- Small profile imports use the direct bulk path; large imports yield between bounded batches. One operation owns
captured input and its continuation through completion/cancellation; teardown rejects deferred calls. A parser call
+3 -1
View File
@@ -11,7 +11,9 @@ relative to this source tree's root.
owners already exist during election. Plugins are available before repository restoration interprets persisted
profiles. Register cleanup as each acquisition succeeds, including election-failure paths, and preserve these
dependencies when changing stage order.
- Partial startup, normal exit, signals, and event-loop failure converge on one reverse-order cleanup path.
- Once `DesktopApplication.run()` is entered, partial startup, normal exit and event-loop failure converge on one
reverse-order cleanup path. Constructor failures and signals before handler installation need separate outer-process
evidence; do not extend the run-loop cleanup guarantee to acquisitions it never reached.
`aboutToQuit` and the event-loop `finally` may both reach it; repeated entry must not repeat registered stages.
One callback failure does not skip later stages, but the stack consumes that callback and does not retry it.
Its successful `close()` return means this invocation ran the stack, not that every resource was released.
+3 -1
View File
@@ -26,7 +26,9 @@ tree's root.
owns the editable snapshot, acceptance validation, identity resolution, and eventual write-back. Runtime factories
likewise transfer fresh execution resources to the workflow owner. Editor acceptance and runtime readiness are
different validations; neither may silently rewrite stored data to make a later stage succeed. Backend factories
may deliberately defer editor/native imports for discovery and process boundaries; do not hoist those imports
can return no prepared launch for an unsupported operation. Preserve that outcome without treating a missing
launch as execution success or silently selecting another backend.
Factories may deliberately defer editor/native imports for discovery and process boundaries; do not hoist those imports
solely for uniform style without checking cold imports and the spawned-child construction path.
- `Furious/Plugins/Runtime.py` checks that serialization yields nonempty text and carries structured diagnostics on failure;
it does not parse pre-serialized strings or validate a backend's complete schema. Keep serialization success,
+3 -1
View File
@@ -10,7 +10,9 @@ source tree's root.
- External Core represents one user-selected local executable, not an embedded protocol binding. Keep executable path,
optional working directory, argument vector, environment overrides, HTTP/SOCKS endpoints, shutdown timeout, remote
TUN address, and application-TUN opt-in distinct while preserving unknown top-level fields.
- Loading is observational: do not silently absolutize or rewrite relative paths. Validation before spawn owns path
- Loading is observational: do not silently absolutize or rewrite relative paths. An explicitly chosen file may
be resolved by the editor, while opening a stored document must preserve its path text. The chooser's nested
event loop also requires a surviving native field tree before write-back. Validation before spawn owns path
existence/type, argument and environment types/NULs, endpoint requirements, and a finite bounded shutdown timeout.
Reject NaN, infinities, Booleans, and integer-to-float overflow before process wait APIs. Preserve the accepted
finite interval and prove rejection behavior directly; equivalent-looking comparisons are not a substitute
+2 -1
View File
@@ -15,7 +15,8 @@ source tree's root.
host routing or connection commit. Keep the factory's unsupported routing/TUN combination rejection before
execution acquisition; do not silently substitute Global routing or borrow native TUN from Hysteria 2.
Keep MMDB/ACL launch preparation here and application-TUN acquisition/rollback with that workflow. The existing
rejection prompt is a compatibility path, not a requirement that runtime factories own UI.
rejection prompt and absent prepared launch are compatibility outcomes, not a requirement that runtime factories
own UI. Test refusal before acquisition separately from a typed runtime failure after ownership transfers.
- 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. The serialized client document and these
+3 -1
View File
@@ -30,7 +30,9 @@ this source tree's root.
make that preparation interruptible. Test resolved addresses and explicit route exclusions as separate inputs to
the exclusion guarantee; a resolution failure alone does not prove that valid manual exclusions are absent.
DNS failure and insufficient Linux privilege are independent preparation failures. Manual exclusions can satisfy
the former route-input requirement but do not grant the latter privilege or prove remote connectivity.
the former route-input requirement but do not grant the latter privilege or prove remote connectivity. Native
TUN ownership is decided from the prepared document, before application-engine selection; a later preference change
must not reinterpret the running core's ownership.
- 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
+3
View File
@@ -38,6 +38,9 @@ source tree's root.
download path and does not inherit runtime staging or checksum guarantees. Hash jobs receive copied bytes
and return through the updater's Qt-thread boundary; closing the updater must release request and hash-callback
contexts independently, including native destruction without a normal reply completion.
Checksum workers own copied bytes and opaque job identity, not a download callback or transient Qt receiver.
Resolve result context on the updater's Qt thread and discard it at shutdown; a completed hash is not permission
to revive a retired download. `tests/test_xray_asset_download.py` covers the blocked-worker destruction case.
- 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.
Trace the selected repository routing document separately from the connection's routing branch and prepared
+2
View File
@@ -45,6 +45,8 @@ source tree's root.
- `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.
Presentation can queue a checkbox request to let Qt's native setter unwind. The controller remains authoritative
when that request is delivered; queued UI timing is not a second preference state or a delayed persistence policy.
TUN mode, application-engine preference, and the active runtime's captured choice are separate values. A preference
change affects a subsequent attempt; it neither replaces a live engine nor overrides proxy-core native TUN.
Registration/defaults and selection signals belong here, while customization storage and host work keep their owners.
+4 -2
View File
@@ -48,8 +48,10 @@ relative to this source tree's root.
queues, or callbacks. Start with `tests/test_runtime_lifecycle.py` and `tests/test_connection_startup_async.py`;
output/process stress lives in the tiers documented by `tests/README.md`. Review output admission and draining
together when changing backpressure.
- `SingTUN` imports the Go binding only in a spawned child. Its bounded status pipe establishes native readiness
and the actual device name independently of diagnostic output and process liveness. Cooperative stop is followed
- `SingTUN` imports the Go binding only in a spawned child. Exercise the real child import path independently of
an injected test engine when import or metadata plumbing changes. Distribution-version lookup must not start
the native engine. Its bounded status pipe establishes native readiness and the actual device name independently
of diagnostic output and process liveness. Cooperative stop is followed
by exact-child reap and attempt-local host recovery; retain the lease when either fails. Never infer Go cleanup
from forced termination. Its `SingTUNHostPlan` remains attached through host-worker drain and restoration; tests
in `tests/test_sing_tun.py` cover startup cancellation, validated status with binding-provided failure reasons,
+2
View File
@@ -11,6 +11,8 @@ tree's root.
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.
A pre-existing asset diff may belong to the user or the runtime updater. Preserve its bytes during source/guidance
work instead of treating it as disposable generated output or including it in an unrelated documentation commit.
- 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
+3 -2
View File
@@ -13,8 +13,9 @@ relative to this source tree's root.
belongs to `SubscriptionImportService`, and group reconciliation, request generations, timers, persistence, and
post-commit effects belong to the subscription service/repository path.
- Automatic detection probes decoders by priority. An explicit decoder ID restricts dispatch to that decoder;
an unknown ID or a mismatch must not silently resume automatic detection. Return `None` for a mismatch. Recognizing
a share-link envelope does not validate its URI schemes or protocols; the importer owns that decision.
an unknown ID or a mismatch must not silently resume automatic detection. Return `None` for a mismatch;
an empty `SubscriptionResult` instead describes recognized input and reaches a different import/reconciliation
policy. Recognizing a share-link envelope does not validate its URI schemes or protocols; the importer owns that decision.
Preserve useful names/upstream IDs and never log a complete payload or link. Standard plain/Base64 decoding
materializes input before per-item import can be cancelled; linear parsing is not a size or responsiveness bound.
Review decoded size and work limits at this boundary before adding richer formats.
+2
View File
@@ -45,6 +45,8 @@ tree's root.
brace placeholders is extractable: translate it first, then interpolate with `.format()` outside `_()`.
- Keep runtime interpolation outside the translatable expression. Translate UI language, not identifiers, protocol
values, user-defined names, persisted values, paths, or diagnostic payloads.
Translate application-owned validation categories through static catalog keys while preserving native diagnostic
text and user JSON keys. Do not make localization depend on an upstream exception's exact English wording.
- When a control stores source text for later retranslation, update that source instead of manually translating one
rendered instance. Adjacent static literals and multiline literals still form one source key; preserve their
exact whitespace/newlines when changing layout or formatting. Verify extraction and rendered retranslation
+2
View File
@@ -21,6 +21,8 @@ Read `Furious/Frozenlib/AppSettings.py` with `tests/test_frozenlib.py`; paths ar
- `Mixins.qObjectIsValid` checks native QObject validity and deliberately accepts non-QObjects, including `None`.
Check required presence and plain resource state separately; a Python editor binding needs checks of its Qt fields.
Neither one-object nor grouped validity checks provide ownership, thread affinity, or generation freshness.
Use the Qt scope's boundary rule before adding checks to a caller. This helper supplies a predicate, not a reason
to check every method; pure reads and computations do not invalidate an already-valid receiver.
- `AppSettings` keys include preferences and encoded repository blobs. Preserve names, defaults, string/binary
encodings, migrations, and import-time registration. `AppSettings.get()` can persist a default or repair an
invalid preference; it is not an observational reader like a copied customization projection. Distinguish
+2
View File
@@ -30,6 +30,8 @@ Read `Furious/Interface/Runtime.py` with `tests/test_interface.py`; paths are re
- `ApplicationRunner.ExitCode` is the outer application process protocol; it is not interchangeable with a core's
raw exit code or `RuntimeExitReason`. Preserve the meaning at each boundary instead of translating every nonzero
value into one generic failure.
Declaring the exit enum does not route exceptions into it. Verify the concrete process boundary separately from
an exception hook's mapping; bootstrap interception can bypass that hook.
- Model encoders may raise, while configuration construction deliberately captures diagnostics. Callers must inspect
the contract they consume; successful construction alone proves neither serialization nor backend acceptance.
Preserve `RuntimeStartError`'s reason/code/details and `RuntimeExit`'s typed meaning across adapters; exception text
+2
View File
@@ -17,6 +17,8 @@ root.
or malformed input becomes an empty object with `constructionError()`. Keep construction and serialization errors
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.
Profile/configuration `isValid()` methods validate domain data, not QObject lifetime. Keep these checks distinct
from native-wrapper guards when auditing similarly named calls or changing a validation contract.
- `ServerProfile` separates connection data from `ProfileMetadata`. `fromConfiguration()` copies a bare configuration
but returns an already-supplied profile unchanged; the direct dataclass constructor does not imply copying. A type
conversion is therefore not an isolation boundary. Choose explicit copy semantics before independent editing or
+2 -1
View File
@@ -48,7 +48,8 @@ tree's root.
state. Backend-specific defaults, settings keys, document branches, and host assumptions stay behind the provider.
Capability presence advertises an operation, not a configured target or successful execution; callers must handle
absence, unavailable configuration, and operation failure separately (notably statistics, export, and probes).
- API-version-3 runtime factories return `PreparedRuntime` directly. The runtime is fully prepared before return,
- Runtime factories admitted by the current plugin API return `PreparedRuntime` directly. The API version is owned
by `Plugins.API`, not by a duplicated literal in this guide. The runtime is fully prepared before return,
starts with zero arguments, raises typed startup failures, and exposes readiness separately. An alternate result
shape requires an explicit contract/version migration, not an implicit adapter inferred from built-in factories.
The registry's existing synchronous `startCoreRuntime()` wrapper separately returns runtime/success for
+4 -2
View File
@@ -64,9 +64,11 @@ Use the `manage-qt-pyside6-lifetimes` skill for source lifetime work when availa
that owner, when more native work follows. Name the actual boundary and trace its callers/observers rather than
assuming every function can destroy arbitrary UI. If the check already passed and the intervening code only reads
or computes data, do not repeat it. Keep callback-specific checks inside the branch that invokes that callback.
Qt receiver disconnection and `connectWeakly()` protect delivery entry, so an immediately repeated receiver check
Qt-connected QObject slots and `connectWeakly()` protect delivery entry, so an immediately repeated receiver check
adds nothing; they do not protect continuation after reentrant delivery. Required workflow-generation checks remain
separate. Existing callback, modal, borrowed-object and peer-destruction cases in `tests/test_qt_lifetime.py`,
separate from validity. A plain callback retained outside Qt's receiver context needs its own lifetime contract;
do not extend QObject-slot disconnection guarantees to arbitrary Python callables. Existing callback,
modal, borrowed-object and peer-destruction cases in `tests/test_qt_lifetime.py`,
`tests/test_frozenlib.py`, and `tests/test_service_runtime.py` challenge these distinctions.
- Only the GUI thread mutates widgets/live GUI models. Slots do not sleep or perform unbounded file, host, process, or
network work; split work into bounded event-loop units or an owned worker and reject stale results on return.
+2
View File
@@ -20,6 +20,8 @@ to this source tree's root.
migration deliberately changes it; do not treat every duplicate key as interchangeable.
Connection JSON export is not a profile-store backup. Verify durable metadata through storage-record/backend
round trips, including identity, favorites and remote ownership, rather than connection serialization alone.
Favorite mutation updates local metadata on the existing profile. Rendering a star must not rewrite the remark,
connection document, subscription matching key, or profile identity merely to display that persisted flag.
- 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. Root decoding, complete-collection
hydration, live replacement, and later serialization are separate failure boundaries. Byte preservation does
+4 -3
View File
@@ -30,9 +30,10 @@ source tree's root.
and release contexts only when execution no longer needs them. Late delivery must not revive a shut-down manager
or mutate live state. A terminal result ends an operation's publication contract, not necessarily its execution:
a replacement may be admitted only under the scheduler's resource bounds while cancelled work still occupies a slot.
Provider calls, reply aborts, and grouped notifications are reentrancy boundaries too. Recheck native ownership
and the captured generation before continuing a stage, restarting a timer, admitting another request, or
publishing the next result; a check at callback entry alone cannot establish freshness afterward.
External provider callbacks, reply aborts and signal publication can be reentrancy boundaries. Trace the specific
callback/observer contract before adding continuation guards; pure preparation is not a destruction boundary.
Recheck native ownership and the captured generation before continuing a stage, restarting a timer, admitting
another request, or publishing the next result; a check at callback entry alone cannot establish freshness afterward.
## Connection and network workflows
+4 -2
View File
@@ -10,13 +10,15 @@ source tree's root.
- `AppMainProcess` owns one exact Qt application child and one small synchronized crash-log result. Do not add a
`multiprocessing.Manager` or auxiliary child merely to communicate status, and preserve the platform’s explicit spawn
behavior.
- Exception reporting must work before and after application construction. The child runs the supplied application
factory; the parent must not construct a Qt application to pass across the process boundary. Signal handlers are
- Required exception reporting covers failures before and after application construction. The child runs the supplied
application factory; the parent must not construct a Qt application to pass across the process boundary. Signal handlers are
installed only after the factory returns, so pre-construction signals are outside this wrapper's handler coverage.
Preserve semantic exit codes and original exception/traceback context; crash-log failure is secondary.
Verify this through a real spawned child: multiprocessing bootstrap can intercept an uncaught factory/run failure
before `sys.excepthook`. Direct hook tests prove its mapping only, not dispatch from every child failure path;
compare the actual exit and crash flag before claiming supervision coverage.
The current wrapper installs the hook but does not explicitly catch exceptions escaping the supplied factory
or `application.run()`. Keep this coverage gap visible instead of describing hook installation as complete dispatch.
- The parent entry point joins only the child it created and shows the fallback Qt report only for a nonzero result.
That join follows the GUI session lifetime; it is not a short startup-readiness deadline. Tests must bound their
own waits and reap their exact child if the fixture fails. A child stuck in cooperative worker cleanup can
+3
View File
@@ -59,6 +59,9 @@ source tree's root.
keep connection/remote ownership intact. Favorites, search, and subscription filters intersect in the existing
proxy model; a favorite mark is persisted metadata, while the filter is presentation state. The profile mutation
and Home workflow cases in `tests/test_qt_interactions.py` cover these boundaries.
Favorite SVG decoration follows the remark's foreground and selected-text roles, including privilege-dependent
connection colors. Use the shared color authority and view palette rather than a dark/light test; keep selected
icon and text behavior aligned. The selected-rendering cases in `tests/test_qt_interactions.py` are the pixel anchor.
- Endpoint lookup belongs to `EndpointInfoService`; the map renders validated results and has a no-WebEngine
fallback. Optional WebEngine import failure must not prevent importing the widget/package, and hidden presentation
must not retarget a queued lookup.
+3
View File
@@ -24,6 +24,9 @@ Read `Furious/Window/MainWindow.py` with `tests/test_ui_behavior.py`; paths are
silently normalizing storage, importing tun2socks preferences, or launching a native engine just to open settings.
The application JSON editor is another view of that same candidate, not a second configuration authority.
Validate the merged candidate at acceptance; editor syntax checking does not replace model validation.
Checkbox requests that can destroy their card use queued delivery after the native setter unwinds. Destroying
a card before delivery cancels its request; tests must process the event turn before asserting committed settings.
Keep this presentation boundary separate from the controller's synchronous policy and repository commit.
Translate semantic application validation categories here, preserving technical diagnostics and user JSON keys.
Do not classify failures by matching exact English exception text.
- The current page composition shares one subscription workflow between server and subscription presentation, records
+5 -1
View File
@@ -9,7 +9,11 @@ Read `Resources.qrc` with `tests/test_public_api.py`; paths are relative to this
remote resources, embedded rasters, editor metadata, or hard-coded page backgrounds.
- Use the shared icon helpers and the bundled monochrome/default and white variants as appropriate. An SVG's
`currentColor` alone does not establish Qt theme behavior; verify how `Furious/Qt/QtGui.py` resolves and masks the
chosen asset. Reuse that path instead of adding control-specific recoloring, and do not rely on color alone.
chosen asset. Theme-only controls reuse that path. Per-item decorations may mask an existing SVG into a native
QIcon using the view's foreground and selected-text colors; profile connection/privilege colors are not determined
by dark mode alone. `Furious/Widget/ServerTableView.py` and the favorite rendering tests in
`tests/test_qt_interactions.py` anchor this exception.
Preserve accessible text and do not rely on color alone.
Mask/opacity helpers cache shared icon values: keep cache size bounded and keys independent of widgets, and avoid
mutating a cached icon as if it belonged to one control.
- Preserve license/provenance and the `Resources.qrc` alias contract. Any add, removal, rename, or alias change
+3
View File
@@ -87,3 +87,6 @@ Read `tests/support.py` with `tests/README.md`; paths are relative to this sourc
the contract. For guidance-only changes, verify path preservation, changed-file scope, referenced commands/tests,
and contradictory claims; run existing behavior tests only to resolve architecture uncertainty rather than adding
tests of prose.
For a blank-line-only cleanup, compare the AST, executable tokens and nonblank lines, compile touched files,
and check formatter/diff output. This proves the promised structural equivalence without creating new behavioral
tests or repeating a full resource campaign solely for visual spacing.