diff --git a/docs/architecture/playground-ownership.md b/docs/architecture/playground-ownership.md index a054844b..cf53cc5b 100644 --- a/docs/architecture/playground-ownership.md +++ b/docs/architecture/playground-ownership.md @@ -2,6 +2,7 @@ Status: Accepted Date: 2026-08-13 +Revisited: 2026-09-03 Roadmap item: `CMUI-148` ## Decision @@ -15,14 +16,52 @@ No `ui-playground` package, `CmPlayground` component, Annabel Razor adapter, or is added to the CodeMonster UI 1.0 topology. The existing packages remain supported under the VueForge migration and maintenance policy and may run alongside CodeMonster UI. +## Why this held up under the same test that moved icons and layouts + +By 2026-09-03 the icon and layout lines had each looked hard to port and turned out portable once +read closely enough — icons looked like a 2,135-line rendering engine that would have to be +duplicated in PHP and turned out to be static data once precomputed. That made "retained" worth +re-checking rather than trusting as a standing label: was Playground actually the same kind of +question, just not yet worked through? + +It is not, and the code says why rather than a category label asserting it. +`packages/playground-core/src/typescriptWorker.js` transpiles with a real `Worker`: + +```js +self.addEventListener('message', (event) => { + const request = event.data; + // ... transpiles request.sources with the TypeScript compiler ... + self.postMessage({ type: 'result', id: request.id, outputs: [] }); +}); +``` + +`packages/playground-core/src/runtimes/browserRuntime.ts` runs the result in a sandboxed frame: + +```ts +export function runInIframe(iframe: HTMLIFrameElement, html: string): void { + iframe.setAttribute('sandbox', 'allow-scripts'); + iframe.srcdoc = html; +} +``` + +`Worker` and `HTMLIFrameElement` are not a framework choice Vue happened to make; they are what a +live, reactive, sandboxed preview of arbitrary just-typed code requires, and nothing server-rendered +can supply either. A PHP request answers one request with one response; it cannot host a running +session watching for the next keystroke. An icon's output is a pure function of three known values, +computable once and shipped as data. Playground's output is a pure function of whatever a person is +typing at this instant — not a harder version of the same precomputation problem, a different one. + +Confirmed rather than assumed: nothing in `ui-vue`, `ui-layouts`, `ui-runtime`, or `ui-icons` +depends on any of the three Playground packages. + ## Reviewed package boundaries -| Package | Responsibility | Ownership outcome | -| --- | --- | --- | -| `@codemonster-ru/vueforge-playground-core` | Framework-independent session state, TypeScript worker, module compilation, iframe document generation, and preview messaging | Retained Playground runtime product | -| `@codemonster-ru/vueforge-playground` | Vue editor/preview UI, component-preview mode, theme bridging, console/files/actions regions, and Playground session orchestration | Retained Vue Playground adapter | -| `@codemonster-ru/vueforge-playground-vite-plugin` | Build-time virtual modules backed by explicitly configured local source files | Retained Playground build integration | -| `examples/vue` | Repository showcase and manual integration consumer | Application; migrated separately by `CMUI-153` | +| Package | Responsibility | Ownership outcome | +| ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | +| `@codemonster-ru/vueforge-playground-core` | Framework-independent session state, TypeScript worker, module compilation, iframe document generation, and preview messaging | Retained Playground runtime product | +| `@codemonster-ru/vueforge-playground` | Vue editor/preview UI, component-preview mode, theme bridging, console/files/actions regions, and Playground session orchestration | Retained Vue Playground adapter | +| `@codemonster-ru/vueforge-playground-vite-plugin` | Build-time virtual modules backed by explicitly configured local source files | Retained Playground build integration | +| `examples/vue` | Repository showcase and manual integration consumer | Application; migrated separately by `CMUI-153` | The framework-independent core remains outside `ui-runtime`. The latter enhances canonical CodeMonster UI DOM with small controllers; it must not become a compiler, worker host, module diff --git a/migration/codemonster-ui-maturity-backlog.json b/migration/codemonster-ui-maturity-backlog.json index 1c7154a4..9a88d3c0 100644 --- a/migration/codemonster-ui-maturity-backlog.json +++ b/migration/codemonster-ui-maturity-backlog.json @@ -162,15 +162,15 @@ }, { "package": "@codemonster-ru/vueforge-playground", - "reason": "Executable preview infrastructure is a retained Vue product rather than design-system UI." + "reason": "Runs a live, sandboxed browser preview of arbitrary just-typed code -- Worker-based TypeScript transpilation and an HTMLIFrameElement sandbox, neither of which a server request/response can supply. Nothing in the CodeMonster line depends on it. See docs/architecture/playground-ownership.md." }, { "package": "@codemonster-ru/vueforge-playground-core", - "reason": "Browser compilation sessions remain framework-independent Playground infrastructure." + "reason": "The Worker transpiler and iframe runtime behind the Playground UI; browser-only by the primitives it uses, not by framework choice. See docs/architecture/playground-ownership.md." }, { "package": "@codemonster-ru/vueforge-playground-vite-plugin", - "reason": "Virtual demo module generation remains build-tool infrastructure for the retained Playground product." + "reason": "A Vite/Rollup build plugin that turns demo files into virtual modules for the retained Playground product; build-tool infrastructure with no PHP analog. See docs/architecture/playground-ownership.md." } ] } diff --git a/scripts/ci/frozen-showcase.mjs b/scripts/ci/frozen-showcase.mjs index ae1ba539..110191f7 100644 --- a/scripts/ci/frozen-showcase.mjs +++ b/scripts/ci/frozen-showcase.mjs @@ -37,10 +37,7 @@ export function findFrozenShowcaseChanges(changedPaths) { * describes and rot into a list nobody reads. The visual gate remains the authority on whether * pixels actually moved; this only records that someone looked. */ -export const acknowledgedChanges = { - 'examples/vue/src/sections/icons/IconsShowcase.vue': - 'Import path only: the VueForge icons package moved to packages/vueforge-icons so the CodeMonster line could take the packages/icons name. The imported file is unchanged, so nothing renders differently.', -}; +export const acknowledgedChanges = {}; /** Reports acknowledged paths that no longer differ, so the list cannot outlive its reasons. */ export function findStaleAcknowledgements(changedPaths, acknowledged = acknowledgedChanges) {