Address adversarial-review findings on FE-745 metadata propagation:
- send_sync previously spread active_prompt_metadata onto every dict
payload, contaminating unrelated status/queue broadcasts with the
running prompt's workflow_id. Change the slot to (prompt_id, metadata)
and only inject when payload.prompt_id matches the active prompt_id.
Same condition applied to the WS reconnect catch-up frame.
- post_prompt now validates extra_data.metadata at the submission
boundary: flat dict[str,str], max 16 keys, 64-char keys, 256-char
values, and reserved server-side keys (prompt_id, node, output, etc.)
are rejected with 400. Removes the broadcast-amplification vector
where a client could submit arbitrarily large metadata and force it
onto every WS frame.
- Extract validate_client_metadata + caps into app/prompt_metadata.py so
tests can import without pulling server.py's import-time side effects.
- Expand tests-unit/server_test/test_prompt_metadata.py from 12 to 47:
add TestStatusBroadcastsAreNotContaminated for prompt_id-scoping and
TestValidateClientMetadata for the new submission-boundary checks
(including parametrized reserved-key rejection).
server.py builds an opaque dict at submission time from extra_data and pins
it on PromptServer.active_prompt_metadata while main.py's worker drives the
prompt. send_sync spreads the dict's key/value pairs onto outgoing payloads
so frames carry whatever tags the submission attached (today: workflow_id).
The mechanism is intentionally untyped — the transport layer doesn't know
what workflow_id means or treat any key specially. Adding a new propagated
field requires only a one-line addition in post_prompt; execution.py and
comfy_execution/progress.py are not touched.
execution.py changes: 0 lines.