- Severity-bitmask long crash repro confirmed end-to-end via SymTest.project
(PLCWinNT, device not installed -> 17 ERROR messages, 2 WARNING, 34 total
through get_compile_messages with _coerce_for_json -- no TypeError).
- MCPTest2/Application/Symbols cleanup recorded.
- 5 deferred symbol-config tools still pending a build-clean project.
5 of 10 symbol-config tools verified end-to-end on SP22 P1 against
MCPTest2: find/create/get_settings/set_settings/list_configured_symbols.
3 timed out and crashed CODESYS with exit 0xFFFFFFFF (set_signature_
access_bulk, export_symbol_xsd, indirectly set_symbol_access) because
get_all_signatures(True) and get_symbol_configuration_xsd() trigger an
application.build() that aborts on this project (empty PLC_PRG body,
IoDrvGPIO managed library). list_all_signatures itself ran cleanly but
returned 0 -- not a crash, just a build short-circuit on an empty POU.
Re-run on a project with a real, build-clean PLC_PRG body. Tool code
itself non-regressing -- the 5 read/write paths that don't trigger a
build all worked.
vitest tests/integration/e2e.test.ts:
- 10 new template-prep assertions, one per Symbol Configuration tool.
Each asserts no leftover {PLACEHOLDER} in the rendered script and
that the relevant CODESYS API method names appear (get_all_signatures,
application.create_symbol_config, configured_access, etc.).
- Drive-by: fix the existing add_library e2e test that was missing the
ALLOW_UNRESOLVED placeholder (added when the resolution gate landed
in d414c77). Test was previously failing on /\{[A-Z_]+\}/ regex.
Suite is now 107/107 green (excluding the orphan .worktrees/phobics-tui
suite that's been failing pre-this-change).
README.md:
- Tool count 31 -> 41.
- New "Symbol Configuration Tools" section under Library Management
with one row per tool.
- Project-structure tool count footnote updated.
docs/function-test-2026-04-28.md:
- Append "Symbol Configuration tools (added 2026-04-28 evening)" block
with a per-tool vitest/live status grid.
- Live SP22 column is deferred: the MCP tool list is negotiated at
Claude Code session start and doesn't refresh mid-session, so the
new tools aren't callable in the session that built them. Document
the round-trip cycle so a fresh session can run it.
- Note the SymbolAccess enum-value probe risk per the plan
(docs/superpowers/plans/2026-04-28-symbol-config-tools.md).
Python 3 ast.parse run against all 10 new + 1 helper scripts -- 11/11
parsed cleanly (catches the obvious IronPython 2.7 syntax issues that
Py3 would also flag).
Two real bugs surfaced today:
1. compile_project / get_compile_messages reported 0 errors even when
the IDE's download path saw real compile errors. Root cause: both
scripts queried get_message_objects() with no category arg, which
returns only the IDE's last-active message tab (typically "Other"
for the WATCHER startup messages). Build/Code-Generation errors
live in a different category and were never queried.
Fix: enumerate script_engine.system.message_categories AND probe a
set of well-known V3.5 category GUIDs (Compile, Build, Online,
LibMan); query target_app.get_message_objects(cat) and
system.get_message_objects(cat) per category; aggregate dedup'd
entries (severity, text, object, line). Each entry now carries its
originating category label.
2. add_library's post-add _is_resolved() check trusted is_placeholder
== False as proof of resolution. CODESYS lets you call
add_placeholder(name_str) for a name that is NOT in the installed
Library Repository -- the resulting reference reports
is_placeholder=False yet has empty effective_version and the IDE
shows it with a yellow-warning triangle in Library Manager (no
Effective Version column populated). Karstein hit this with
"OPC UA PubSub SL": list_project_libraries reported it as
[managed] but compile failed because the IDE couldn't resolve it.
Fix: for the non-placeholder branch, probe effective_version /
resolved_version / version / resolved_library / managed_library /
library. ALL must be empty/None for the ref to be considered
hollow. Logs a DEBUG with the ref's attribute list so the next
such bug is diagnosable without source spelunking.
Bumped 0.6.2 -> 0.6.3.