Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
180 changes: 90 additions & 90 deletions architecture_explore.md

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions benchmarks/mcp_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from je_auto_control.utils.mcp_server.server import MCPServer
from je_auto_control.utils.mcp_server.tools import MCPTool, build_default_tool_registry

_TOOLS_CALL = "tools/call"


def _rpc(server: MCPServer, method: str, params: dict | None = None) -> tuple[dict, float, int]:
request = json.dumps({"jsonrpc": "2.0", "id": 1, "method": method, "params": params or {}})
Expand Down Expand Up @@ -42,14 +44,14 @@ def _mode(tools: list[MCPTool], mode: str, repeats: int) -> dict[str, Any]:
search, enable = [], []
search_bytes = 0
for _ in range(repeats):
_, elapsed, search_bytes = _rpc(server, "tools/call", {
_, elapsed, search_bytes = _rpc(server, _TOOLS_CALL, {
"name": "ac_mcp_tool_search", "arguments": {"query": "screen", "limit": 10}})
search.append(elapsed)
if mode == "progressive":
_, elapsed, _ = _rpc(server, "tools/call", {
_, elapsed, _ = _rpc(server, _TOOLS_CALL, {
"name": "ac_mcp_tools_enable", "arguments": {"names": ["ac_screen_size"]}})
enable.append(elapsed)
_rpc(server, "tools/call", {
_rpc(server, _TOOLS_CALL, {
"name": "ac_mcp_tools_disable", "arguments": {"names": ["ac_screen_size"]}})
return {"count": len(initial["tools"]), "response_json_bytes": wire_bytes,
"descriptor_json_bytes": len(json.dumps(initial["tools"], ensure_ascii=False,
Expand Down
33 changes: 33 additions & 0 deletions docs/updates/2026-11.md
Original file line number Diff line number Diff line change
Expand Up @@ -588,3 +588,36 @@ Index and query commands: [README.md](README.md). New entries go at the end.
variable, some reads need `drive_input`, MCP refusals are terser, and the state machine runs
on the calling executor. `CHANGELOG.md` 1.1.0 lists them.
- **Open items**: none.

## U-20261102-02 · 2026-11-02 · Clear the SonarCloud findings the 1.1.0 release PR reported · #ci #test #quality

- **What**: SonarCloud listed 2,087 open findings in the new code of PR #538
(Release 1.1.0). All are maintainability findings; the quality gate passed.
1,616 were in tests, 471 in the package, scripts, examples and the Android
helper.
- **Result / numbers**:
- S9073 (1,208): every flagged `assert a and b` is one assert per condition,
so a failure names the condition that broke.
- S5778 (400): each `pytest.raises` block holds only the call under test;
setup calls are hoisted, and branching bodies moved into a local function.
- S1192 (292): `scripts/generate_facade_exports.py` emits one constant per
owner module the generated bindings repeat (249 findings); the rest are
named constants. A generated owner named like a credential carries a
`nosec B105` with its reason.
- The remaining package findings are fixed in place: redundant classes in
except tuples (checked against the real MRO), `\d`/`\w` regexes with
`re.ASCII` so they still match ASCII only, nested conditionals and `with`
statements, cognitive-complexity splits, empty blocks given a reason.
The Script Builder table's 34 append runs became `extend`; its built spec
list is byte-identical.
- 33 findings are left as intended and closed on SonarCloud with a reason:
15 S5754 (BaseException handlers that re-raise through a helper or hand
the error to another thread), 12 S5886 (`dataclasses.replace` inferred as
`DataclassInstance`), 4 S7504 (`list()` snapshots of a dict the loop
mutates), 1 S5655 (a writable ctypes buffer) and 1 kotlin S6624 (no
version catalog for the Android helper; the version is locked by
`gradle.lockfile`).
- **Verification**: ruff, bandit, `radon cc -nc`, `generate_facade_exports.py
--check`, `typing_contract_verify.py` (both modes) and the doc-count and
budget tests pass; `architecture_explore.md` line counts re-measured.
- **Open items**: none.
1 change: 1 addition & 0 deletions docs/updates/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ In the same commit: delete the item from `Progress.md`, add a `#done` entry here

| ID | Date | Title | Tags | Batch |
|---|---|---|---|---|
| U-20261102-02 | 2026-11-02 | Clear the SonarCloud findings the 1.1.0 release PR reported | #ci #test #quality | [2026-11](2026-11.md) |
| U-20261101-17 | 2026-11-01 | Patch the dependencies named in Dependabot security alerts | #bugfix #deps #security #ci | [2026-11](2026-11.md) |
| U-20261101-16 | 2026-11-01 | Accept either refusal when a revocation races the lease watch | #incident #ci #test | [2026-11](2026-11.md) |
| U-20261101-15 | 2026-11-01 | Observe only the maintenance call's own writes in the receipt test | #incident #ci #test | [2026-11](2026-11.md) |
Expand Down
8 changes: 5 additions & 3 deletions examples/sync_assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@

from je_auto_control import DirectoryAssetTransport, build_asset_manifest, sync_assets

_TEMPLATE = 'template.bin'


def main() -> None:
"""Round-trip a script and referenced template as inert files with no device or network calls."""
with TemporaryDirectory(prefix='autocontrol-assets-') as temporary:
root = Path(temporary)
source = root / 'source'
source.mkdir()
(source / 'template.bin').write_bytes(b'controlled-template-bytes')
actions = [['AC_locate', {'template': 'template.bin'}]]
(source / _TEMPLATE).write_bytes(b'controlled-template-bytes')
actions = [['AC_locate', {'template': _TEMPLATE}]]
(source / 'script.json').write_text(json.dumps(actions), encoding='utf-8')
manifest = build_asset_manifest(source, ['script.json', 'template.bin'])
manifest = build_asset_manifest(source, ['script.json', _TEMPLATE])
transport = DirectoryAssetTransport(source, root / 'cache')
result = sync_assets(manifest, transport)
repeated = sync_assets(manifest, transport)
Expand Down
15 changes: 9 additions & 6 deletions examples/sync_profile_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@
from examples.sync_referenced_assets import _template_png
from je_auto_control import LoadedSyncProfile, SyncReference, SyncWorkspace, load_sync_profile

_SCRIPT = 'demo.json'
_TEMPLATE_ASSET = 'assets/template.png'


def configuration(root: Path) -> dict[str, object]:
"""Select seven temporary native definition domains and bind one explicit image asset."""
image = root / 'selected-template.png'
image.write_bytes(_template_png())
definitions: dict[str, object] = {
'scripts': {'demo.json': {'actions': [['AC_locate_image_center', {'image': str(image)}]]}},
'scripts': {_SCRIPT: {'actions': [['AC_locate_image_center', {'image': str(image)}]]}},
'locators': {'login': {'name': 'Sign in', 'role': 'button'}},
'hotkeys': {'demo-key': {'combo': 'ctrl+alt+1', 'script_path': 'scripts/demo.json'}},
'triggers': {'demo-watch': {'kind': 'file', 'script_path': 'scripts/demo.json', 'repeat': False,
Expand All @@ -28,8 +31,8 @@ def configuration(root: Path) -> dict[str, object]:
{'kind': kind, 'state_path': str(root / 'adapters.sqlite3'), 'source': {'records': values}}
for kind, values in definitions.items()]
profiles[0]['bindings'] = {
'fields': {'demo.json': {'/actions/0/1/image': SyncReference('local', 'button').to_dict()}},
'local_values': {'button': str(image)}, 'assets': {'button': 'assets/template.png'}}
'fields': {_SCRIPT: {'/actions/0/1/image': SyncReference('local', 'button').to_dict()}},
'local_values': {'button': str(image)}, 'assets': {'button': _TEMPLATE_ASSET}}
return {'schema_version': 1, 'endpoint': 'https://controlled.invalid', 'user_id': 'example',
'outbox_path': str(root / 'outbox.sqlite3'), 'profiles': profiles}

Expand All @@ -42,16 +45,16 @@ def workflow(root: Path) -> dict[str, object]:
original = _digests(generation.directory)
loaded: LoadedSyncProfile = load_sync_profile(generation.directory, root / 'workspaces',
expected_digest=generation.manifest_digest)
actions = loaded.script_actions('demo.json')
actions = loaded.script_actions(_SCRIPT)
arguments = cast(dict[str, object], cast(list[object], actions[0])[1])
assert arguments['image'] == str(loaded.directory / 'assets/template.png')
assert arguments['image'] == str(loaded.directory / _TEMPLATE_ASSET)
assert loaded.hotkeys[0].enabled is False and loaded.triggers[0].enabled is False
assert loaded.address_book.list_entries()[0]['host_id'] == 'example-host'
loaded.locators.save('cancel', name='Cancel')
assert 'cancel' in loaded.locators.all()
assert original == _digests(generation.directory)
return dict(loaded.to_dict(), immutable_source_unchanged=True, executed=0, listeners_started=0,
external_calls=0, image_bytes=(loaded.directory / 'assets/template.png').stat().st_size)
external_calls=0, image_bytes=(loaded.directory / _TEMPLATE_ASSET).stat().st_size)


def _digests(directory: Path) -> dict[str, str]:
Expand Down
8 changes: 5 additions & 3 deletions examples/sync_referenced_assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
from je_auto_control import CausalConfigStore, SyncAssetStore, SyncReference, SyncWorkspace
from je_auto_control.utils.path_guard import PathPolicy

_SCRIPT_NAME = 'demo.json'


def configuration(root: Path, endpoint: str, *, sender: bool) -> dict[str, object]:
"""Select an exact native action file and bind one image argument to a private asset alias."""
Expand All @@ -20,9 +22,9 @@ def configuration(root: Path, endpoint: str, *, sender: bool) -> dict[str, objec
image = root / 'template.png'
image.write_bytes(_template_png())
actions = [['AC_locate_image_center', {'image': str(image)}]]
(root / 'demo.json').write_text(json.dumps(actions), encoding='utf-8')
source = {'path': str(root), 'paths': ['demo.json']}
bindings = {'fields': {'demo.json': {'/actions/0/1/image': SyncReference('local', 'button').to_dict()}},
(root / _SCRIPT_NAME).write_text(json.dumps(actions), encoding='utf-8')
source = {'path': str(root), 'paths': [_SCRIPT_NAME]}
bindings = {'fields': {_SCRIPT_NAME: {'/actions/0/1/image': SyncReference('local', 'button').to_dict()}},
'local_values': {'button': str(image)}, 'assets': {'button': 'assets/template.png'}}
return {'schema_version': 1, 'endpoint': endpoint, 'user_id': 'example',
'outbox_path': str(root / 'outbox.sqlite3'), 'asset_cache_path': str(root / 'cache.sqlite3'),
Expand Down
Loading
Loading