Skip to content

Convert RuntimeIslandTrait into a RuntimeIslandAnalyzer collaborator (#242) - #1316

Merged
chubes4 merged 1 commit into
trunkfrom
refactor/242-runtime-island-collaborator
Aug 28, 2026
Merged

Convert RuntimeIslandTrait into a RuntimeIslandAnalyzer collaborator (#242)#1316
chubes4 merged 1 commit into
trunkfrom
refactor/242-runtime-island-collaborator

Conversation

@chubes4

@chubes4 chubes4 commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Slice 4 for #242, workstream 1. Follows #1310, #1312, #1315.

This one converts an actual trait, which is the argument the previous three slices were building toward.

Why this trait

RuntimeIslandTrait's own docblock said it best:

Moved verbatim out of HtmlTransformer under #242; behaviour is unchanged.

It was one of the extractions this epic already performed. As a single-consumer trait, that move relocated 404 lines across a file boundary while every method still resolved against the transformer's $this. Nothing left the object scope, nothing became testable, and two agents editing runtime-island logic and transformer logic still collided.

Measured before this PR, 7 of the 8 traits mixed into HtmlTransformer have exactly one consumer, totalling 8,483 lines. Only DomHelpersTrait (4 consumers) is doing real reuse.

What changed

RuntimeIslandAnalyzer runs the same logic against an explicit RuntimeIslandContext of 17 operations. Session-scoped collaborators (FallbackEmitter, RuntimeDomState, RuntimeSelectorState) are resolved through closures because they are per-transform — the analyzer is built once with the transformer but must see the state of the transform currently running.

No forwarding shims. All 61 call sites were migrated to the collaborator:

call sites
HtmlTransformer 41
FormDispatchTrait 12
ElementConversionTrait 6
ButtonLinkDispatchTrait 2

The trait file is deleted, not hollowed out. RUNTIME_TAG_SELECTORS and RUNTIME_APP_ROOT_TOKENS moved onto the analyzer with it.

Behavior preservation

Corpus hash diff on clean trunk before any edit, recaptured after — serializedBlocks SHA-256 plus block/diagnostic/fallback counts:

385 fixtures — DIFFERING: 0 — threw: 0

Fallback and diagnostic counts matter here: this code records runtime islands and preservation fallbacks, so identical counts are what show the diagnostic path is unchanged.

composer test exit 0.

Coverage

tests/unit/runtime-island-analyzer.php — 32 assertions, constructs no transformer. The distinction it pins down was previously unreachable without a full document plus script evidence plus a stylesheet:

  • an id matching a behavioral runtime selector is a DOM target
  • the same id matching only a presentational animation selector is not

That is what keeps CSS-animated decoration out of runtime-island preservation, and it had no direct test. Also covered: the bounded selector grammar (accepted and rejected shapes), data-attribute preservation exclusions for canvas/form/script/form controls, 160-char attribute truncation, app-shell detection needing both multiple targets and a root token, and native retention being limited to semantic wrappers with no interactive descendants.

Impact

trunk after
HtmlTransformer.php 12,619 12,650
single-consumer trait lines 8,483 8,079

HtmlTransformer.php is 31 lines larger — the context factory costs more than the use statement it replaced. The file size is not the metric. 404 lines of runtime-island decision logic left the transformer's object scope and gained 32 assertions.

Cumulative across the four slices: convertElement() 441 → 301, 11 collaborator files, 132 isolation assertions, one trait eliminated.

Scope

Six single-consumer traits remain: StyleResolutionTrait (2,822), FormDispatchTrait (1,865), NavigationStyleProjectionTrait (1,319), SvgMaterializationTrait (983), NavigationToggleSuppressionTrait (781), ElementConversionTrait (594), ButtonLinkDispatchTrait (119). ButtonLinkDispatchTrait is the natural next one — smallest, and it already depends on the analyzer this PR introduces.


AI assistance disclosure: implemented and drafted by Claude Sonnet 4.6 running in Claude Code, operated by @chubes4. The AI captured the pre-change corpus baseline, converted the trait, migrated all 61 call sites, verified byte-identical serializedBlocks and fallback counts across 385 fixtures, and wrote the isolation test. Reviewed by a human before opening.

…242)

RuntimeIslandTrait's own docblock recorded that it had been "moved
verbatim out of HtmlTransformer under #242". As a single-consumer trait
that move changed nothing: every method still resolved against the
transformer's $this, so none of the 404 lines had left the object scope.

The logic now runs against an explicit RuntimeIslandContext. All 61 call
sites across HtmlTransformer and the three dispatch traits were migrated
to the collaborator, so no forwarding shims remain and the trait is
deleted rather than hollowed out.
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