Addresses review feedback on the per-prompt metadata envelope:
- Sanitize at the boundary: reject envelopes larger than 16 keys, keys
over 64 chars, values over 256 chars, or anything that isn't a flat
``dict[str, str]``. Logs a warning so abuse is observable. Stops a
malicious client from inflating broadcast volume by stamping a 10 MB
metadata blob onto every WS event.
- Cap the in-memory store at 4096 concurrent envelopes with FIFO
eviction. Acts as a backstop if any cleanup hook is skipped.
- Drop envelopes when prompts are cancelled before reaching the worker:
``PromptQueue.wipe_queue`` and ``delete_queue_item`` now call
``server.unregister_prompt_metadata`` for every removed item.
- Drop envelopes on hard execution failures: the worker now wraps
``e.execute()`` in ``try/finally``, so an uncaught exception in
execution no longer leaks the envelope.
- Guard the WS reconnect handler: only include ``prompt_id`` in the
``executing`` payload when ``last_prompt_id`` is set, so clients
with strict schemas (zod ``prompt_id: zJobId``) don't reject the
message with a null id.
- Extract a ``PromptMetadataStore`` class that owns the dict and the
bounds, so ``PromptServer`` becomes a thin delegating layer and the
full register/inject/unregister cycle (plus FIFO eviction and
sanitization) is unit-tested without torch.
44 tests passing; ruff clean on all touched files.
Replaces the workflow_id-on-every-event approach (#13684, reverted in
#13901) with a generic metadata envelope captured at submission and
injected at the server-side send chokepoint.
- POST /prompt accepts an opaque ``extra_data.metadata`` dict (falls
back to synthesizing ``{"workflow_id": <id>}`` from
``extra_pnginfo.workflow.id`` so existing frontends keep working).
- ``PromptServer`` owns a ``prompt_id -> metadata`` map populated at
submission, drained when the prompt finishes. ``send_sync`` injects
the envelope into any outbound payload that carries a ``prompt_id``,
including the ``(preview_image, metadata_dict)`` tuple used by
``PREVIEW_IMAGE_WITH_METADATA``. WS reconnect path carries it too.
- Pure helpers live in ``app/prompt_metadata.py`` so the execution
layer never depends on workflow concepts and the helpers can be
unit-tested without torch.
Execution layer (``execution.py``, ``comfy_execution/*``) and the jobs
API are unchanged. Backward compatible: existing fields and shapes are
preserved, only an additional ``metadata`` field is attached when
present.