Drop wall + fence feature flags: register unconditionally; remove verification logs
Parity comparison against deployed prod is now cleaner than juggling
env-var flag toggles locally. Both kinds enter builtinPlugin.nodes
unconditionally; the Phase 0 dispatch shims (<LegacySystem kind="X">
wrappers + NodeRenderer's registry-first branch) handle the cutover.
Files deleted:
- packages/nodes/src/wall/feature-flag.ts
- packages/nodes/src/fence/feature-flag.ts
Files changed:
- packages/nodes/src/index.ts: drops isWallRegistryEnabled /
isFenceRegistryEnabled gates; wallDefinition + fenceDefinition
land directly in builtinPlugin.nodes.
- packages/nodes/src/{wall,fence}/index.ts: drop the flag re-export.
- packages/nodes/src/{wall,fence}/renderer.tsx: drop the one-shot
verification console.info. Same for the system.tsx wrappers.
- packages/viewer/src/components/renderers/{wall,fence}/{wall,fence}-
renderer.tsx: drop the paired [X:legacy] verification logs (no
longer comparing flag-toggled paths).
Net DX: no env var to remember when starting `bun dev:community`. To
A/B test, compare against editor.pascal.app deployed prod.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
9883f1cdc1
commit
6a4de8cff5
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Feature flag for the registry-driven fence.
|
||||
*
|
||||
* Same pattern as wall (Phase 3) and spawn (Phase 2): with the flag on,
|
||||
* `fenceDefinition` is appended to `builtinPlugin.nodes` and the Phase 0
|
||||
* dispatch shims hand fence over to the registry. With the flag off,
|
||||
* the legacy fence paths run unchanged.
|
||||
*
|
||||
* Drops the moment Phase 5 fence parity is signed off.
|
||||
*/
|
||||
export const isFenceRegistryEnabled = (): boolean => {
|
||||
return process.env.NEXT_PUBLIC_USE_REGISTRY_FOR_FENCE === 'true'
|
||||
}
|
||||
@@ -1,3 +1,2 @@
|
||||
export { fenceDefinition } from './definition'
|
||||
export { isFenceRegistryEnabled } from './feature-flag'
|
||||
export { FenceNode } from './schema'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { type FenceNode, useRegistry, useScene } from '@pascal-app/core'
|
||||
import { DEFAULT_STAIR_MATERIAL, useNodeEvents } from '@pascal-app/viewer'
|
||||
import { useEffect, useLayoutEffect, useMemo, useRef } from 'react'
|
||||
import { useLayoutEffect, useMemo, useRef } from 'react'
|
||||
import type { Mesh } from 'three'
|
||||
|
||||
/**
|
||||
@@ -17,8 +17,6 @@ import type { Mesh } from 'three'
|
||||
* Material is `DEFAULT_STAIR_MATERIAL` (legacy reuse; fence and stairs
|
||||
* share the wood-tone preset).
|
||||
*/
|
||||
let didLogFirstRegistryFenceMount = false
|
||||
|
||||
const FenceRenderer = ({ node }: { node: FenceNode }) => {
|
||||
const ref = useRef<Mesh>(null!)
|
||||
const handlers = useNodeEvents(node, 'fence')
|
||||
@@ -29,14 +27,6 @@ const FenceRenderer = ({ node }: { node: FenceNode }) => {
|
||||
useScene.getState().markDirty(node.id)
|
||||
}, [node.id])
|
||||
|
||||
useEffect(() => {
|
||||
if (didLogFirstRegistryFenceMount) return
|
||||
didLogFirstRegistryFenceMount = true
|
||||
console.info(
|
||||
'[fence:registry] first registry-driven FenceRenderer mounted — legacy FenceRenderer is NOT in use',
|
||||
)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<mesh
|
||||
castShadow
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { FenceSystem } from '@pascal-app/viewer'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
/**
|
||||
* Registry-driven fence system bundle.
|
||||
@@ -10,8 +9,7 @@ import { useEffect } from 'react'
|
||||
* via `RegisteredSystems` when fence is registry-driven. The legacy
|
||||
* `<LegacySystem kind="fence">` wrapper around `<FenceSystem />` in
|
||||
* `viewer/components/viewer/index.tsx` short-circuits whenever
|
||||
* `nodeRegistry.has('fence')` is true — same pattern wall used in
|
||||
* milestone B.
|
||||
* `nodeRegistry.has('fence')` is true — same pattern wall uses.
|
||||
*
|
||||
* Phase 6 deletes the legacy mount point; until then this bundle is the
|
||||
* single mount surface for fence's per-frame work when registry-driven.
|
||||
@@ -22,13 +20,6 @@ import { useEffect } from 'react'
|
||||
* the rebuild loop and this bundle can be deleted.
|
||||
*/
|
||||
const FenceSystems = () => {
|
||||
useEffect(() => {
|
||||
console.info('[fence:registry] system bundle mounted — registry path active')
|
||||
return () => {
|
||||
console.info('[fence:registry] system bundle unmounted')
|
||||
}
|
||||
}, [])
|
||||
|
||||
return <FenceSystem />
|
||||
}
|
||||
|
||||
|
||||
+10
-24
@@ -1,8 +1,8 @@
|
||||
import type { AnyNodeDefinition, Plugin } from '@pascal-app/core'
|
||||
import { fenceDefinition, isFenceRegistryEnabled } from './fence'
|
||||
import { fenceDefinition } from './fence'
|
||||
import { shelfDefinition } from './shelf'
|
||||
import { spawnDefinition } from './spawn'
|
||||
import { isWallRegistryEnabled, wallDefinition } from './wall'
|
||||
import { wallDefinition } from './wall'
|
||||
|
||||
/**
|
||||
* Built-in plugin bundling every node kind shipped with the Pascal editor.
|
||||
@@ -15,35 +15,21 @@ import { isWallRegistryEnabled, wallDefinition } from './wall'
|
||||
* `loadPlugin` call path. This is intentional: the API is stress-tested
|
||||
* by built-ins before any third-party plugin lands.
|
||||
*
|
||||
* Status by kind:
|
||||
* - **shelf**: brand-new kind, registry-driven, no legacy. Registered
|
||||
* unconditionally.
|
||||
* - **spawn**: migrated to the registry path during Phase 2. Legacy
|
||||
* SpawnRenderer / SpawnTool files still present in viewer/editor but
|
||||
* short-circuited by the Phase 0 shims. Registered unconditionally.
|
||||
* - **wall**: registry-driven behind `NEXT_PUBLIC_USE_REGISTRY_FOR_WALL`.
|
||||
* Phase 3 stress test; flag drops when fixture parity signs off.
|
||||
* - **fence**: registry-driven behind `NEXT_PUBLIC_USE_REGISTRY_FOR_FENCE`.
|
||||
* First Phase 5 batch-migration kind. Same shape as wall (thin
|
||||
* renderer + system re-export); pure geometry / floor-plan / tool
|
||||
* affordance ports as later milestones.
|
||||
* All four current kinds are registered unconditionally. Parity is
|
||||
* verified by comparing against deployed production rather than an
|
||||
* in-app env-var flag toggle. Legacy paths still exist in `viewer/` and
|
||||
* `editor/` for kinds undergoing migration; they short-circuit via the
|
||||
* Phase 0 `<LegacySystem>` wrapper + `NodeRenderer`'s registry-first
|
||||
* dispatch. Phase 6 deletes the legacy paths.
|
||||
*/
|
||||
const wallEntries: AnyNodeDefinition[] = isWallRegistryEnabled()
|
||||
? [wallDefinition as unknown as AnyNodeDefinition]
|
||||
: []
|
||||
|
||||
const fenceEntries: AnyNodeDefinition[] = isFenceRegistryEnabled()
|
||||
? [fenceDefinition as unknown as AnyNodeDefinition]
|
||||
: []
|
||||
|
||||
export const builtinPlugin: Plugin = {
|
||||
id: 'pascal:core',
|
||||
apiVersion: 1,
|
||||
nodes: [
|
||||
shelfDefinition as unknown as AnyNodeDefinition,
|
||||
spawnDefinition as unknown as AnyNodeDefinition,
|
||||
...wallEntries,
|
||||
...fenceEntries,
|
||||
wallDefinition as unknown as AnyNodeDefinition,
|
||||
fenceDefinition as unknown as AnyNodeDefinition,
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Feature flag for the registry-driven wall.
|
||||
*
|
||||
* Wall is the Phase 3 stress test — its scope is large enough (5 affordances,
|
||||
* miter cascade, host re-anchor, slab/zone dirty propagation, undo
|
||||
* correctness) that flipping it on uncontrolled would risk silently
|
||||
* regressing every wall scene in production.
|
||||
*
|
||||
* Pattern mirrors `NEXT_PUBLIC_USE_REGISTRY_FOR_SPAWN` used during the
|
||||
* Phase 2 spawn migration: when ON, `wallDefinition` is appended to
|
||||
* `builtinPlugin.nodes` and the Phase 0 dispatch shims take over wall
|
||||
* rendering / tooling. When OFF, the legacy wall paths run unchanged.
|
||||
*
|
||||
* Literal `process.env.NEXT_PUBLIC_USE_REGISTRY_FOR_WALL` access is required
|
||||
* — Next.js only inline-substitutes literal env reads, so `process.env[name]`
|
||||
* with a variable would always read undefined in client bundles.
|
||||
*
|
||||
* Drop this file the moment Phase 3 parity is signed off and wall is
|
||||
* registered unconditionally.
|
||||
*/
|
||||
export const isWallRegistryEnabled = (): boolean => {
|
||||
return process.env.NEXT_PUBLIC_USE_REGISTRY_FOR_WALL === 'true'
|
||||
}
|
||||
@@ -1,3 +1,2 @@
|
||||
export { wallDefinition } from './definition'
|
||||
export { isWallRegistryEnabled } from './feature-flag'
|
||||
export { WallNode } from './schema'
|
||||
|
||||
@@ -14,8 +14,7 @@ import { BufferGeometry, Float32BufferAttribute, type Mesh } from 'three'
|
||||
* items) inside the wall's local frame.
|
||||
*
|
||||
* Behaviorally identical to the legacy `WallRenderer` in
|
||||
* `@pascal-app/viewer/components/renderers/wall/wall-renderer.tsx` — same
|
||||
* placeholder geometry, same material lookup, same dirty-mark on mount.
|
||||
* `@pascal-app/viewer/components/renderers/wall/wall-renderer.tsx`.
|
||||
* Phase 6 deletes the legacy file; until then both coexist and the Phase 0
|
||||
* shims pick which one renders based on `nodeRegistry.has('wall')`.
|
||||
*
|
||||
@@ -25,12 +24,6 @@ import { BufferGeometry, Float32BufferAttribute, type Mesh } from 'three'
|
||||
* That decision lands in a later milestone; for now the system retains
|
||||
* ownership of the rebuild loop.
|
||||
*/
|
||||
// Phase 3 verification — set once when the first registry-driven wall
|
||||
// renderer mounts. Stops the log firing per wall (a scene with 200 walls
|
||||
// would spam the console). Drop alongside the feature flag at Phase 3
|
||||
// sign-off.
|
||||
let didLogFirstRegistryWallMount = false
|
||||
|
||||
function createEmptyWallGeometry(): BufferGeometry {
|
||||
const geometry = new BufferGeometry()
|
||||
geometry.setAttribute('position', new Float32BufferAttribute([], 3))
|
||||
@@ -55,14 +48,6 @@ const WallRenderer = ({ node }: { node: WallNode }) => {
|
||||
useScene.getState().markDirty(node.id)
|
||||
}, [node.id])
|
||||
|
||||
useEffect(() => {
|
||||
if (didLogFirstRegistryWallMount) return
|
||||
didLogFirstRegistryWallMount = true
|
||||
console.info(
|
||||
'[wall:registry] first registry-driven WallRenderer mounted — legacy WallRenderer is NOT in use',
|
||||
)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
placeholderGeometry.dispose()
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
'use client'
|
||||
|
||||
import { WallCutout, WallSystem } from '@pascal-app/viewer'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
/**
|
||||
* Registry-driven wall system bundle.
|
||||
*
|
||||
* Wall has two per-frame concerns that need to mount when the kind is
|
||||
* Wall has two per-frame concerns that mount when the kind is
|
||||
* registry-driven:
|
||||
*
|
||||
* - **`WallSystem`** — reads `dirtyNodes`, batches by level, runs
|
||||
@@ -17,28 +16,16 @@ import { useEffect } from 'react'
|
||||
* - **`WallCutout`** — cutaway-mode hide/show logic based on camera
|
||||
* direction and `frontSide` / `backSide` interior/exterior tags.
|
||||
*
|
||||
* Both already live in `@pascal-app/viewer` and are wrapped in
|
||||
* `<LegacySystem kind="wall">` at the legacy mount point. When the
|
||||
* `wall` kind appears in `nodeRegistry`, those wrappers short-circuit and
|
||||
* this bundle takes over the mount via `RegisteredSystems`. The
|
||||
* components themselves are unchanged — no logic duplication during
|
||||
* Phase 3.
|
||||
* Both live in `@pascal-app/viewer` and are wrapped in
|
||||
* `<LegacySystem kind="wall">` at the legacy mount point. With wall
|
||||
* registered, those wrappers short-circuit and this bundle takes over
|
||||
* the mount via `RegisteredSystems`. The components themselves are
|
||||
* unchanged — no logic duplication.
|
||||
*
|
||||
* Phase 6 deletes the legacy `<LegacySystem kind="wall">` wrappers; until
|
||||
* then this file is the single mount surface for wall's per-frame work.
|
||||
*/
|
||||
const WallSystems = () => {
|
||||
// Phase 3 verification log — confirms the registry took over the wall
|
||||
// dispatch. Fires once when RegisteredSystems lazy-loads this bundle (so
|
||||
// exactly once per viewer mount when NEXT_PUBLIC_USE_REGISTRY_FOR_WALL=true).
|
||||
// Drop alongside the feature flag at Phase 3 sign-off.
|
||||
useEffect(() => {
|
||||
console.info('[wall:registry] system bundle mounted — registry path active')
|
||||
return () => {
|
||||
console.info('[wall:registry] system bundle unmounted')
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<WallSystem />
|
||||
|
||||
Reference in New Issue
Block a user