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.
This keeps the testing branch aligned with the current Popi.TV interaction direction: generation is controlled from the selected node context, model/provider selection is simplified around the NewAPI gateway path, Popiai embedding can hydrate workflow state, and media nodes expose names plus dimensions in the canvas header.
Constraint: Testing branch needs the full current source state, not runtime logs or local browser artifacts
Rejected: Commit logs, browserfs state, and handoff bundles | they are local runtime artifacts rather than application source
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep model selection consolidated around the NewAPI gateway unless supplier-specific behavior is intentionally reintroduced
Tested: npm run test:run -- src/components/__tests__/FloatingNodeHeader.test.tsx src/components/__tests__/nodeHeaderMedia.test.ts src/components/__tests__/WorkflowCanvas.test.tsx
Tested: npm run test:run -- src/components/__tests__/ImageInputNode.test.tsx src/components/__tests__/GenerateVideoNode.test.tsx src/components/__tests__/GenerateImageNode.test.tsx
Tested: npm run build
Tested: git diff --check -- src
Not-tested: npm run lint | existing script uses next lint and resolves to nonexistent ./lint directory
The bottom composer and right-side node settings both expose video duration, resolution, and sound. Selected video nodes now receive quick-control changes immediately, so both surfaces read the same node data instead of diverging until blur or generate.
Constraint: Bottom composer remains the primary quick control while existing node settings continue to read workflow store data
Rejected: Remove the node settings panel | broader product change outside this fix
Rejected: Convert all composer draft fields to immediate store writes | higher risk and unnecessary for the reported video parameter mismatch
Confidence: high
Scope-risk: narrow
Directive: Keep shared video parameters on GenerateVideoNodeData; do not introduce a second parameter source for quick controls
Tested: npm run test:run -- src/components/__tests__/GenerationComposer.test.tsx
Tested: npm run test:run -- src/components/__tests__/GenerateVideoNode.test.tsx
Tested: git diff --check
Not-tested: full lint/typecheck still blocked by existing repo script/type issues from prior verification
The accumulated fixes move the test build toward the current product shape: Popi models are the default provider surface, remote community workflow APIs are removed from the local template flow, media nodes expose accurate preview/preview-modal behavior, and Generate Video owns first-class duration, resolution, and sound defaults instead of burying those values in provider schemas.
The test suite was brought back in line with the product mode split: Popi provider mode is the default runtime, while multi-provider model search remains covered explicitly under multi mode.
Constraint: Product direction is canvas-owned workflow structure with Popi Models as the tested default provider path.
Rejected: Keep legacy community workflow API surface | user requested removing remote data paths and retaining local templates.
Rejected: Treat video duration/resolution/sound as hidden provider params | these are user-facing Generate Video controls.
Confidence: high
Scope-risk: broad
Directive: Do not reintroduce remote community template loading without a product decision on hosted templates and i18n ownership.
Tested: npm test -- --run src/store/utils/__tests__/nodeDefaults.test.ts src/store/execution/__tests__/generateVideoExecutor.test.ts src/components/__tests__/GenerateVideoNode.test.tsx src/components/__tests__/GenerationComposer.test.tsx
Tested: npm run build
Tested: npm test -- --run src/components/__tests__/ModelSearchDialog.test.tsx src/store/utils/__tests__/localStorage.test.ts
Tested: npm run test:run
Not-tested: Live provider generation calls against paid external APIs.
The bottom generation composer now treats reference thumbnails as previewable assets: clicking a thumbnail opens a portal lightbox with the full image, backdrop/click-close behavior, and Escape close support. The remove button stops propagation so deletion remains distinct from preview opening.
Constraint: Keep the interaction inside the existing composer surface without introducing a shared modal dependency
Rejected: Reusing output-node lightbox directly | it is coupled to node media state and download/video behavior
Confidence: high
Scope-risk: narrow
Directive: Keep thumbnail click and remove click separated; do not nest buttons
Tested: npm run test:run -- src/components/__tests__/GenerationComposer.test.tsx
Tested: PROVIDER_MODE=popi NEXT_PUBLIC_PROVIDER_MODE=popi npm run build
Tested: Playwright uploaded a reference image, opened the preview dialog, and closed it with Escape
New users now land on Popi gateway defaults that match the tested production-style path: APIYI Nano Banana 2 for images, Doubao Seedance for video, and Doubao Seed 2.0 Lite for LLM chat/tool use. Settings and FTUX screens render these effective defaults instead of empty placeholders, while existing local node defaults keep taking precedence.
The same pass keeps provider-overload errors user-facing by formatting the model name that the node currently displays, so fallback and switched-model failures are easier to understand across media nodes.
Constraint: Popi mode should hide internal NewApiWG naming and default to models available through the Popi gateway.
Rejected: Persist default values into localStorage for every new user | would make future system default changes harder and could overwrite explicit user preferences.
Confidence: high
Scope-risk: moderate
Directive: Do not change these defaults without checking the Popi gateway model ids and www.popi.art login/model-routing assumptions.
Tested: npm run test:run -- src/lib/__tests__/llmModels.test.ts src/store/utils/__tests__/nodeDefaults.test.ts src/store/execution/__tests__/generateVideoExecutor.test.ts src/components/__tests__/ProjectSetupModal.test.tsx src/components/__tests__/GenerationComposer.test.tsx src/app/api/chat/__tests__/route.test.ts src/components/__tests__/LLMGenerateNode.test.tsx src/utils/__tests__/userFacingErrors.test.ts
Tested: PROVIDER_MODE=popi NEXT_PUBLIC_PROVIDER_MODE=popi npm run build
Tested: git diff --check
Not-tested: npm run lint currently fails because next lint is no longer a valid project command in this Next.js setup
The collapsed composer should expand from the surrounding summary area, but the model label and generate button are explicit action targets. This keeps model selection and generation isolated while retaining one-click expansion from the remaining collapsed surface.
Constraint: Red-marked collapsed controls have dedicated product actions
Rejected: Treat the whole collapsed summary as one expand button | steals the model selector action
Confidence: high
Scope-risk: narrow
Directive: Do not bind collapsed-container expansion over buttons with dedicated actions
Tested: npm run test:run -- src/components/__tests__/GenerationComposer.test.tsx
Tested: npm run build
Not-tested: npm run lint | existing script calls unsupported next lint under Next 16
Not-tested: npx tsc --noEmit | existing unrelated test type errors remain
Users expect a collapsed bottom composer to expand from the visible summary itself, not only the small expand icon. The collapsed summary now acts as the expansion target while preserving the generate button's submit behavior, and a regression test locks the summary-click path.
Constraint: TEST-s deployment branch is used for the test server
Rejected: Keep model summary opening the model dialog while collapsed | conflicts with the requested one-click expand behavior
Confidence: high
Scope-risk: narrow
Directive: Keep collapsed summary clicks focused on expansion; preserve generate button isolation
Tested: npm run test:run -- src/components/__tests__/GenerationComposer.test.tsx
Tested: npm run build
Tested: Local browser check on http://localhost:3000/ collapsed summary click
Not-tested: npm run lint | existing script calls unsupported next lint under Next 16
Not-tested: npx tsc --noEmit | existing unrelated test type errors remain
P0 regressions showed several workflow paths needed to stay visible and deterministic: language switching had a hardcoded composer label, Video Trim hid controls before media loaded, and media handoffs to LLM needed real canvas edges rather than implicit conversion. P1 fixes keep canvas-owned structure by adding explicit image/video LLM handles, audio composer validation, 3D output/file routing, and Chat proposal cards that require user apply before mutating nodes.
Constraint: User asked to stop new feature work and only repair P0/P1 product-fit gaps.
Rejected: Auto-convert image or video directly into text for LLM | hides workflow structure and violates the visible-node product model.
Rejected: Let Chat tool calls silently add or edit nodes | canvas structure must be previewed and explicitly applied.
Confidence: high
Scope-risk: moderate
Directive: Keep media transformations represented by visible handles, nodes, and edges; do not add silent Chat or media mutation paths without product review.
Tested: Browser automation for language switch, video input to Generate Video, prompt to Generate Video, LLM default model, Video Trim controls, and video media to LLM input.
Tested: npm run test:run -- src/components/__tests__/ConnectionDropMenu.test.tsx src/components/__tests__/GenerationComposer.test.tsx src/components/__tests__/VideoTrimNode.test.tsx src/components/__tests__/LLMGenerateNode.test.tsx src/store/execution/__tests__/llmGenerateExecutor.test.ts src/app/api/llm/__tests__/route.test.ts src/store/execution/__tests__/generateAudioExecutor.test.ts src/store/execution/__tests__/generate3dExecutor.test.ts src/store/execution/__tests__/simpleNodeExecutors.test.ts src/components/__tests__/OutputNode.test.tsx src/components/__tests__/Generate3DNode.test.tsx src/components/__tests__/ChatPanel.test.tsx src/lib/chat/tools.test.ts src/lib/chat/editOperations.test.ts src/lib/__tests__/llmModels.test.ts src/store/utils/__tests__/nodeDefaults.test.ts
Tested: npm run build
Tested: git diff --cached --check
Not-tested: npm run lint, because the existing script calls removed Next.js lint command and exits with invalid project directory /lint.
Not-tested: Live paid provider calls for LLM, audio, and 3D generation.
The TEST-s branch renders the composer generate action with the English aria-label used by nearby tests. Updating the stale assertion keeps the test focused on image-count persistence instead of locale-specific text.
Constraint: TEST-s currently renders the generate button aria-label as Generate in this test setup
Rejected: Change composer runtime label for the test | would alter UI behavior to satisfy a stale assertion
Confidence: high
Scope-risk: narrow
Directive: Prefer stable accessible labels already used in adjacent composer tests
Tested: npm run test:run -- src/components/__tests__/GenerateImageNode.test.tsx src/components/__tests__/GenerationComposer.test.tsx src/app/api/generate/providers/__tests__/newapiwg.test.ts
Tested: git diff --check
Not-tested: Full browser locale sweep
P0/P1 reports clustered around unavailable LLM defaults, video media connections, and missing controls on the generation surface. This routes the default NewApiWG LLM away from the unavailable Doubao channel, makes video a first-class schema and canvas connection type, carries request ids into node errors, and fills the composer, trim, audio, and 3D gaps without changing the canvas workflow model.
Constraint: NewApiWG Doubao channels are not reliably routed in the default gateway
Constraint: Video model schemas expose video fields that must not flow through image handles
Rejected: Continue accepting video through image handles | hides incorrect graph types and loses schema-specific dynamic inputs
Confidence: high
Scope-risk: moderate
Directive: Keep media handle types explicit; add schema mapping when adding a new connectable media type
Tested: npm run test:run -- src/store/execution/__tests__/generateVideoExecutor.test.ts src/store/utils/__tests__/connectedInputs.test.ts src/store/execution/__tests__/generateAudioExecutor.test.ts src/store/execution/__tests__/llmGenerateExecutor.test.ts src/store/__tests__/workflowStore.integration.test.ts src/lib/__tests__/llmModels.test.ts src/store/utils/__tests__/nodeDefaults.test.ts src/components/__tests__/GenerationComposer.test.tsx src/app/api/chat/__tests__/route.test.ts src/app/api/llm/__tests__/route.test.ts src/app/api/models/[modelId]/__tests__/route.test.ts src/app/api/generate/providers/__tests__/newapiwg.test.ts
Tested: npm run build
Tested: git diff --check
Not-tested: npm run lint | package script calls removed Next 16 next lint command
Not-tested: npx tsc --noEmit | existing test type errors remain; changed runtime files filtered clean
The generation composer previously collapsed multiple reference images into a single thumbnail with a count badge. The composer now renders each reference thumbnail in sequence, keeps them scrollable in the toolbar, and lets editable drafts remove a specific image by position.
Constraint: Reference image ordering matters for multi-image generation context.
Rejected: Keep count badge overlay | it hides which images are attached and makes order ambiguous.
Confidence: high
Scope-risk: narrow
Tested: npm test -- --run src/components/__tests__/GenerationComposer.test.tsx
Tested: npx tsc --noEmit --pretty false filtered to GenerationComposer files
Not-tested: Full tsc remains blocked by existing unrelated test typing errors
This aligns image, video, and text defaults with the PopiArt NewApi gateway while keeping provider-specific escape hatches available. Chat now uses the OpenAI-compatible NewApiWG route so workflow editing and LLM generation share the same Doubao-first text default. The canvas composer and quick-add controls are tightened so visible actions map to real clickable behavior, while temporarily unused header actions stay hidden.
Constraint: Text/chat requests must prefer Doubao-Seed-2.0-lite through NewApiWG.
Constraint: Image and video defaults should prefer PopiArt NewApi gateway models when configured.
Rejected: Keep /api/chat on Gemini 3 Flash | conflicts with the requested NewApiWG text/chat default.
Rejected: Hand-roll AI SDK chat streaming | would risk tool-call and UI stream compatibility.
Confidence: high
Scope-risk: moderate
Directive: Do not add new text/chat defaults without updating src/lib/llmModels.ts and the chat route together.
Tested: npm test -- --run src/app/api/chat/__tests__/route.test.ts src/components/__tests__/LLMGenerateNode.test.tsx src/lib/__tests__/llmModels.test.ts src/store/utils/__tests__/nodeDefaults.test.ts src/components/__tests__/GenerationComposer.test.tsx src/lib/chat/tools.test.ts
Tested: npm test -- --run src/lib/__tests__/llmModels.test.ts src/store/utils/__tests__/nodeDefaults.test.ts src/components/__tests__/GenerationComposer.test.tsx src/lib/quickstart/__tests__/templates.test.ts src/lib/quickstart/__tests__/validation.test.ts src/lib/quickstart/__tests__/prompts.test.ts src/components/__tests__/ProjectSetupModal.test.tsx
Tested: npm test -- --run src/components/__tests__/WorkflowCanvas.test.tsx
Not-tested: Full suite; repository has pre-existing unrelated type/test warnings outside this change.
Provider video URLs can expire before users finish composing, and the bottom composer was too visually dominant for canvas work. This change keeps remote videos playable while background-localizing them, teaches video previews to use the media proxy, makes audio nodes first-class in the composer and executor, and adds a compact composer state for canvas visibility.
Constraint: Provider media URLs may be remote, signed, or CORS-restricted during playback and thumbnail extraction
Constraint: Audio generation nodes need to work from their internal prompt as well as connected text
Rejected: Store only provider URLs | remote URLs can expire and break later playback
Rejected: Treat audio nodes as unsupported composer nodes | it falls back to the image model and corrupts user intent
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep provider media playable through the resolver/proxy path and preserve local refs as the durable source when available
Tested: npm run test:run
Tested: npm run test:run -- src/components/__tests__/GenerationComposer.test.tsx src/store/execution/__tests__/generateAudioExecutor.test.ts src/store/execution/__tests__/generateVideoExecutor.test.ts src/components/__tests__/VideoStitchNode.test.tsx src/components/__tests__/GenerateVideoNode.test.tsx
Tested: npm run build
Not-tested: npm run lint currently fails because next lint is not supported by this Next.js setup
Not-tested: npx tsc --noEmit still reports pre-existing test typing errors outside this change
The bottom composer now treats video stitch and ease curve as processing-node inspectors instead of unsupported prompt editors. The connection menu also keeps video streams and ease-curve settings on separate handle paths so downstream creation matches the node graph semantics.
Constraint: Processing nodes should run existing local media operations and must not expose model or prompt controls
Constraint: Ease curve Settings handles carry curve parameters, not video media
Rejected: Let Settings handles reuse generic video/text drop options | creates misleading nodes and invalid graph intent
Rejected: Make Video Input a downstream target from Video Out | Video Input is an import/source node, not a processing destination
Confidence: high
Scope-risk: moderate
Directive: Keep media handles and settings handles separated in connection menus and validation
Tested: npm run test:run -- src/components/__tests__/ConnectionDropMenu.test.tsx
Tested: npm run test:run -- src/components/__tests__/GenerationComposer.test.tsx
Tested: npm run test:run -- src/components/__tests__/WorkflowCanvas.test.tsx
Tested: npm run build
Tested: git diff --check
Not-tested: npm run lint still uses the existing Next 16-incompatible next lint script
The bottom composer now edits and reruns the current generation node while canvas-visible actions own downstream node creation. NewApiWG media normalization, video frame extraction, and node quick-add keep generated media flows explicit and connected rather than hidden behind the prompt box.
Constraint: Composer must not call providers directly or create hidden downstream branches when a node is selected
Constraint: NewApiWG video families use inconsistent media schemas, so common media aliases are normalized in the provider adapter
Rejected: Let the bottom composer create next-step nodes from selected outputs | hides graph mutation and conflicts with the PRD source-of-truth rules
Rejected: Put NewApiWG model-family payload rules in the composer | provider-specific schemas would leak into UI state
Confidence: high
Scope-risk: moderate
Directive: Keep provider payload normalization in provider/executor layers; do not move it into GenerationComposer
Tested: npm run test:run -- src/components/__tests__/GenerationComposer.test.tsx
Tested: npm run test:run -- src/components/__tests__/WorkflowCanvas.test.tsx
Tested: npm run test:run -- src/components/__tests__/GenerateVideoNode.test.tsx
Tested: npm run test:run -- src/app/api/generate/providers/__tests__/newapiwg.test.ts src/app/api/generate/__tests__/route.test.ts
Tested: npm run test:run -- src/store/execution/__tests__/videoProcessingExecutors.test.ts
Tested: npm run build
Not-tested: npm run lint fails because next lint is incompatible with the current Next 16 script configuration