Skip to content

fix(manager): isA() walks past component.Base to any ancestor (#19130) - #19154

Merged
tobiu merged 1 commit into
neomjs:devfrom
drakeo338:claude/19130-fix
Sep 24, 2026
Merged

tobiu merged 1 commit into
neomjs:devfrom
drakeo338:claude/19130-fix

Conversation

@drakeo338

Copy link
Copy Markdown

Does this PR resolve an issue? (Required)

Resolves #19130

isA() stopped walking as soon as it reached Neo.component.Base unless the ancestor asked for was Neo.core.Base, which assumed component.Base extends core.Base directly. Since Neo.component.Abstract now sits between them, isA('Neo.button.Base', 'Neo.component.Abstract') returned false. This drops that short-circuit so the walk continues to core.Base like any other chain, and adds a ClassHierarchy unit spec; two of its tests fail on dev and pass with the fix.

Written with Claude Code (Claude Opus).

What kind of change does this PR introduce? (check at least one)

  • Bugfix
  • Feature
  • Code style update
  • Refactor
  • Build-related changes
  • Other, please describe:

Does this PR introduce a breaking change? (check one)

  • Yes
  • No

The PR fulfills this requirement:

  • It's submitted to the dev branch, not the main branch

…#19130)

isA() short-circuited to false as soon as the walk reached Neo.component.Base
and the requested ancestor was not Neo.core.Base. That encoded an assumption
that component.Base extends core.Base directly, which stopped being true once
Neo.component.Abstract was inserted between them: isA('Neo.button.Base',
'Neo.component.Abstract') returned false for every component subclass.

Drop the short-circuit. The loop already ends at Neo.core.Base, so the walk
now sees every class between a descendant and the root, whatever sits there.
The memoization is unchanged.

The new spec pins the parentClassName chain, the ancestor case that used to
fail, a set of non-ancestor cases and the isAQueryMap behaviour.

@neo-fable neo-fable left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Micro-Review

Opening: Thank you — specifically for removing the false short-circuit instead of special-casing Neo.component.Abstract, and for the memoization test that pins the answer cache the ticket asked you to keep. To watch the engine you just fixed run, set up the Engine from a clone — three commands — then open apps/workstation and drag a tab out of the browser; why that works. Your agent needs neither our Knowledge Base nor Memory Core — neo-agent-skills is on npm.

Class: contained — a curated good-first-issue fix (#19130) in one manager method plus its unit spec; the concept (walk the registered parentClassName chain to Neo.core.Base) is the ticket's, and the diff teaches no new one.

Verdict: Approved

Glance: The claim holds against the source: Neo.component.Base extends Neo.component.Abstract, which extends Neo.core.Base, so the removed guard ("component.Base directly extends core.Base") answered false for any ancestor above component.Base other than core.Base. With it gone the walk ends at core.Base as before and the cache is written after the loop, unchanged. Because the ticket asked for the failing output and the body summarises it instead, I ran the new spec myself: against dev's ClassHierarchy.mjs it reads 2 failed / 4 passed ("isA() finds ancestors that sit between component.Base and core.Base" and "isA() memoizes its results", the second because the cached Abstract answer was false); with this head's ClassHierarchy.mjs it reads 6 passed. CI is green at 4a495ae4d6 (unit, components, e2e shards), MERGEABLE/CLEAN. The ticket's "Done when" list is covered: self → true, direct parent, transitive ancestor, unrelated and unknown → false, and the cache — the "second identical call" item is witnessed through the map entries rather than a second call's return value, which pins the same fact. One thing I looked for and did not find: any other caller relying on the old early false (a git grep isA( over src shows lookups by descendant/ancestor only, none keyed on the shortcut).

Findings: None. No required actions — eligible for human merge.

  • Origin Session ID: 091a1019-7f73-4117-b281-99190ceb224f

🖖 Mnemosyne · Fable 5.1 · Claude Code

@tobiu
tobiu merged commit 0c83936 into neomjs:dev Sep 24, 2026
35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ClassHierarchy.isA answers false for ancestors above Neo.component.Base

3 participants