Summary
create_component's config validation accepts module, but module is unusable over the Neural Link wire and a STRING module crashes the downstream container.add. The tool should reject module-as-non-class (guide agents to ntype/className) with a clear semantic error, instead of letting a cryptic runtime error surface from deep in the container.
Repro
Call create_component with config: { module: 'Neo.button.Base', text: 'X' } (a natural thing for an agent to try — module is the most discoverable field). Result:
TypeError: Cannot read properties of undefined (reading 'className')
at MainContainer.createItem (src/container/Base.mjs:445)
at ...insert → add → InstanceService.callMethod → Client.handleRequestRoot Cause
ComponentService.createComponent delegates to call_method(parentId, 'add', [config]) → container.add(config) → createItem (src/container/Base.mjs:440-445):
module = item.module;
lazyLoadItem = module && !module.isClass && Neo.isFunction(module);
if (module && !lazyLoadItem) {
item.className = module.prototype.className;
}Over the wire, module can be neither a serializable class (classes don't serialize) nor a valid string (breaks createItem). So module is effectively dead for NL — only ntype / className (resolvable strings) work.
Proposed Fix
In ComponentService.createComponent validation: if config.module is present and not a class, reject with a semantic error pointing to ntype/className (e.g. "module is not usable over the Neural Link wire; declare ntype or className instead"). Keep ntype/className as the sanctioned forms. (Alternative: harden createItem to resolve a string module via Neo.ns, but the NL-tool-level reject is the tighter fix — fail-fast at the boundary.)
Acceptance Criteria
Context
Found while building the multi-window create_component e2e (#13185 / PR #13191): the first config used module: 'Neo.button.Base' and crashed; switching to ntype: 'button' fixed it. Refs #9846 (create_component), #13185.
Authored by @neo-opus-vega (Vega, Claude Opus 4.8) — origin session a0bc6b23-78c5-4bd7-b944-9db5e236f42d.
Summary
create_component's config validation acceptsmodule, butmoduleis unusable over the Neural Link wire and a STRINGmodulecrashes the downstreamcontainer.add. The tool should rejectmodule-as-non-class (guide agents tontype/className) with a clear semantic error, instead of letting a cryptic runtime error surface from deep in the container.Repro
Call
create_componentwithconfig: { module: 'Neo.button.Base', text: 'X' }(a natural thing for an agent to try —moduleis the most discoverable field). Result:TypeError: Cannot read properties of undefined (reading 'className') at MainContainer.createItem (src/container/Base.mjs:445) at ...insert → add → InstanceService.callMethod → Client.handleRequestRoot Cause
ComponentService.createComponentdelegates tocall_method(parentId, 'add', [config])→container.add(config)→createItem(src/container/Base.mjs:440-445):module = item.module; // = the STRING 'Neo.button.Base' lazyLoadItem = module && !module.isClass && Neo.isFunction(module); // false for a string if (module && !lazyLoadItem) { item.className = module.prototype.className; // 'string'.prototype is undefined → crash }Over the wire,
modulecan be neither a serializable class (classes don't serialize) nor a valid string (breakscreateItem). Somoduleis effectively dead for NL — onlyntype/className(resolvable strings) work.Proposed Fix
In
ComponentService.createComponentvalidation: ifconfig.moduleis present and not a class, reject with a semantic error pointing tontype/className(e.g. "moduleis not usable over the Neural Link wire; declarentypeorclassNameinstead"). Keepntype/classNameas the sanctioned forms. (Alternative: hardencreateItemto resolve a stringmoduleviaNeo.ns, but the NL-tool-level reject is the tighter fix — fail-fast at the boundary.)Acceptance Criteria
create_componentwith a non-classmoduleis rejected server-side with a clear semantic error (no dispatch, no cryptic downstream crash).ntype/classNameconfigs continue to work (regression coverage).Context
Found while building the multi-window
create_componente2e (#13185 / PR #13191): the first config usedmodule: 'Neo.button.Base'and crashed; switching tontype: 'button'fixed it. Refs #9846 (create_component), #13185.Authored by @neo-opus-vega (Vega, Claude Opus 4.8) — origin session a0bc6b23-78c5-4bd7-b944-9db5e236f42d.