Vidu rejects generic video reference payloads, while the canvas preview also needs to keep long prompt text inside the prompt node bounds. This keeps provider-specific video reference fields for Vidu and constrains long prompt previews without changing the Seedance media field mapping.
Constraint: Vidu/NewApiWG expects reference_video_urls for video-reference generation.
Rejected: Change all video providers to reference_* fields | Seedance has existing coverage and logs using generic images/videos/audios.
Confidence: high
Scope-risk: narrow
Directive: Do not collapse Vidu video references back to videos without validating against the gateway schema.
Tested: npm run test:run -- src/app/api/generate/providers/__tests__/newapiwg.test.ts src/components/__tests__/PromptNode.test.tsx
Tested: git diff --check
Tested: npm run build
Not-tested: Real Vidu generation, to avoid consuming account points.
Local reference images were reaching the gateway as localhost URLs, and selected image/video nodes still exposed duplicate inline settings while the composer is the active control surface. This keeps gateway media inputs self-contained, maps GPT Image 2 sizes from the actual aspect ratio controls, and keeps node bodies focused on preview/output state.
Constraint: NewApiWG upstream cannot fetch browser-local /api/images URLs.
Constraint: Selected-node composer owns image and video generation controls.
Rejected: Keep localhost reference URLs | remote gateway requests cannot dereference local browser routes.
Rejected: Keep duplicate inline settings | it creates conflicting controls with the composer.
Confidence: high
Scope-risk: moderate
Directive: Do not send /api/images temporary URLs to NewApiWG upstream; resolve them to data URLs before provider calls.
Tested: npm run test:run -- src/app/api/generate/providers/__tests__/newapiwg.test.ts src/app/api/generate/__tests__/route.test.ts src/components/__tests__/GenerateImageNode.test.tsx src/components/__tests__/GenerateVideoNode.test.tsx src/components/__tests__/PromptNode.test.tsx src/lib/__tests__/llmModels.test.ts src/store/__tests__/workflowStore.integration.test.ts
Tested: npm run build
Tested: git diff --check
Not-tested: npm run lint still fails because next lint resolves to a nonexistent lint directory under Next 16.
The image-count pricing regression was passing an override into a helper that ignored it, so the test exercised the one-image default while expecting the four-image total. This makes the fixture accept the same node data overrides as the lower-level image node factory without touching production pricing logic.
Constraint: Remote master already contains the UI change that hides unimplemented image toolbar actions.
Rejected: Change GenerationComposer point calculation | the failing evidence showed draft.imageCount was never set by the fixture.
Confidence: high
Scope-risk: narrow
Tested: npm run test:run -- src/components/__tests__/ImageInputNode.test.tsx src/app/api/generate/providers/__tests__/newapiwg.test.ts src/app/api/points/estimate/__tests__/route.test.ts src/components/__tests__/GenerationComposer.test.tsx src/store/execution/__tests__/generateVideoExecutor.test.ts
Tested: npm run build
Tested: git diff --check
Popi/NewAPIWG is now the primary gateway, so the UI and request paths need to avoid legacy provider assumptions while keeping local reference media usable for upstream calls. This change aligns model defaults, point display, inline node controls, and temporary reference image handling around that gateway boundary.
Constraint: Upstream providers cannot fetch localhost reference URLs, but large base64 payloads previously caused request/body reliability issues.
Constraint: Seedance point estimates depend on authenticated NewAPIWG /api/points/estimate responses rather than static catalog prices.
Rejected: Send all reference images directly as large data URLs | would reintroduce oversized JSON/request failures.
Rejected: Restore legacy per-provider key controls by default | current product direction is a single Popi/NewAPI gateway.
Confidence: high
Scope-risk: moderate
Directive: Do not pass /api/images localhost URLs to upstream generation APIs; resolve them server-side or fail before the upstream call.
Tested: npm run test:run -- src/app/api/generate/providers/__tests__/newapiwg.test.ts src/app/api/points/estimate/__tests__/route.test.ts src/lib/images/store.test.ts src/components/__tests__/GenerationComposer.test.tsx src/components/__tests__/ImageInputNode.test.tsx src/components/__tests__/PromptNode.test.tsx src/components/__tests__/ProjectSetupModal.test.tsx src/store/execution/__tests__/generateVideoExecutor.test.ts src/store/execution/__tests__/nanoBananaExecutor.test.ts src/store/utils/__tests__/nodeDefaults.test.ts
Tested: npm run build
Tested: git diff --check
Not-tested: npm run lint fails because next lint is parsed as a missing /lint project directory under Next 16.
Multi-image NewAPIWG generations were sending base64 reference images
inside the /api/generate JSON body. Two ordinary canvas references can
push that payload near the dev/server body boundary, leaving the route
to parse an incomplete JSON string and surface a raw syntax error.
Move large NewAPIWG references through the existing in-memory image
serving path: the browser uploads large data URLs as multipart image
files, sends short /api/images/{id} URLs in the generation request, and
the route resolves those temporary URLs back to server-local image data
before calling providers. The route also turns malformed/truncated JSON
into a readable validation error.
Constraint: Keep provider payload semantics unchanged after /api/generate receives the request
Constraint: Do not rely on request origin matching because Next dev can report 0.0.0.0 while the browser uses localhost
Rejected: Increase body size limits only | still sends multi-MB JSON and does not protect hosted/proxied environments
Rejected: Compress reference images client-side | changes model input fidelity and still leaves large JSON possible
Confidence: high
Scope-risk: moderate
Directive: Do not forward /api/images/{id} temporary URLs to external providers; resolve them server-side first
Tested: npm run test:run -- src/store/execution/__tests__/nanoBananaExecutor.test.ts src/app/api/generate/__tests__/route.test.ts
Tested: npm run build
Not-tested: Live NewAPIWG generation with the user's exact two images
The welcome screen now matches the Popi.TV brand and gives unauthenticated users two explicit paths: jump to the main-site login page or provide a Popi/NewAPI gateway key directly. The manually provided key is persisted in the local user store and forwarded through the NewAPI-backed generation, model, LLM, and chat routes without requiring a login token.
Constraint: Users need a usable local path when they are not logged into the main site.\nRejected: Keep the startup login modal for missing tokens | it blocked the in-welcome login/key choices.\nRejected: Rename internal workflow prompts and storage keys | those are compatibility/internal identifiers, not the visible brand surface.\nConfidence: high\nScope-risk: moderate\nDirective: Keep manual gateway-key access scoped to NewAPI-backed paths; non-NewAPI providers should continue requiring a login token.\nTested: npm run test:run -- src/app/api/models/__tests__/route.test.ts src/app/api/models/[modelId]/__tests__/route.test.ts src/app/api/llm/__tests__/route.test.ts src/app/api/chat/__tests__/route.test.ts src/app/api/generate/__tests__/route.test.ts\nTested: npm run test:run -- src/components/__tests__/QuickstartInitialView.test.tsx src/components/__tests__/WelcomeModal.test.tsx\nTested: npm run build\nTested: Browser verification for Popi.TV welcome title and two unauthenticated entry paths\nTested: git diff --cached --check\nNot-tested: Full test suite\nNot-tested: npm run lint still fails because the existing Next 16 next lint script resolves /lint as a project directory
The welcome screen now matches the Popi.TV brand and gives unauthenticated users two explicit paths: jump to the main-site login page or provide a Popi/NewAPI gateway key directly. The manually provided key is persisted in the local user store and forwarded through the NewAPI-backed generation, model, LLM, and chat routes without requiring a login token.
Constraint: Users need a usable local path when they are not logged into the main site.\nRejected: Keep the startup login modal for missing tokens | it blocked the in-welcome login/key choices.\nRejected: Rename internal workflow prompts and storage keys | those are compatibility/internal identifiers, not the visible brand surface.\nConfidence: high\nScope-risk: moderate\nDirective: Keep manual gateway-key access scoped to NewAPI-backed paths; non-NewAPI providers should continue requiring a login token.\nTested: npm run test:run -- src/app/api/models/__tests__/route.test.ts src/app/api/models/[modelId]/__tests__/route.test.ts src/app/api/llm/__tests__/route.test.ts src/app/api/chat/__tests__/route.test.ts src/app/api/generate/__tests__/route.test.ts\nTested: npm run test:run -- src/components/__tests__/QuickstartInitialView.test.tsx src/components/__tests__/WelcomeModal.test.tsx\nTested: npm run build\nTested: Browser verification for Popi.TV welcome title and two unauthenticated entry paths\nTested: git diff --cached --check\nNot-tested: Full test suite\nNot-tested: npm run lint still fails because the existing Next 16 next lint script resolves /lint as a project directory
Browser directory picking can be intercepted by embedded automation environments, which raises before the user can choose a folder. The project setup browse flow now treats that specific interception as a signal to use the existing server browse-directory fallback, while preserving normal browser picker behavior and cancellation semantics.
Constraint: In-app browser automation may install Page.setInterceptFileChooserDialog and break showDirectoryPicker
Constraint: Browser File System Access selection should still be preferred when it works
Rejected: Always fall back after any browser picker error | permission and unsupported errors should remain visible instead of silently choosing a server path
Confidence: high
Scope-risk: narrow
Directive: Do not broaden fallback errors without checking browser local-project semantics
Tested: npm run test:run -- src/components/__tests__/ProjectSetupModal.test.tsx --testNamePattern "fall back to browse-directory API"
Tested: npm run test:run -- src/components/__tests__/ProjectSetupModal.test.tsx --testNamePattern "Browse Button"
Tested: npm run test:run -- src/components/__tests__/ProjectSetupModal.test.tsx --testNamePattern "fall back to browse-directory API|should call browse-directory API|should keep selected parent path|should handle cancelled browse dialog"
Tested: npm run build
Not-tested: npm run lint | existing Next 16 next lint script resolves to nonexistent /lint directory
Not-tested: Full ProjectSetupModal test file | existing Provider tab assertions expect API key inputs hidden by current Popi mode
The app now starts I18nProvider in zh-CN when no saved language exists, while preserving explicit saved choices. The login-required Ant Design modal also uses the v6 mask.closable shape so the console no longer warns about maskClosable.
Constraint: First-run locale should not override an existing saved language preference
Constraint: Ant Design 6 deprecates maskClosable on Modal.confirm
Rejected: Keep browser-language detection | first entry needs deterministic Simplified Chinese
Confidence: high
Scope-risk: narrow
Directive: Keep provider-less useI18n fallback stable for isolated tests unless all callers are wrapped in I18nProvider
Tested: npm run test:run -- src/i18n/__tests__/index.test.tsx src/components/__tests__/TemplateExplorerView.test.tsx src/components/__tests__/Header.test.tsx src/utils/__tests__/loginRequiredModal.test.ts src/utils/__tests__/authFetch.test.ts src/store/__tests__/userStore.test.ts
Tested: npm run build
Not-tested: npm run lint | existing Next 16 next lint script resolves to nonexistent /lint directory
The canvas now treats the visible plus affordance as part of the output handle hit zone, so users can click or drag from the same right-side target. Empty image input nodes also handle double-click locally before the canvas node double-click centering logic sees the event.
Constraint: The plus affordance must not block React Flow handle drag events
Rejected: Keep the plus as the primary pointer target | it prevented drag-to-connect from the same visual area
Confidence: high
Scope-risk: moderate
Directive: Keep quick-add visuals non-interactive unless handle dragging is reworked at the React Flow layer
Tested: npm run test:run -- src/components/__tests__/ImageInputNode.test.tsx src/components/__tests__/WorkflowCanvas.test.tsx
Tested: npm run build
Not-tested: npm run lint | existing Next 16 next lint script resolves to nonexistent /lint directory