Repository navigation
Close the gaps the second sweep left: stoppable GUI runs, tab lifecycle, MCP session ownership, config-sync leftovers, journal and CI - #511
Merged
Conversation
…f http_transport The file was at 727 of 750 lines, so nothing could be added to the session handling without first making room.
… is not Sphinx-only 27 of the 41 variables the package reads were named only on the Sphinx configuration page. Each README now has one table row per variable, grouped, and the test requires exactly that in all three languages; the recorded-exceptions set is empty.
…s stop skipping
Every signaling-server test starts with importorskip("fastapi"), so the server half of config sync ran on developer machines only. The exact versions tested are pinned on the tooling line, with httpx for fastapi.testclient.
A journal named the command and how it ended but not the screenshot, report or trace it produced, so a reader had to guess which file belonged to which step. The field is optional and the schema stays at version 1.
The history said a script failed and the journal said which step, but nothing joined the two: a reader had to match them by timestamp. An existing database gains the two columns on first open.
…reads Their steps were journalled without a parent, so a candidate script had to guess the nesting from timestamps and dropped them as detached. The time-containment guess stays for journals written before this.
…reaches the file limit client.py was 717 lines with the 409-content check, the default origin and the blob transport still to come. The bucket model and error types move to bucket.py, the merges to merge.py; client.py keeps the HTTP client and still exports every old name. All three are in the strict typing tier.
With RBAC every request was authorised by its own token, but the session id was honoured for whoever presented it, so a second authenticated user could attach to the first one's stream, delete the session or read which tools it had enabled. The id is now refused with 403 for anyone but its creator. The HTTP entry points also take tool_mode, and a tool registered outside a request (the plugin watcher's thread) is announced on every session's standing stream instead of reaching nobody.
In full mode the filter ran once, when the registry was built, so a mutating tool a plugin registered later was listed and ran on a server documented as offering only read-only tools. The two other modes already refused it; the check now runs at list time and at call time in all three.
Pattern redaction only recognises text that looks like a credential, so a passphrase quoted by an exception was written as it stood. The recorder now remembers, in memory and only until the journal stops, what the run read from the vault or typed as a secret, and masks it before cutting the error to length.
…ing it committed The store answered any repeat of an operation id with the first commit's revision, so a caller that reused an id for another bucket was told its write had landed when it had been discarded. The store now keeps a hash of what each operation wrote; a mismatch is OperationMismatchError, 409 with code operation_mismatch on the wire, and the typed error on the client. Rows from before the hash still answer as resends.
Python output was parsed with ast but Robot output was not checked at all. robotframework is not a dependency, so this reads sections, indentation and keyword rows itself and says in the manifest that it is not the Robot parser.
connection_screen.py was at 749 of 750 lines, so nothing could be added to it. The Recent list group moves unchanged into connection_recent.py as a mixin; the screen class keeps every slot under its original name.
…ted them An observer callback fires on the observer's thread or inside whoever polls, with no identity, so an operator's watch could run a privileged command unchecked. It now carries its registrant like a scheduler job does. A state machine or a plan handed to another thread keeps its caller the same way.
…a token The five commands could only be composed through the raw JSON view, and the builder prints a run's whole record, so the two that issue a token would have displayed it. Those two are marked and their result is masked before the record reaches the result pane.
Only the template strategy could be named from JSON, so a VLM version could not be measured from the executor, MCP or the GUI, and no report said how many model calls an answer took. Tokens and cost are reported only where the backend reports them.
A rule whose owner was removed or demoted is refused each poll, about once a second, and every refusal wrote an info line for the life of the process. A rule now reports a failure when it starts, changes or ends.
…device upsert/remove without origin= wrote flat last_modified entries, so programs written against the first API kept letting the later clock win, and a device that only called sync() was never listed under peers, so deletions did not wait for it. origin now defaults to this machine's device id, sync() settles the bucket the way push_operations does, and versioned=False keeps the flat entry for callers that need it.
A Stop in the scheduler, trigger, hotkey, e-mail trigger, webhook, REST API, USB sharing, remote-desktop host and WebRTC panels called a backend stop() that joins a thread, from the slot itself: the window froze for 2-6 s. They go through SlowOp / StopQueue on the task controller now; the tab shows "Stopping..." until the stop reports and ignores a second click meanwhile.
The check was a Python callable, so every click made from JSON, MCP or the GUI was logged with action_verified None and the heal statistics could not tell a click that worked from one that landed on the wrong thing. A check that cannot be carried out raises instead of reading as gone.
…ing to protect A device's first push_operations([]) always wrote, to list itself under peers. On an account with no entries that was revision 1 of an empty bucket. Joining is still recorded when the bucket holds entries, because their later deletion has to wait for the new device.
The tab printed the report as JSON, so comparing two versions meant reading two nested objects side by side. Versions are now rows with the rates and their counts; the full report stays underneath for the failing samples.
send_input wrote to the socket on the caller's thread, which for the viewer panels is the GUI thread once per mouse move: a host that stopped reading froze the window. Events go to a bounded queue with one writer thread; stale pointer moves give way under back-pressure, key and button events never do, and a failed or stalled write is reported through on_error.
Data and signature were two files written one after the other, and the lock around a change belonged to the instance. A second instance or process read new data against the old signature and failed closed on an untouched file, or saved over a rule written between its read and its write: two instances adding twenty rules each ended with twenty. The signature now lives in the file, replaced in one rename, and a change holds a lock file.
REST and MCP were driven this way already; the socket server, which runs a file through AC_execute_files, was the one surface left unexercised.
only_run_id, write_candidate, check_thresholds, format_comparison, LocateRequest, the Wayland authorisation ledger and the journal and healing schema versions were reachable only by module path, which is not a public contract.
…el execute_action The function every example starts with took only the list, so a dry run or a strict run meant knowing about the executor object behind it.
…ffline Inside the back-off left by a failed send a sync did not contact the server at all and still said offline, so Sync now right after the network came back looked like a dead server. The run and the status now say backing_off with retry_in_s, force skips the delay once (the GUI command does), and the status turns to pending when the delay has run out.
…r shares close_tab(key, release=True) called an optional dispose() that no tab had, so a released tab kept polling and stayed registered until Qt deleted it. The seventeen tabs that start a timer, register a listener, hold a share of the USB watcher or tail the logger release them on the call now.
Every Windows capability was 'available' and every macOS one 'unknown' without anything being read, so a locked workstation, a service in session 0 or a missing Screen Recording grant looked the same as a working session. The probes are read-only; a fact that could not be read is unknown, never available. The snapshot also carries what the backend can say about its version.
AC_android_list_devices, AC_android_shell and the device_info commands were listed as delivering the input capability, so the capability matrix claimed input coverage from commands that send none.
The note still said Wayland works through three CLI bridges; input has gone through libei and the portal first for some time, capture has four routes, and a refused consent no longer falls back.
181 warnings, all in older pages: title underlines shorter than a CJK title, inline markup that never closed because it touched a CJK character or an ASCII bracket (separated with an escaped space, which renders as nothing), three malformed tables, and an html_static_path naming a directory the tree does not have. No wording changed.
…aded Python A thread started inside execution_scope was documented not to inherit the run's scope, which held only because a new thread starts with an empty context on a default build. On a free-threaded build, and under -X thread_inherit_context=1, it starts with a copy of its creator's: measured on CPython 3.14.8t, a thread started in a run read the run's variables and kept writing into its scope after the run had ended. A binding now records the thread that made it and counts only there.
…out asserting them yet The click-state read-back, the by-id lookup of a minimised window and the point-based grab_logical run on the macos-14 runner as reported probes: printed with the line EXPECTED would hold, unable to fail the job until a run has measured them. The first two re-run the existing real-framework tests and count a skip as a skip.
…e docs with warnings as errors, and run the scope tests without a GIL The typing contract reads the optional libraries as Any so its verdict cannot depend on what is installed, which also means no call into Qt or aiortc was ever checked. --extras drops those three from the override and holds the 70 modules that already disagree with the libraries' signatures in a shrink-only list of their own; the typing-extras job runs it beside the unchanged contract. The docs job builds HTML with -W, and free-threaded-scope runs the variable scope tests on CPython 3.14t.
…n files out of the folder mirror note_received and ClipboardEchoGuard had tests and no callers. The WebRTC and TCP file receivers now tell every folder mirror watching the destination before they rename a finished file into place; the host keeps a clipboard guard per viewer and the viewer one for its host, consulted by the automatic=True form of the clipboard senders. The mirror pushed files mid-write, the receivers' own .part files included: a changed file now has to look the same on two polls, and in-progress names are never mirrored.
The tier is checked against the tree, so three new modules had to be named in it; and the argument walk had grown one branch past the complexity limit.
A read-only directory made the change raise where it used to be applied and the failed save logged. Only a lock that is held by someone else refuses. The single-file format is also recorded among the versioned formats.
A module in neither the strict list nor the baseline is new code nobody asked mypy to check at that level.
…sset transport The only asset transport needed a folder both machines could reach, which two machines that share nothing but the sync server do not have. The server now keeps content-addressed blobs per account at /blobs under the rules /config follows (shared secret, account in the path, size cap checked before the body is read) plus a total quota per account, and HttpAssetTransport is the client. http_client returns the undecoded body on request so a binary download is not mangled.
The offline example had to import the store errors, the concrete adapters, run_sync and the directory transport from utils.config_sync. They are on the facade now, with the names this sweep added; the wire version is exported as CONFIG_SYNC_WIRE_VERSION because a bare WIRE_VERSION there would not say which wire.
# Conflicts: # je_auto_control/gui/script_builder/builder_tab.py
…rame; tests delete their panels A journal candidate replaced the recording open in the editor, or an earlier export, unseen: diff_candidate says what changes, the two tabs show it first and AC_generate_code_from_journal returns it for diff_against. The Config Sync tab remembers its server, user and folders (never the secret). The viewer panel dropped a frame that reached the GUI thread before the connect's own result; a host sends a static screen once, so the window then stayed blank -- the intermittent failure of test_viewer_input_round_trips_to_dispatcher. Tests that built parentless panels left them, and every combo box popup on them, alive for the run.
# Conflicts: # je_auto_control/gui/self_healing_tab.py # test/unit_test/headless/test_gui_slots_menu_audit.py
mypy read the tuple assignment as rebinding the non-optional engine.
…ts and docs The usage listing summed sizes out of dicts typed as object, which the strict tier refuses. resolve_sections and SYNCABLE_SECTIONS join the package exports, and the configuration reference names the blob flags.
# Conflicts: # docs/source/Eng/doc/new_features/v5_features_doc.rst # docs/source/Zh/doc/new_features/v5_features_doc.rst # je_auto_control/__init__.py # je_auto_control/gui/config_sync_tab.py # je_auto_control/gui/remote_desktop/viewer_panel.py # je_auto_control/gui/remote_desktop/webrtc_panel.py # je_auto_control/gui/remote_desktop/webrtc_panel_common.py # je_auto_control/gui/remote_desktop/webrtc_viewer_files.py # je_auto_control/utils/codegen/__init__.py
…the merged tests reading one job's lines
…patibility notes and the gaps still open
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 2669 |
| Duplication | 54 |
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
… mirror test's edit visibly newer, and answer the static-analysis findings
…d in, and record the two limits CI exposed
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



What
Six areas, each merged from its own branch and gated on lint and its tests:
AC_run_stoppable,AC_stop_execution,AC_list_executions).dispose(), a theme switch restyles once, a candidate script shows its diff before replacing anything.Compatibility
Listed in
CHANGELOG.mdunder Unreleased › Changed. The ones most likely to be noticed: config-sync entries written withoutorigin=are stored versioned;RemoteDesktopViewer.send_inputqueues instead of writing;usb_acl.jsoncannot be read by older versions; a read-only MCP server runs no plug-in tool.Checks
ruff,bandit,radon cc -nc, the typing contract (plain and--extras) and the Qt-free import check pass.Still open
Progress.mdlists what is left: work that needs hardware, a real client or a paid API, and decisions for the maintainer.