# Conditional Logic: Gap Analysis & Design This document captures the structural differences between Adobe Sign's and DocuSign's conditional field models, which gaps are solvable in the migrator, and the design of proposed solutions. It complements `field-mapping.md` (current-state reference) and `IMPLEMENTATION-PLAN.md` (feature history). --- ## Background: The Two Models **Adobe Sign** supports full conditional logic per field: - `conditionalAction.predicates[]` — one or more `{fieldName, operator, value}` tuples - `anyOrAll` — ANY (OR) or ALL (AND) combining semantics - `action` — SHOW or HIDE the field - `operator` — EQUALS, NOT_EQUALS, GT, LT, CONTAINS, etc. - The trigger field can belong to any recipient; cross-recipient conditions are valid **DocuSign** supports a single, simple reveal condition per tab: - `conditionalParentLabel` — the `tabLabel` or `groupName` of the trigger tab - `conditionalParentValue` — the exact string value that reveals the tab - The trigger tab must be a `listTab`, `radioGroupTab`, or `checkboxTab` - The trigger and the dependent tab must belong to the **same recipient** - Only one condition per tab, always EQUALS, always a SHOW (reveal) This is the deepest structural asymmetry in the migration. Every gap below flows from the gap between these two models. --- ## Gap Catalog ### Gap 1 — HIDE action **Adobe**: `action: HIDE` — field is visible by default and hides when the condition is met. **DocuSign**: No equivalent. DocuSign only supports revealing a tab that starts hidden. **Current behavior**: Condition dropped; field always visible. `HIDE_ACTION` issue emitted. ### Gap 2 — NOT_EQUALS and other operators **Adobe**: Supports NOT_EQUALS, GT, LT, CONTAINS, etc. **DocuSign**: Only EQUALS is supported. **Current behavior**: Condition dropped; field always visible. `UNSUPPORTED_OPERATOR` issue emitted. The most common real-world case is `NOT_EQUALS ""` (show this field if the user entered *anything* in another field). This is doubly broken in DocuSign: 1. NOT_EQUALS has no equivalent 2. Text fields can't be conditional parents at all (see Gap 5) ### Gap 3 — Cross-recipient conditionals **Adobe**: Field B can show/hide based on the value of Field A even if A and B belong to different recipients. **DocuSign**: `conditionalParentLabel` resolves only within the same recipient's tab set. The API silently ignores or rejects cross-recipient references. **Current behavior**: Condition dropped. `CROSS_RECIPIENT_CONDITIONAL` issue emitted. ### Gap 4 — Multi-predicate ANY (OR) logic **Adobe**: `anyOrAll: ANY` with multiple predicates — show if condition 1 OR condition 2 OR … **DocuSign**: One `conditionalParentValue` per tab — no native OR. **Current behavior**: Only the first EQUALS predicate is mapped; rest are dropped. `MULTI_PREDICATE` issue emitted. ### Gap 5 — Invalid conditional parent tab types **Adobe**: Any field can be a conditional trigger — text fields, signature fields, anything. **DocuSign**: Only `listTabs`, `radioGroupTabs`, and `checkboxTabs` may be conditional parents. All other types cause `CONDITIONALTAB_HAS_INVALID_PARENT` (400). **Current behavior**: Strip pass removes conditions referencing invalid parent types. `INVALID_PARENT_TAB` issue emitted. ### Gap 6 — Multi-predicate ALL (AND) logic **Adobe**: `anyOrAll: ALL` — show only if ALL conditions are simultaneously true. **DocuSign**: No AND logic at the template conditional level. **Current behavior**: Only the first EQUALS predicate is mapped. `MULTI_PREDICATE` issue emitted. --- ## The DocuSign "Flags" Technique DocuSign's "Building Advanced Templates" guide describes using **hidden intermediate tabs** ("flags") to work around the platform's single-parent conditional model. The pattern: 1. Create a hidden `checkboxTab` or `listTab` — the "flag" — placed out of the visible form area or given `locked: true, selected: false`. 2. Make the flag conditionally revealed by one condition (the flag itself is shown when condition A is true). 3. Make the dependent field conditionally revealed when the flag is in a specific state. This creates two-level conditional depth. However, DocuSign tabs don't auto-set their own value — a checkbox flag only "activates" when the signer checks it, or when the sender pre-fills it before sending. This limits the technique to two scenarios: **Scenario A — Sender-prefill flags**: The sender manually checks/sets flags before routing the envelope, making explicit business logic decisions that the template cannot express automatically. Useful for bespoke workflows but not for automated migration. **Scenario B — Checkbox-group section selectors**: For OR-style logic driven by a single dropdown, radio group, or checkbox, the flag technique is not needed — the multi-copy approach (Gap 4 solution below) handles this cleanly. **Bottom line**: The flag technique is a UI/manual-workflow tool, not an automated migration output. It doesn't solve AND logic or cross-recipient conditions without human intervention at sending time. --- ## Solvable Gaps: Proposed Designs ### Solution A — ANY multi-predicate fan-out (addresses Gap 4, partially Gap 2) **Scope**: When `anyOrAll: ANY` and all predicates share the same parent field and all use `EQUALS`, the OR logic can be emitted as **one copy of the dependent tab per predicate value**, all at the same coordinates with the same `tabLabel`. At signing time, DocuSign shows exactly the copies whose condition is satisfied. Because the copies share a `tabLabel`, their values sync — the signer fills one and DocuSign treats them as the same logical field. **Before** (current output — only first predicate mapped): ```json { "tabLabel": "Notes", "conditionalParentLabel": "Category", "conditionalParentValue": "Option A" } ``` **After** (fan-out): ```json { "tabLabel": "Notes", "conditionalParentLabel": "Category", "conditionalParentValue": "Option A" }, { "tabLabel": "Notes", "conditionalParentLabel": "Category", "conditionalParentValue": "Option B" } ``` **NOT_EQUALS expansion** (Gap 2, dropdown parents only): When the operator is NOT_EQUALS and the parent is a `listTab`, look up the parent field's option list and compute the complement — emit one copy per remaining value. This covers the common "show unless user picked X" pattern. **Limitations**: - Only works when all predicates reference the **same parent field** - Mixed-parent ANY (field A = x OR field B = y) is still unsupported - NOT_EQUALS expansion only works for `listTab` parents with a finite option set - Text field parents remain invalid regardless of operator (Gap 5) **New issue codes proposed**: - `MULTI_PREDICATE_EXPANDED` (info) — OR logic successfully fanned out - `NOT_EQUALS_EXPANDED` (info) — NOT_EQUALS resolved via complement enumeration - `NOT_EQUALS_UNEXPANDABLE` (warning) — NOT_EQUALS on a non-list parent; condition dropped --- ### Solution B — Richer guidance messages for unsolvable gaps All currently unsolvable gaps emit a generic "condition dropped" message. Each gap warrants a specific, actionable message explaining the constraint and what to do manually. | Gap | Improved guidance | |-----|------------------| | `HIDE_ACTION` | "Restructure as a SHOW condition: start the field hidden (remove it from the base layout) and show it when the inverse condition is met. If the trigger is a dropdown, this requires listing all values that should reveal the field." | | `CROSS_RECIPIENT_CONDITIONAL` | "Add a prefill recipient (routing order 0) that holds the controlling field. Downstream signers' conditional fields can then reference the prefill tab. The sender sets the value before routing." | | `INVALID_PARENT_TAB` (text parent) | "DocuSign requires a dropdown, radio group, or checkbox as the condition trigger. Replace the text field trigger with a dropdown containing expected values, then the condition can be mapped." | | `MULTI_PREDICATE` (mixed parents) | "DocuSign supports one condition per field. Split this field into two separate positioned fields, each conditional on one predicate." | --- ## Unsolvable Gaps (Fundamental Limits of DocuSign Templates) These gaps cannot be addressed at the template layer regardless of technique: | Gap | Why | |-----|-----| | HIDE action (general) | DocuSign has no "start visible, hide when X" model. Inversion via complement enumeration only works for dropdown triggers with finite option sets. | | Text field as conditional parent | DocuSign's API flatly rejects any tab type other than `listTabs`, `radioGroupTabs`, `checkboxTabs` as a parent — this is a server-side constraint, not a schema quirk. | | AND logic (multi-predicate ALL) | DocuSign template conditionals have no AND. The flag chaining technique requires a human to set intermediate flags at sending time, making it unsuitable for automated migration output. | | Mixed-parent ANY | "Show if field A = x OR field B = y" requires two independent conditions on the same tab, which the single-parent model cannot express. | | Cross-recipient without prefill restructure | True cross-recipient logic (signer 2's visibility driven by signer 1's choice) requires restructuring the recipient list to add a prefill signer — a structural change, not a tab-level fix. | **The right platform for these cases is DocuSign Maestro (Workflow automation)**, which supports proper conditional branching, cross-step data references, and decision gateways. Templates with significant AND logic or cross-recipient conditionals should be flagged as Maestro candidates in the migration report. --- ## Proposed Implementation Phases ### Phase 24 — NOT_EQUALS expansion for dropdown parents - Detect `operator: NOT_EQUALS` where parent field is a `listTab` - Look up parent's `hiddenOptions`/`visibleOptions` from the Adobe source fields - Compute complement set (all options except the excluded value) - Emit one tab copy per remaining option with `conditionalParentValue = option` - Emit `NOT_EQUALS_EXPANDED` info issue - Emit `NOT_EQUALS_UNEXPANDABLE` warning for non-list parents (unchanged drop behavior) - Tests: unit tests for complement computation; regression snapshots updated ### Phase 25 — ANY multi-predicate fan-out - Detect `anyOrAll: ANY`, multiple predicates, all referencing the **same parent field**, all using `EQUALS` - Emit one tab copy per predicate value at the same coordinates with the same `tabLabel` - Emit `MULTI_PREDICATE_EXPANDED` info issue - Cases with mixed parents or non-EQUALS operators keep `MULTI_PREDICATE` warning - Tests: unit tests covering fan-out; mixed-parent case stays as warning ### Phase 26 — Richer issue guidance text - Update `HIDE_ACTION`, `CROSS_RECIPIENT_CONDITIONAL`, `INVALID_PARENT_TAB`, and `MULTI_PREDICATE` message strings to include specific manual fix instructions - No behavioral change — UI display only - Tests: update any tests that assert on exact message strings ### Phase 27 — Maestro escalation advisory - Add template-level `MAESTRO_RECOMMENDED` advisory (distinct from per-field issues) when a template contains unresolvable AND logic, cross-recipient conditionals, or HIDE actions that affect more than N fields (threshold TBD) - Surface in the Issues tab of the template detail view - No code generation — guidance only --- *Created: 2026-05-14. Companion documents: `field-mapping.md` (current-state reference), `docs/IMPLEMENTATION-PLAN.md` (feature history), `tests/EDGE-CASES.md` (known edge cases).*