Deferred Items from PR #1058
Items identified during the PR #1058 review (workflow execution lifecycle + editor improvements) that are out of scope for that PR but should be tracked.
1. JWT token in localStorage (security)
The JWT access token is stored in localStorage (web/src/stores/auth.ts), making it accessible to any JavaScript on the same origin. A stored XSS vulnerability anywhere would silently exfiltrate the token.
Remediation: Migrate session tokens to HttpOnly; Secure; SameSite=Strict cookies managed by the backend. The Litestar auth service already handles JWT issuance. If deferred, shorten expires_in and consider sessionStorage as an interim step.
2. Backend condition evaluator AND/OR/NOT support
The frontend condition expression builder now supports AND/OR/NOT compound expressions and nested groups, but the backend condition_eval.py evaluator only handles single comparisons, boolean literals, and key lookups. Compound expressions serialized by the frontend (e.g., field1 == val1 AND field2 != val2) will not be parsed correctly by the backend.
Remediation: Extend evaluate_condition() in src/synthorg/engine/workflow/condition_eval.py to tokenize and evaluate compound expressions with AND/OR/NOT operators and parenthesized groups.
3. O(R*N) execution lookup performance
_find_execution_by_task() in execution_service.py scans all RUNNING executions and all their node executions to find one by task_id. This is O(R*N) where R = running executions and N = nodes per execution. Called on every task state change event from the TaskEngine.
Remediation: Add a repository-level indexed lookup (execution_repo.find_by_task_id() or a task_id -> execution_id map) to make this O(1).
4. Observer delivery on TaskEngine hot path (performance)
The _notify_observers() call in TaskEngine._process_one() awaits all observers sequentially on the single-writer mutation path. A slow observer blocks subsequent task mutations. Currently acceptable at low scale (single observer, fast persistence ops), but will need a background dispatcher as observer count or persistence latency grows.
Remediation: Move observer notification to a dedicated background queue/dispatcher so the mutation pipeline is not blocked by observer I/O.
5. Explicit branch metadata in YAML depends_on
The YAML import parser (yaml-to-nodes.ts) infers conditional_true/conditional_false edge types by declaration order in depends_on. Reordering steps in YAML can flip which successor is true vs false, breaking the bidirectional round-trip guarantee for conditional flows.
Remediation: Extend the YAML schema so depends_on entries can be either a plain string ID or an object with explicit edge metadata (e.g. { id: "stepA", branch: "true" }). Update both the YAML exporter (workflow-to-yaml.ts) to emit the metadata and the importer (yaml-to-nodes.ts) to prefer it over counter-based inference.
Deferred Items from PR #1058
Items identified during the PR #1058 review (workflow execution lifecycle + editor improvements) that are out of scope for that PR but should be tracked.
1. JWT token in localStorage (security)
The JWT access token is stored in
localStorage(web/src/stores/auth.ts), making it accessible to any JavaScript on the same origin. A stored XSS vulnerability anywhere would silently exfiltrate the token.Remediation: Migrate session tokens to
HttpOnly; Secure; SameSite=Strictcookies managed by the backend. The Litestar auth service already handles JWT issuance. If deferred, shortenexpires_inand considersessionStorageas an interim step.2. Backend condition evaluator AND/OR/NOT support
The frontend condition expression builder now supports AND/OR/NOT compound expressions and nested groups, but the backend
condition_eval.pyevaluator only handles single comparisons, boolean literals, and key lookups. Compound expressions serialized by the frontend (e.g.,field1 == val1 AND field2 != val2) will not be parsed correctly by the backend.Remediation: Extend
evaluate_condition()insrc/synthorg/engine/workflow/condition_eval.pyto tokenize and evaluate compound expressions with AND/OR/NOT operators and parenthesized groups.3. O(R*N) execution lookup performance
_find_execution_by_task()inexecution_service.pyscans all RUNNING executions and all their node executions to find one by task_id. This is O(R*N) where R = running executions and N = nodes per execution. Called on every task state change event from the TaskEngine.Remediation: Add a repository-level indexed lookup (
execution_repo.find_by_task_id()or a task_id -> execution_id map) to make this O(1).4. Observer delivery on TaskEngine hot path (performance)
The
_notify_observers()call inTaskEngine._process_one()awaits all observers sequentially on the single-writer mutation path. A slow observer blocks subsequent task mutations. Currently acceptable at low scale (single observer, fast persistence ops), but will need a background dispatcher as observer count or persistence latency grows.Remediation: Move observer notification to a dedicated background queue/dispatcher so the mutation pipeline is not blocked by observer I/O.
5. Explicit branch metadata in YAML depends_on
The YAML import parser (
yaml-to-nodes.ts) infersconditional_true/conditional_falseedge types by declaration order independs_on. Reordering steps in YAML can flip which successor is true vs false, breaking the bidirectional round-trip guarantee for conditional flows.Remediation: Extend the YAML schema so
depends_onentries can be either a plain string ID or an object with explicit edge metadata (e.g.{ id: "stepA", branch: "true" }). Update both the YAML exporter (workflow-to-yaml.ts) to emit the metadata and the importer (yaml-to-nodes.ts) to prefer it over counter-based inference.