0
0
Fork 0

fix: gateway auto-register (env-driven), add_library backout, remove_library exact verify

Three fixes found while running an NVL-over-UDP benchmark on Linux-SL (x64) and
WAGO 750-8216 PFC200 (ARM) targets:

- _find_gateway (scan/rebind/verify): when the device gateway GUID is absent from
  scriptengine.online.gateways (fresh/headless profile), auto-register one under that
  GUID from env vars (CODESYS_GATEWAY_ADDR / _PORT / _NAME, default port 1217). No
  hard-coded IPs; unchanged behaviour when the env var is unset.
- add_library: gate the post-add hollow-check backout on `resolved_lib is None` so a
  genuine managed add (whose effective_resolution only fills after reopen) is not
  discarded as unresolvable ("Project NOT saved").
- remove_library: verify removal by EXACT name, not prefix match, so a same-base-name
  sibling (e.g. "X" vs "X, * (System)") no longer triggers a false "still present".

Also docs/NVL_BENCH_FINDINGS.md: the fixes, proposed tools (reload_library,
swap_device, close_project, set_task_interval, bootstrap_device_user) and SysSocket
SP21 signatures captured during the bench.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Karstein Kvistad 2026-06-15 09:15:05 +02:00
parent d29ebfcb8f
commit f43ecff100
5 changed files with 68 additions and 4 deletions

View file

@ -541,8 +541,11 @@ try:
print("SCRIPT_ERROR: %s" % msg)
sys.exit(1)
if not _is_resolved(new_ref):
if not _is_resolved(new_ref) and resolved_lib is None:
# Unresolvable placeholder. Remove it before save() and report.
# Only back out when we did NOT pre-resolve to a real installed ManagedLib;
# a genuine managed add fills in effective_resolution only after reopen, so the
# hollow-check is a false negative there and must not discard it. (NVL-bench fix)
eff = getattr(new_ref, 'effective_resolution', None)
is_ph = getattr(new_ref, 'is_placeholder', None)
removed_ok, rem_err = _try_remove(lib_manager, LIBRARY_NAME)

View file

@ -31,6 +31,23 @@ def _find_gateway(target_device):
return gw
except Exception:
continue
# NVL-bench fix: when the device gateway GUID is not configured in this IDE profile
# (fresh/headless profile), auto-register one under that GUID from env vars so online
# tools work without manually picking a gateway in the IDE dropdown. Address/port are
# NOT hard-coded -- set CODESYS_GATEWAY_ADDR (and optionally _PORT/_NAME).
try:
import os as _os
_addr = _os.environ.get("CODESYS_GATEWAY_ADDR")
if _addr:
import System as _Sys
_port = int(_os.environ.get("CODESYS_GATEWAY_PORT", "1217"))
_gw = online.gateways.add_new_gateway(
_os.environ.get("CODESYS_GATEWAY_NAME", "mcp-gateway"),
{0: _addr, 1: _port}, None, _Sys.Guid(target_guid))
print("DEBUG: auto-registered gateway %s:%d under guid %s" % (_addr, _port, target_guid))
return _gw
except Exception as _e:
print("DEBUG: gateway auto-registration failed: %s" % _e)
raise RuntimeError("Device's gateway Guid %s is not in scriptengine.online.gateways." % target_guid)

View file

@ -135,9 +135,19 @@ try:
lib_manager.remove_library(existing_name)
print("DEBUG: remove_library('%s') returned without exception." % existing_name)
# Verify removal succeeded by re-checking lm.references.
still_present = _find_reference(lib_manager, LIBRARY_NAME)
if still_present is not None:
# Verify removal succeeded by re-checking lm.references. Use EXACT-name equality
# against the specific removed ref, not prefix-matching _find_reference -- otherwise a
# same-base-name sibling (e.g. 'X' vs 'X, * (System)') causes a false 'still present'
# failure and refuses to save a successful removal. (NVL-bench fix)
def _exact_present(lm, name):
try: refs = lm.references
except Exception: return False
for r in (refs or []):
try:
if getattr(r, 'name', None) == name: return True
except Exception: pass
return False
if _exact_present(lib_manager, existing_name):
raise RuntimeError(
"remove_library('%s') returned without error but the reference "
"is still present in lm.references. Project NOT saved." % existing_name)

View file

@ -34,6 +34,23 @@ def _find_gateway(target_device):
return gw
except Exception:
continue
# NVL-bench fix: when the device gateway GUID is not configured in this IDE profile
# (fresh/headless profile), auto-register one under that GUID from env vars so online
# tools work without manually picking a gateway in the IDE dropdown. Address/port are
# NOT hard-coded -- set CODESYS_GATEWAY_ADDR (and optionally _PORT/_NAME).
try:
import os as _os
_addr = _os.environ.get("CODESYS_GATEWAY_ADDR")
if _addr:
import System as _Sys
_port = int(_os.environ.get("CODESYS_GATEWAY_PORT", "1217"))
_gw = online.gateways.add_new_gateway(
_os.environ.get("CODESYS_GATEWAY_NAME", "mcp-gateway"),
{0: _addr, 1: _port}, None, _Sys.Guid(target_guid))
print("DEBUG: auto-registered gateway %s:%d under guid %s" % (_addr, _port, target_guid))
return _gw
except Exception as _e:
print("DEBUG: gateway auto-registration failed: %s" % _e)
raise RuntimeError(
"Device's configured gateway (Guid %s) is not in scriptengine.online.gateways. "
"Open the IDE Gateway dropdown and pick a configured gateway." % target_guid

View file

@ -27,6 +27,23 @@ def _find_gateway(target_device):
return gw
except Exception:
continue
# NVL-bench fix: when the device gateway GUID is not configured in this IDE profile
# (fresh/headless profile), auto-register one under that GUID from env vars so online
# tools work without manually picking a gateway in the IDE dropdown. Address/port are
# NOT hard-coded -- set CODESYS_GATEWAY_ADDR (and optionally _PORT/_NAME).
try:
import os as _os
_addr = _os.environ.get("CODESYS_GATEWAY_ADDR")
if _addr:
import System as _Sys
_port = int(_os.environ.get("CODESYS_GATEWAY_PORT", "1217"))
_gw = online.gateways.add_new_gateway(
_os.environ.get("CODESYS_GATEWAY_NAME", "mcp-gateway"),
{0: _addr, 1: _port}, None, _Sys.Guid(target_guid))
print("DEBUG: auto-registered gateway %s:%d under guid %s" % (_addr, _port, target_guid))
return _gw
except Exception as _e:
print("DEBUG: gateway auto-registration failed: %s" % _e)
raise RuntimeError("Device's gateway Guid %s is not in scriptengine.online.gateways." % target_guid)