Skip to content

fix(document): invalidate layout cache on registry().register(...) (I3)#113

Merged
DemchaAV merged 1 commit into
developfrom
fix/registry-immutable-view
Jun 1, 2026
Merged

fix(document): invalidate layout cache on registry().register(...) (I3)#113
DemchaAV merged 1 commit into
developfrom
fix/registry-immutable-view

Conversation

@DemchaAV
Copy link
Copy Markdown
Owner

@DemchaAV DemchaAV commented Jun 1, 2026

Summary

Closes the v1.6.7 Track I3 item from the readiness taskboard. Fixes
a latent cache-staleness bug on DocumentSession.registry() and adds
the regression test the taskboard asked for.

The bug

DocumentSession.registry() returned the raw NodeRegistry, so
callers mutating it directly via session.registry().register(...)
left the cached LayoutGraph pointing at the previous compile —
only session.registerNodeDefinition(...) invalidated the cache.
The two entry points had different caching semantics for what is
the same underlying mutation. A subsequent render(...) /
layoutGraph() call would silently return the stale graph routed
through the old definition.

The fix (Variant B — additive, non-breaking)

  • Drop the final modifier from NodeRegistry so DocumentSession
    can install a session-owned subclass. Binary-compatible — japicmp
    reports the change as semver PATCH, compatible bug fix.
  • Add a private InvalidatingNodeRegistry subclass inside
    DocumentSession whose register(...) calls super.register(...)
    followed by invalidate(). The session's registry field is
    initialised with this subclass, so every path that mutates the
    registry goes through cache invalidation (the early
    default-definitions setup is safe — layoutCache is field-
    initialised before the constructor body).
  • Drop the now-redundant explicit invalidate() from
    registerNodeDefinition; the wrapper handles it.
  • Javadoc on registry() and registerNodeDefinition updated to
    reflect the equivalent semantics.

Why Variant B, not Variant A

The taskboard offered "read-only view OR deprecate with invalidate-
on-mutate guard". Variant A (read-only view) would have changed the
registry() return type to an immutable subset, breaking any caller
that already typed it as NodeRegistry. Variant B keeps the public
shape, fixes the bug for the broken call site, and leaves the cleaner
"immutable view" redesign as a 2.0 candidate.

Test plan

  • ./mvnw test -pl . -Dtest=DocumentSessionTest#registryRegisterInvalidatesCachedLayoutFromPreviousCompile
    passes after the fix.
  • ./mvnw verify -pl . -P japicmp1032 tests (+1 new),
    0 failures; japicmp reports semver PATCH (compatible bug
    fix), no incompatible changes vs the v1.6.6 baseline.

DocumentSession.registry() returned the raw NodeRegistry, so callers
mutating it directly via `session.registry().register(...)` left the
cached LayoutGraph pinned to the previous compile. Only the dedicated
session.registerNodeDefinition(...) path called invalidate(); the two
entry points had different caching semantics for what is the same
underlying mutation.

Fix:
- Drop the `final` modifier from NodeRegistry so DocumentSession can
  install a session-owned subclass. Binary-compatible — japicmp
  reports the change as "semver PATCH, compatible bug fix".
- Add a private InvalidatingNodeRegistry subclass inside
  DocumentSession that overrides register(...) to call
  super.register(...) followed by invalidate(). The session
  initialises its registry field with this subclass, so every path
  that mutates the registry goes through cache invalidation —
  including default-definitions setup at construction time
  (layoutCache is field-initialised before the constructor body, so
  the early invalidate() calls are safe no-ops on an empty cache).
- Drop the now-redundant explicit invalidate() from
  registerNodeDefinition; the wrapper handles it.
- Update Javadoc on registry() and registerNodeDefinition to reflect
  the equivalent caching semantics.

Regression test added:
- registryRegisterInvalidatesCachedLayoutFromPreviousCompile in
  DocumentSessionTest. Warms the cache by rendering one badge under
  the default BadgeNodeDefinition, swaps in a replacement definition
  through registry().register(...), and asserts the next render
  reflects the replacement. Before the fix the test fails with
  "alpha" instead of "UPPER-alpha" because the cached LayoutGraph
  is returned unchanged.

Gates: 1032 tests pass; japicmp vs v1.6.6 reports semver PATCH
(compatible bug fix), no incompatible changes.
@DemchaAV DemchaAV merged commit b4720c6 into develop Jun 1, 2026
11 checks passed
@DemchaAV DemchaAV deleted the fix/registry-immutable-view branch June 1, 2026 12:13
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.

1 participant