---
title: "Preview a column definition"
method: POST
path: "/tables/{table_id}/columns/preview/"
tags: ["table-columns"]
---

# Preview a column definition

`POST /tables/{table_id}/columns/preview/`

## Request

- Base URL: `https://api.getoneprofile.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.getoneprofile.ai/tables/{table_id}/columns/preview/`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Evaluate an unsaved formula definition over the table's first 25 rows with the same data-type derivation the save path uses. Nothing is persisted and no run is requested. Every other kind of definition, including a Use AI or agent enrichment, is rejected with a 422 whose issue type is `column_kind_not_previewable`: to see what one of those fills in, create the column and run it on its first few rows.

## Path parameters

- `table_id` string, uuid, required

## Request body

- TableColumnPreviewRequestSchema: Request body for previewing an unsaved formula definition.
  - `definition` union, required: Discriminated union of column definitions. A ``RootModel`` is required because ``PydanticJSON`` needs a ``BaseModel`` subclass to (de)serialize the stored JSON. Consumers always access the concrete member via ``.root``.
    - ManualColumnDefinition: Definition of a manual column: typed, user-editable cells.
      - `default_value` union
        - string
        - integer
        - number
        - boolean
      - `kind` 'manual'
    - FormulaColumnDefinitionInput: Definition of a formula column: a pure-function chain over other columns.
      - `chain` union, required
        - TableCopyInput: Copy the input value unchanged.
          - `failure_mode` 'pass_through_raw' | 'set_null' | 'static' | 'skip': What a formula cell resolves to when a step in its chain fails. Applies to the whole chain, read off the top-level function only. ``SKIP`` is equivalent to ``SET_NULL`` for table cells (a cell always has a stored slot, so there is nothing to skip). Kept for shape compatibility.
          - `fallback_value` union
            - string
            - integer
            - number
            - boolean
          - `function` 'copy'
          - `next` union
            - TableCopyInput (recursive)
            - TableChangeCaseInput: Change the case of a string value.
              - …
            - TableTrimInput: Strip leading and trailing whitespace from a string value.
              - …
            - TableReplaceInput: Replace all occurrences of a substring.
              - …
            - TableRegexExtractInput: Extract a regex group from a string value.
              - …
            - TableRegexReplaceInput: Replace regex matches in a string value.
              - …
            - TableConcatenateInput: Join several values into one string. Sources are ORDERED and may mix columns with the results of earlier steps: ``[First name, step 2]`` and ``[step 2, First name]`` are different strings, which is why there is one list rather than a list of columns beside a list of steps. The field keeps its original name: every stored definition holds ``source_column_ids``, and the list is still overwhelmingly columns. Only the item type widened, so old definitions validate untouched.
              - …
            - TableArithmeticInput: Apply an arithmetic operator with a constant or column-valued operand.
              - …
            - TableRoundInput: Round a numeric value to a precision.
              - …
            - TableClampInput: Clamp a numeric value to an inclusive range.
              - …
            - TableDateFormatInput: Convert a date between iso/unix/unix_ms representations.
              - …
            - TableDateExtractInput: Extract a component (year, month, ...) from a date value.
              - …
            - TableDateArithmeticInput: Add or subtract a fixed duration from a date value.
              - …
            - TableListFirstInput: Take the first element of a list value.
              - …
            - TableListLastInput: Take the last element of a list value.
              - …
            - TableListNthInput: Take the element at an index of a list value.
              - …
            - TableListJoinInput: Join list elements into a string with a separator.
              - …
            - TableListCountInput: Count the elements of a list value.
              - …
            - TableListPluckInput: Pull one field out of every object in a list. Enrichment payloads routinely carry lists of objects (``[{"value": "Payroll"}, {"value": "HR"}]``) where the useful thing is the field, not the wrapper. Plucking turns that into ``["Payroll", "HR"]`` so ``list_join`` and friends can work on it; items without the field become empty and scalar items pass through unchanged.
              - …
            - TableListUniqueInput: De-duplicate list elements, keeping first-seen order.
              - …
            - TableListSplitInput: Split a string value into a list on a separator.
              - …
            - TableCoalesceInput: Substitute a default (a literal or another column) when the input is empty.
              - …
            - TableIfThenElseInput: Pick one of two values based on a comparison. Each of the three slots takes a literal or a column, so this expresses both "if this column is over that column" and "use A, else use B". Neither of those was reachable while they were constants.
              - …
            - TableConditionsInput: Fold several comparisons into ONE boolean. The engine's only boolean combinator, and the shape a column's ``run_condition`` is authored in: "only run where Employees > 50 AND Country is US". Nothing else here joins predicates: ``if_then_else`` compares exactly one pair and returns a value rather than a verdict. So without this a multi-clause gate could only be reached by chaining steps that pipe a truthy stand-in forward, which no editor could read back. One joiner over clauses and, at most one level down, groups of clauses: "A and (B or C)". That is precisely the row filter's shape, so a view's filter can be saved as a gate and read back as a filter without loss; a deeper tree would be expressible on one side only. Reads its clauses' operands directly and ignores the piped input, so it is a leaf rather than a transform.
              - …
            - TableValueMappingInput: Map input values through a lookup table.
              - …
            - TableToStringInput: Coerce the input to a string.
              - …
            - TableToIntInput: Coerce the input to an integer.
              - …
            - TableToFloatInput: Coerce the input to a float.
              - …
            - TableToBoolInput: Coerce the input to a boolean.
              - …
            - TableToDateInput: Coerce the input to a date.
              - …
            - TablePhoneE164Input: Normalize a phone number to E.164 format.
              - …
            - TableUtmParseInput: Extract a UTM parameter from a URL value.
              - …
            - TableUrlDomainInput: Reduce a URL to its bare registrable-looking host. A website field arrives as a whole URL (``https://www.acme.com/about``) but the thing that joins, dedupes and enriches is ``acme.com``. Doing it with ``regex_extract`` means every caller hand-writes the same fragile pattern, so the parse lives here once and uses a real URL parser.
              - …
            - TableCompanyDomainInput: Reduce a company's website URL to the company's own registrable domain. Three differences from ``url_domain``, which stays the generic read (a column of LinkedIn profile URLs legitimately reduces to ``linkedin.com`` there): Hosts that name a platform rather than the company (LinkedIn and Facebook pages, link aggregators, review sites, vendor partner directories) come out empty. A company whose only listed website is its LinkedIn page has no derivable domain, and an empty cell says so; ``linkedin.com`` is worse than empty because it joins, dedupes and syncs as if it were real. The result is the domain someone REGISTERED, not the bare host: a provider that lists ``careers.acme.com`` is describing ``acme.com``. A subdomain joins against nothing and sends an agent somewhere that often does not resolve. Page builders that give each customer their own label are the exception the Public Suffix List already encodes, so ``acme.wixsite.com`` survives whole rather than collapsing into ``wixsite.com``. ``company_name`` guards the case those two cannot: a directory listing reduces to the DIRECTORY owner's domain, so ``cloudpartners.transform.microsoft.com`` becomes ``microsoft.com``: right shape, wrong company, and nothing downstream can tell. Pointed at the column naming the employer, the domain is dropped when the two disagree. Optional: without it the other two rules still apply.
              - …
            - TableGetPathInput: Read a dotted path out of an object- or list-valued cell. Object and list columns were storable but unreadable: nothing in the catalog could reach a field inside one, so an enrichment payload landed in a cell and stopped there. Segments index dicts by key and lists by integer position: ``employees.count``, ``emails.0.address``. ``output_type`` is declared rather than derived because a JSON path can land on anything, and the column's data type has to be known before a single row is evaluated.
              - …
            - TableFormatInput: Build a string from a positional template and a list of arguments. ``concatenate`` joins whole columns with one separator, which cannot produce "Enterprise: Acme (12.4%)". Placeholders are positional only (``{0}``, ``{1}``) so the template stays data, not an expression language. Like ``concatenate`` this takes no ``source_column_id``: its inputs are its arguments, not the value flowing down the chain.
              - …
            - TableDateDiffInput: The signed duration between this step's date and another date. ``date_arithmetic`` shifts a date by a CONSTANT amount, so the gap between two date columns had no expression. Positive when the step's own date is the later of the two.
              - …
            - TableKeywordsInput: The most frequent meaningful words in a text or list value. Reads a body of text (a scraped page, a bio, a job description) and returns the words that carry its subject, ordered most frequent first. Stopwords ("the", "and", "with") are dropped: a frequency count that keeps them returns the same five words for every row and says nothing about any of them. Deterministic and pure: no model call, so a keyword column costs nothing and re-runs identically.
              - …
            - TableListFilterInput: Keep only the list items whose field passes a test. An enrichment payload lands as a list of objects (every job opening, every funding round, every contact) and the row usually wants a subset of it: the engineering roles, the rounds after 2024, the contacts with an email. Without this the whole list is the only thing a cell can hold. ``field`` is a dotted path INSIDE each item (``location.country``); leaving it empty tests the item itself, which is what a list of plain strings needs. ``exists``/``missing`` ignore ``value``: they ask only whether the field is there.
              - …
            - TableListSortInput: Order a list, ascending or descending. ``list_unique`` and ``list_join`` both preserve whatever order the source happened to arrive in, which is fine until the cell is meant to be READ: a top-3 of anything, a chronological history, an alphabetised tag list. ``field`` names the dotted path to sort objects BY; empty sorts the items themselves. Values that cannot be compared with each other (a number next to a string) are ordered by type first, so the sort is total instead of raising on the row where the data is mixed.
              - …
            - TableListIntersectInput: The values this list shares with another: the overlap, in the first list's order. The scoring question every ICP fit column asks: which of the buyer's tags, technologies or keywords are ALSO on my target list. Doing it by hand meant one ``if_then_else`` per tag. ``other`` is a column holding the second list, or literal text split on ``separator``. Matching ignores case and surrounding spaces, because the two lists come from different sources and "Shopify " never equals "shopify" when it matters most.
              - …
            - TableTextSimilarityInput: How alike two pieces of text are, as a percentage. The dedupe and match question: is "Acme Inc." the same company as "Acme, Inc"? An exact comparison says no and a human says obviously yes, so the honest answer is a number the row can threshold on. Case and surrounding whitespace never count: they are formatting, not difference. 100 means identical after that normalisation, 0 means nothing in common.
              - …
            - TableDetectLanguageInput: The language a piece of text is written in, as an ISO 639-1 code. Routes a row before anything expensive touches it: which sequence to enrol a lead into, which reviewer sees a scraped page, whether to translate at all. Script comes first (Cyrillic, Greek, Hebrew, Arabic, Han, kana and hangul each answer on their own) and Latin text is decided by the function words it uses. That is a heuristic, not a model: it is deterministic, free, and honest about not knowing, returning null when the text is too short or matches nothing.
              - …
            - TableScoreWordsInput: Score text by the weighted words it contains. The rules half of lead scoring, without a model: "enterprise" is worth 3, "student" is worth -5, and the cell adds up whatever the row's text, tags or tech stack actually say. Expressing the same thing with ``if_then_else`` needs one step per word and runs out of chain depth at ten. Weights are a plain object: word or phrase to number. Matching is case-insensitive; a multi-word key matches as a phrase. ``count_repeats`` decides whether saying "enterprise" three times scores three times, which is the difference between weighing a claim and weighing a page.
              - …
            - TableHashInput: Hash a value: the identifier ad platforms and clean rooms ask for. Uploading an audience means handing over hashed emails, never raw ones, and the hash has to be produced the way the platform specifies: lowercased and trimmed first, hex digest out. That normalisation is the part people get wrong by hand, so it happens here rather than in three chained steps.
              - …
            - TableUriEncodeInput: Percent-encode a value so it survives being put in a URL. Every search-URL column builds the same thing (a query string with a company name in it) and every one of them breaks on the first ampersand or accent. Encoding belongs one step before the URL is assembled, not in a regex chain that handles the four characters someone remembered. ``component`` escapes everything reserved, which is what a query value needs; ``full`` leaves ``:/?#`` alone so an entire URL stays usable. Lists are encoded item by item.
              - …
            - TableUrlValidInput: Whether a value is a usable web address. The gate in front of every scrape, screenshot and HTTP column: a row whose "website" cell holds "n/a", "coming soon" or a bare company name should never spend a credit finding that out. True means the value parses as a host with a real-looking domain, not that the site answers. A formula cannot make a request, and pretending otherwise would be the one dishonest thing this function could do.
              - …
            - TableEmailPermutationsInput: The candidate work-email addresses for a name at a domain. What a verifier needs to be pointed at: nine or so patterns companies actually use, in the order they are actually common, so the cheapest verification step has a list to work through instead of one guess. The piped value is the person's name: "Ada Lovelace", or a first name with ``last_name`` supplying the rest. Anything after the first and last token (middle names, suffixes) is ignored rather than permuted, which is what keeps the list nine long instead of ninety.
              - …
            - TableRoundRobinInput: Assign each row to one of a list of owners, evenly. Lead routing, as a column: the rep, the region, the sending inbox. The piped value is the row's IDENTITY (its email, domain or id) and the owner is derived from a hash of it rather than from the row's position. That is a deliberate departure from a counter-based round robin, and it is the only version that behaves: re-running the column, adding rows above, or sorting the view all leave every existing row with the owner it already had. A counter reassigns half the table the first time anything moves, which in a CRM means the wrong rep gets the follow-up.
              - …
            - TableWeightedRoundRobinInput: Assign each row to an owner, in proportion to each owner's share. The version real teams need: a senior rep takes three leads for every one a new hire gets, one region absorbs twice the volume of another. Shares are whole numbers and mean exactly what they look like: 3 and 1 is three quarters and one quarter. Stable per row for the same reason ``round_robin`` is: the owner comes from a hash of the row's identity, so nothing already assigned moves when the table grows or the view is sorted. Changing the SHARES does move rows, because that is what changing them means.
              - …
          - `source_column_id` string, uuid, nullable
          - `source_step` integer, nullable: Read the result of an EARLIER step, by 1-based position, instead of the step immediately before. Lets a later step fork back to an intermediate value (splitting a URL once and then using both the raw split and something derived from it), which a strict pipeline cannot express. Ignored when source_column_id is set (a column wins over a step), and ignored by functions that read their arguments rather than the piped value. None reads the previous step.
        - TableChangeCaseInput: Change the case of a string value.
          - `failure_mode` 'pass_through_raw' | 'set_null' | 'static' | 'skip': What a formula cell resolves to when a step in its chain fails. Applies to the whole chain, read off the top-level function only. ``SKIP`` is equivalent to ``SET_NULL`` for table cells (a cell always has a stored slot, so there is nothing to skip). Kept for shape compatibility.
          - `fallback_value` union
            - string
            - integer
            - number
            - boolean
          - `function` 'change_case'
          - `mode` 'lower' | 'upper' | 'title', required
          - `next` union
            - TableCopyInput: Copy the input value unchanged.
              - …
            - TableChangeCaseInput (recursive)
            - TableTrimInput: Strip leading and trailing whitespace from a string value.
              - …
            - TableReplaceInput: Replace all occurrences of a substring.
              - …
            - TableRegexExtractInput: Extract a regex group from a string value.
              - …
            - TableRegexReplaceInput: Replace regex matches in a string value.
              - …
            - TableConcatenateInput: Join several values into one string. Sources are ORDERED and may mix columns with the results of earlier steps: ``[First name, step 2]`` and ``[step 2, First name]`` are different strings, which is why there is one list rather than a list of columns beside a list of steps. The field keeps its original name: every stored definition holds ``source_column_ids``, and the list is still overwhelmingly columns. Only the item type widened, so old definitions validate untouched.
              - …
            - TableArithmeticInput: Apply an arithmetic operator with a constant or column-valued operand.
              - …
            - TableRoundInput: Round a numeric value to a precision.
              - …
            - TableClampInput: Clamp a numeric value to an inclusive range.
              - …
            - TableDateFormatInput: Convert a date between iso/unix/unix_ms representations.
              - …
            - TableDateExtractInput: Extract a component (year, month, ...) from a date value.
              - …
            - TableDateArithmeticInput: Add or subtract a fixed duration from a date value.
              - …
            - TableListFirstInput: Take the first element of a list value.
              - …
            - TableListLastInput: Take the last element of a list value.
              - …
            - TableListNthInput: Take the element at an index of a list value.
              - …
            - TableListJoinInput: Join list elements into a string with a separator.
              - …
            - TableListCountInput: Count the elements of a list value.
              - …
            - TableListPluckInput: Pull one field out of every object in a list. Enrichment payloads routinely carry lists of objects (``[{"value": "Payroll"}, {"value": "HR"}]``) where the useful thing is the field, not the wrapper. Plucking turns that into ``["Payroll", "HR"]`` so ``list_join`` and friends can work on it; items without the field become empty and scalar items pass through unchanged.
              - …
            - TableListUniqueInput: De-duplicate list elements, keeping first-seen order.
              - …
            - TableListSplitInput: Split a string value into a list on a separator.
              - …
            - TableCoalesceInput: Substitute a default (a literal or another column) when the input is empty.
              - …
            - TableIfThenElseInput: Pick one of two values based on a comparison. Each of the three slots takes a literal or a column, so this expresses both "if this column is over that column" and "use A, else use B". Neither of those was reachable while they were constants.
              - …
            - TableConditionsInput: Fold several comparisons into ONE boolean. The engine's only boolean combinator, and the shape a column's ``run_condition`` is authored in: "only run where Employees > 50 AND Country is US". Nothing else here joins predicates: ``if_then_else`` compares exactly one pair and returns a value rather than a verdict. So without this a multi-clause gate could only be reached by chaining steps that pipe a truthy stand-in forward, which no editor could read back. One joiner over clauses and, at most one level down, groups of clauses: "A and (B or C)". That is precisely the row filter's shape, so a view's filter can be saved as a gate and read back as a filter without loss; a deeper tree would be expressible on one side only. Reads its clauses' operands directly and ignores the piped input, so it is a leaf rather than a transform.
              - …
            - TableValueMappingInput: Map input values through a lookup table.
              - …
            - TableToStringInput: Coerce the input to a string.
              - …
            - TableToIntInput: Coerce the input to an integer.
              - …
            - TableToFloatInput: Coerce the input to a float.
              - …
            - TableToBoolInput: Coerce the input to a boolean.
              - …
            - TableToDateInput: Coerce the input to a date.
              - …
            - TablePhoneE164Input: Normalize a phone number to E.164 format.
              - …
            - TableUtmParseInput: Extract a UTM parameter from a URL value.
              - …
            - TableUrlDomainInput: Reduce a URL to its bare registrable-looking host. A website field arrives as a whole URL (``https://www.acme.com/about``) but the thing that joins, dedupes and enriches is ``acme.com``. Doing it with ``regex_extract`` means every caller hand-writes the same fragile pattern, so the parse lives here once and uses a real URL parser.
              - …
            - TableCompanyDomainInput: Reduce a company's website URL to the company's own registrable domain. Three differences from ``url_domain``, which stays the generic read (a column of LinkedIn profile URLs legitimately reduces to ``linkedin.com`` there): Hosts that name a platform rather than the company (LinkedIn and Facebook pages, link aggregators, review sites, vendor partner directories) come out empty. A company whose only listed website is its LinkedIn page has no derivable domain, and an empty cell says so; ``linkedin.com`` is worse than empty because it joins, dedupes and syncs as if it were real. The result is the domain someone REGISTERED, not the bare host: a provider that lists ``careers.acme.com`` is describing ``acme.com``. A subdomain joins against nothing and sends an agent somewhere that often does not resolve. Page builders that give each customer their own label are the exception the Public Suffix List already encodes, so ``acme.wixsite.com`` survives whole rather than collapsing into ``wixsite.com``. ``company_name`` guards the case those two cannot: a directory listing reduces to the DIRECTORY owner's domain, so ``cloudpartners.transform.microsoft.com`` becomes ``microsoft.com``: right shape, wrong company, and nothing downstream can tell. Pointed at the column naming the employer, the domain is dropped when the two disagree. Optional: without it the other two rules still apply.
              - …
            - TableGetPathInput: Read a dotted path out of an object- or list-valued cell. Object and list columns were storable but unreadable: nothing in the catalog could reach a field inside one, so an enrichment payload landed in a cell and stopped there. Segments index dicts by key and lists by integer position: ``employees.count``, ``emails.0.address``. ``output_type`` is declared rather than derived because a JSON path can land on anything, and the column's data type has to be known before a single row is evaluated.
              - …
            - TableFormatInput: Build a string from a positional template and a list of arguments. ``concatenate`` joins whole columns with one separator, which cannot produce "Enterprise: Acme (12.4%)". Placeholders are positional only (``{0}``, ``{1}``) so the template stays data, not an expression language. Like ``concatenate`` this takes no ``source_column_id``: its inputs are its arguments, not the value flowing down the chain.
              - …
            - TableDateDiffInput: The signed duration between this step's date and another date. ``date_arithmetic`` shifts a date by a CONSTANT amount, so the gap between two date columns had no expression. Positive when the step's own date is the later of the two.
              - …
            - TableKeywordsInput: The most frequent meaningful words in a text or list value. Reads a body of text (a scraped page, a bio, a job description) and returns the words that carry its subject, ordered most frequent first. Stopwords ("the", "and", "with") are dropped: a frequency count that keeps them returns the same five words for every row and says nothing about any of them. Deterministic and pure: no model call, so a keyword column costs nothing and re-runs identically.
              - …
            - TableListFilterInput: Keep only the list items whose field passes a test. An enrichment payload lands as a list of objects (every job opening, every funding round, every contact) and the row usually wants a subset of it: the engineering roles, the rounds after 2024, the contacts with an email. Without this the whole list is the only thing a cell can hold. ``field`` is a dotted path INSIDE each item (``location.country``); leaving it empty tests the item itself, which is what a list of plain strings needs. ``exists``/``missing`` ignore ``value``: they ask only whether the field is there.
              - …
            - TableListSortInput: Order a list, ascending or descending. ``list_unique`` and ``list_join`` both preserve whatever order the source happened to arrive in, which is fine until the cell is meant to be READ: a top-3 of anything, a chronological history, an alphabetised tag list. ``field`` names the dotted path to sort objects BY; empty sorts the items themselves. Values that cannot be compared with each other (a number next to a string) are ordered by type first, so the sort is total instead of raising on the row where the data is mixed.
              - …
            - TableListIntersectInput: The values this list shares with another: the overlap, in the first list's order. The scoring question every ICP fit column asks: which of the buyer's tags, technologies or keywords are ALSO on my target list. Doing it by hand meant one ``if_then_else`` per tag. ``other`` is a column holding the second list, or literal text split on ``separator``. Matching ignores case and surrounding spaces, because the two lists come from different sources and "Shopify " never equals "shopify" when it matters most.
              - …
            - TableTextSimilarityInput: How alike two pieces of text are, as a percentage. The dedupe and match question: is "Acme Inc." the same company as "Acme, Inc"? An exact comparison says no and a human says obviously yes, so the honest answer is a number the row can threshold on. Case and surrounding whitespace never count: they are formatting, not difference. 100 means identical after that normalisation, 0 means nothing in common.
              - …
            - TableDetectLanguageInput: The language a piece of text is written in, as an ISO 639-1 code. Routes a row before anything expensive touches it: which sequence to enrol a lead into, which reviewer sees a scraped page, whether to translate at all. Script comes first (Cyrillic, Greek, Hebrew, Arabic, Han, kana and hangul each answer on their own) and Latin text is decided by the function words it uses. That is a heuristic, not a model: it is deterministic, free, and honest about not knowing, returning null when the text is too short or matches nothing.
              - …
            - TableScoreWordsInput: Score text by the weighted words it contains. The rules half of lead scoring, without a model: "enterprise" is worth 3, "student" is worth -5, and the cell adds up whatever the row's text, tags or tech stack actually say. Expressing the same thing with ``if_then_else`` needs one step per word and runs out of chain depth at ten. Weights are a plain object: word or phrase to number. Matching is case-insensitive; a multi-word key matches as a phrase. ``count_repeats`` decides whether saying "enterprise" three times scores three times, which is the difference between weighing a claim and weighing a page.
              - …
            - TableHashInput: Hash a value: the identifier ad platforms and clean rooms ask for. Uploading an audience means handing over hashed emails, never raw ones, and the hash has to be produced the way the platform specifies: lowercased and trimmed first, hex digest out. That normalisation is the part people get wrong by hand, so it happens here rather than in three chained steps.
              - …
            - TableUriEncodeInput: Percent-encode a value so it survives being put in a URL. Every search-URL column builds the same thing (a query string with a company name in it) and every one of them breaks on the first ampersand or accent. Encoding belongs one step before the URL is assembled, not in a regex chain that handles the four characters someone remembered. ``component`` escapes everything reserved, which is what a query value needs; ``full`` leaves ``:/?#`` alone so an entire URL stays usable. Lists are encoded item by item.
              - …
            - TableUrlValidInput: Whether a value is a usable web address. The gate in front of every scrape, screenshot and HTTP column: a row whose "website" cell holds "n/a", "coming soon" or a bare company name should never spend a credit finding that out. True means the value parses as a host with a real-looking domain, not that the site answers. A formula cannot make a request, and pretending otherwise would be the one dishonest thing this function could do.
              - …
            - TableEmailPermutationsInput: The candidate work-email addresses for a name at a domain. What a verifier needs to be pointed at: nine or so patterns companies actually use, in the order they are actually common, so the cheapest verification step has a list to work through instead of one guess. The piped value is the person's name: "Ada Lovelace", or a first name with ``last_name`` supplying the rest. Anything after the first and last token (middle names, suffixes) is ignored rather than permuted, which is what keeps the list nine long instead of ninety.
              - …
            - TableRoundRobinInput: Assign each row to one of a list of owners, evenly. Lead routing, as a column: the rep, the region, the sending inbox. The piped value is the row's IDENTITY (its email, domain or id) and the owner is derived from a hash of it rather than from the row's position. That is a deliberate departure from a counter-based round robin, and it is the only version that behaves: re-running the column, adding rows above, or sorting the view all leave every existing row with the owner it already had. A counter reassigns half the table the first time anything moves, which in a CRM means the wrong rep gets the follow-up.
              - …
            - TableWeightedRoundRobinInput: Assign each row to an owner, in proportion to each owner's share. The version real teams need: a senior rep takes three leads for every one a new hire gets, one region absorbs twice the volume of another. Shares are whole numbers and mean exactly what they look like: 3 and 1 is three quarters and one quarter. Stable per row for the same reason ``round_robin`` is: the owner comes from a hash of the row's identity, so nothing already assigned moves when the table grows or the view is sorted. Changing the SHARES does move rows, because that is what changing them means.
              - …
          - `source_column_id` string, uuid, nullable
          - `source_step` integer, nullable: Read the result of an EARLIER step, by 1-based position, instead of the step immediately before. Lets a later step fork back to an intermediate value (splitting a URL once and then using both the raw split and something derived from it), which a strict pipeline cannot express. Ignored when source_column_id is set (a column wins over a step), and ignored by functions that read their arguments rather than the piped value. None reads the previous step.
        - TableTrimInput: Strip leading and trailing whitespace from a string value.
          - `failure_mode` 'pass_through_raw' | 'set_null' | 'static' | 'skip': What a formula cell resolves to when a step in its chain fails. Applies to the whole chain, read off the top-level function only. ``SKIP`` is equivalent to ``SET_NULL`` for table cells (a cell always has a stored slot, so there is nothing to skip). Kept for shape compatibility.
          - `fallback_value` union
            - string
            - integer
            - number
            - boolean
          - `function` 'trim'
          - `next` union
            - TableCopyInput: Copy the input value unchanged.
              - …
            - TableChangeCaseInput: Change the case of a string value.
              - …
            - TableTrimInput (recursive)
            - TableReplaceInput: Replace all occurrences of a substring.
              - …
            - TableRegexExtractInput: Extract a regex group from a string value.
              - …
            - TableRegexReplaceInput: Replace regex matches in a string value.
              - …
            - TableConcatenateInput: Join several values into one string. Sources are ORDERED and may mix columns with the results of earlier steps: ``[First name, step 2]`` and ``[step 2, First name]`` are different strings, which is why there is one list rather than a list of columns beside a list of steps. The field keeps its original name: every stored definition holds ``source_column_ids``, and the list is still overwhelmingly columns. Only the item type widened, so old definitions validate untouched.
              - …
            - TableArithmeticInput: Apply an arithmetic operator with a constant or column-valued operand.
              - …
            - TableRoundInput: Round a numeric value to a precision.
              - …
            - TableClampInput: Clamp a numeric value to an inclusive range.
              - …
            - TableDateFormatInput: Convert a date between iso/unix/unix_ms representations.
              - …
            - TableDateExtractInput: Extract a component (year, month, ...) from a date value.
              - …
            - TableDateArithmeticInput: Add or subtract a fixed duration from a date value.
              - …
            - TableListFirstInput: Take the first element of a list value.
              - …
            - TableListLastInput: Take the last element of a list value.
              - …
            - TableListNthInput: Take the element at an index of a list value.
              - …
            - TableListJoinInput: Join list elements into a string with a separator.
              - …
            - TableListCountInput: Count the elements of a list value.
              - …
            - TableListPluckInput: Pull one field out of every object in a list. Enrichment payloads routinely carry lists of objects (``[{"value": "Payroll"}, {"value": "HR"}]``) where the useful thing is the field, not the wrapper. Plucking turns that into ``["Payroll", "HR"]`` so ``list_join`` and friends can work on it; items without the field become empty and scalar items pass through unchanged.
              - …
            - TableListUniqueInput: De-duplicate list elements, keeping first-seen order.
              - …
            - TableListSplitInput: Split a string value into a list on a separator.
              - …
            - TableCoalesceInput: Substitute a default (a literal or another column) when the input is empty.
              - …
            - TableIfThenElseInput: Pick one of two values based on a comparison. Each of the three slots takes a literal or a column, so this expresses both "if this column is over that column" and "use A, else use B". Neither of those was reachable while they were constants.
              - …
            - TableConditionsInput: Fold several comparisons into ONE boolean. The engine's only boolean combinator, and the shape a column's ``run_condition`` is authored in: "only run where Employees > 50 AND Country is US". Nothing else here joins predicates: ``if_then_else`` compares exactly one pair and returns a value rather than a verdict. So without this a multi-clause gate could only be reached by chaining steps that pipe a truthy stand-in forward, which no editor could read back. One joiner over clauses and, at most one level down, groups of clauses: "A and (B or C)". That is precisely the row filter's shape, so a view's filter can be saved as a gate and read back as a filter without loss; a deeper tree would be expressible on one side only. Reads its clauses' operands directly and ignores the piped input, so it is a leaf rather than a transform.
              - …
            - TableValueMappingInput: Map input values through a lookup table.
              - …
            - TableToStringInput: Coerce the input to a string.
              - …
            - TableToIntInput: Coerce the input to an integer.
              - …
            - TableToFloatInput: Coerce the input to a float.
              - …
            - TableToBoolInput: Coerce the input to a boolean.
              - …
            - TableToDateInput: Coerce the input to a date.
              - …
            - TablePhoneE164Input: Normalize a phone number to E.164 format.
              - …
            - TableUtmParseInput: Extract a UTM parameter from a URL value.
              - …
            - TableUrlDomainInput: Reduce a URL to its bare registrable-looking host. A website field arrives as a whole URL (``https://www.acme.com/about``) but the thing that joins, dedupes and enriches is ``acme.com``. Doing it with ``regex_extract`` means every caller hand-writes the same fragile pattern, so the parse lives here once and uses a real URL parser.
              - …
            - TableCompanyDomainInput: Reduce a company's website URL to the company's own registrable domain. Three differences from ``url_domain``, which stays the generic read (a column of LinkedIn profile URLs legitimately reduces to ``linkedin.com`` there): Hosts that name a platform rather than the company (LinkedIn and Facebook pages, link aggregators, review sites, vendor partner directories) come out empty. A company whose only listed website is its LinkedIn page has no derivable domain, and an empty cell says so; ``linkedin.com`` is worse than empty because it joins, dedupes and syncs as if it were real. The result is the domain someone REGISTERED, not the bare host: a provider that lists ``careers.acme.com`` is describing ``acme.com``. A subdomain joins against nothing and sends an agent somewhere that often does not resolve. Page builders that give each customer their own label are the exception the Public Suffix List already encodes, so ``acme.wixsite.com`` survives whole rather than collapsing into ``wixsite.com``. ``company_name`` guards the case those two cannot: a directory listing reduces to the DIRECTORY owner's domain, so ``cloudpartners.transform.microsoft.com`` becomes ``microsoft.com``: right shape, wrong company, and nothing downstream can tell. Pointed at the column naming the employer, the domain is dropped when the two disagree. Optional: without it the other two rules still apply.
              - …
            - TableGetPathInput: Read a dotted path out of an object- or list-valued cell. Object and list columns were storable but unreadable: nothing in the catalog could reach a field inside one, so an enrichment payload landed in a cell and stopped there. Segments index dicts by key and lists by integer position: ``employees.count``, ``emails.0.address``. ``output_type`` is declared rather than derived because a JSON path can land on anything, and the column's data type has to be known before a single row is evaluated.
              - …
            - TableFormatInput: Build a string from a positional template and a list of arguments. ``concatenate`` joins whole columns with one separator, which cannot produce "Enterprise: Acme (12.4%)". Placeholders are positional only (``{0}``, ``{1}``) so the template stays data, not an expression language. Like ``concatenate`` this takes no ``source_column_id``: its inputs are its arguments, not the value flowing down the chain.
              - …
            - TableDateDiffInput: The signed duration between this step's date and another date. ``date_arithmetic`` shifts a date by a CONSTANT amount, so the gap between two date columns had no expression. Positive when the step's own date is the later of the two.
              - …
            - TableKeywordsInput: The most frequent meaningful words in a text or list value. Reads a body of text (a scraped page, a bio, a job description) and returns the words that carry its subject, ordered most frequent first. Stopwords ("the", "and", "with") are dropped: a frequency count that keeps them returns the same five words for every row and says nothing about any of them. Deterministic and pure: no model call, so a keyword column costs nothing and re-runs identically.
              - …
            - TableListFilterInput: Keep only the list items whose field passes a test. An enrichment payload lands as a list of objects (every job opening, every funding round, every contact) and the row usually wants a subset of it: the engineering roles, the rounds after 2024, the contacts with an email. Without this the whole list is the only thing a cell can hold. ``field`` is a dotted path INSIDE each item (``location.country``); leaving it empty tests the item itself, which is what a list of plain strings needs. ``exists``/``missing`` ignore ``value``: they ask only whether the field is there.
              - …
            - TableListSortInput: Order a list, ascending or descending. ``list_unique`` and ``list_join`` both preserve whatever order the source happened to arrive in, which is fine until the cell is meant to be READ: a top-3 of anything, a chronological history, an alphabetised tag list. ``field`` names the dotted path to sort objects BY; empty sorts the items themselves. Values that cannot be compared with each other (a number next to a string) are ordered by type first, so the sort is total instead of raising on the row where the data is mixed.
              - …
            - TableListIntersectInput: The values this list shares with another: the overlap, in the first list's order. The scoring question every ICP fit column asks: which of the buyer's tags, technologies or keywords are ALSO on my target list. Doing it by hand meant one ``if_then_else`` per tag. ``other`` is a column holding the second list, or literal text split on ``separator``. Matching ignores case and surrounding spaces, because the two lists come from different sources and "Shopify " never equals "shopify" when it matters most.
              - …
            - TableTextSimilarityInput: How alike two pieces of text are, as a percentage. The dedupe and match question: is "Acme Inc." the same company as "Acme, Inc"? An exact comparison says no and a human says obviously yes, so the honest answer is a number the row can threshold on. Case and surrounding whitespace never count: they are formatting, not difference. 100 means identical after that normalisation, 0 means nothing in common.
              - …
            - TableDetectLanguageInput: The language a piece of text is written in, as an ISO 639-1 code. Routes a row before anything expensive touches it: which sequence to enrol a lead into, which reviewer sees a scraped page, whether to translate at all. Script comes first (Cyrillic, Greek, Hebrew, Arabic, Han, kana and hangul each answer on their own) and Latin text is decided by the function words it uses. That is a heuristic, not a model: it is deterministic, free, and honest about not knowing, returning null when the text is too short or matches nothing.
              - …
            - TableScoreWordsInput: Score text by the weighted words it contains. The rules half of lead scoring, without a model: "enterprise" is worth 3, "student" is worth -5, and the cell adds up whatever the row's text, tags or tech stack actually say. Expressing the same thing with ``if_then_else`` needs one step per word and runs out of chain depth at ten. Weights are a plain object: word or phrase to number. Matching is case-insensitive; a multi-word key matches as a phrase. ``count_repeats`` decides whether saying "enterprise" three times scores three times, which is the difference between weighing a claim and weighing a page.
              - …
            - TableHashInput: Hash a value: the identifier ad platforms and clean rooms ask for. Uploading an audience means handing over hashed emails, never raw ones, and the hash has to be produced the way the platform specifies: lowercased and trimmed first, hex digest out. That normalisation is the part people get wrong by hand, so it happens here rather than in three chained steps.
              - …
            - TableUriEncodeInput: Percent-encode a value so it survives being put in a URL. Every search-URL column builds the same thing (a query string with a company name in it) and every one of them breaks on the first ampersand or accent. Encoding belongs one step before the URL is assembled, not in a regex chain that handles the four characters someone remembered. ``component`` escapes everything reserved, which is what a query value needs; ``full`` leaves ``:/?#`` alone so an entire URL stays usable. Lists are encoded item by item.
              - …
            - TableUrlValidInput: Whether a value is a usable web address. The gate in front of every scrape, screenshot and HTTP column: a row whose "website" cell holds "n/a", "coming soon" or a bare company name should never spend a credit finding that out. True means the value parses as a host with a real-looking domain, not that the site answers. A formula cannot make a request, and pretending otherwise would be the one dishonest thing this function could do.
              - …
            - TableEmailPermutationsInput: The candidate work-email addresses for a name at a domain. What a verifier needs to be pointed at: nine or so patterns companies actually use, in the order they are actually common, so the cheapest verification step has a list to work through instead of one guess. The piped value is the person's name: "Ada Lovelace", or a first name with ``last_name`` supplying the rest. Anything after the first and last token (middle names, suffixes) is ignored rather than permuted, which is what keeps the list nine long instead of ninety.
              - …
            - TableRoundRobinInput: Assign each row to one of a list of owners, evenly. Lead routing, as a column: the rep, the region, the sending inbox. The piped value is the row's IDENTITY (its email, domain or id) and the owner is derived from a hash of it rather than from the row's position. That is a deliberate departure from a counter-based round robin, and it is the only version that behaves: re-running the column, adding rows above, or sorting the view all leave every existing row with the owner it already had. A counter reassigns half the table the first time anything moves, which in a CRM means the wrong rep gets the follow-up.
              - …
            - TableWeightedRoundRobinInput: Assign each row to an owner, in proportion to each owner's share. The version real teams need: a senior rep takes three leads for every one a new hire gets, one region absorbs twice the volume of another. Shares are whole numbers and mean exactly what they look like: 3 and 1 is three quarters and one quarter. Stable per row for the same reason ``round_robin`` is: the owner comes from a hash of the row's identity, so nothing already assigned moves when the table grows or the view is sorted. Changing the SHARES does move rows, because that is what changing them means.
              - …
          - `source_column_id` string, uuid, nullable
          - `source_step` integer, nullable: Read the result of an EARLIER step, by 1-based position, instead of the step immediately before. Lets a later step fork back to an intermediate value (splitting a URL once and then using both the raw split and something derived from it), which a strict pipeline cannot express. Ignored when source_column_id is set (a column wins over a step), and ignored by functions that read their arguments rather than the piped value. None reads the previous step.
        - TableReplaceInput: Replace all occurrences of a substring.
          - `failure_mode` 'pass_through_raw' | 'set_null' | 'static' | 'skip': What a formula cell resolves to when a step in its chain fails. Applies to the whole chain, read off the top-level function only. ``SKIP`` is equivalent to ``SET_NULL`` for table cells (a cell always has a stored slot, so there is nothing to skip). Kept for shape compatibility.
          - `fallback_value` union
            - string
            - integer
            - number
            - boolean
          - `function` 'replace'
          - `new` string, required
          - `next` union
            - TableCopyInput: Copy the input value unchanged.
              - …
            - TableChangeCaseInput: Change the case of a string value.
              - …
            - TableTrimInput: Strip leading and trailing whitespace from a string value.
              - …
            - TableReplaceInput (recursive)
            - TableRegexExtractInput: Extract a regex group from a string value.
              - …
            - TableRegexReplaceInput: Replace regex matches in a string value.
              - …
            - TableConcatenateInput: Join several values into one string. Sources are ORDERED and may mix columns with the results of earlier steps: ``[First name, step 2]`` and ``[step 2, First name]`` are different strings, which is why there is one list rather than a list of columns beside a list of steps. The field keeps its original name: every stored definition holds ``source_column_ids``, and the list is still overwhelmingly columns. Only the item type widened, so old definitions validate untouched.
              - …
            - TableArithmeticInput: Apply an arithmetic operator with a constant or column-valued operand.
              - …
            - TableRoundInput: Round a numeric value to a precision.
              - …
            - TableClampInput: Clamp a numeric value to an inclusive range.
              - …
            - TableDateFormatInput: Convert a date between iso/unix/unix_ms representations.
              - …
            - TableDateExtractInput: Extract a component (year, month, ...) from a date value.
              - …
            - TableDateArithmeticInput: Add or subtract a fixed duration from a date value.
              - …
            - TableListFirstInput: Take the first element of a list value.
              - …
            - TableListLastInput: Take the last element of a list value.
              - …
            - TableListNthInput: Take the element at an index of a list value.
              - …
            - TableListJoinInput: Join list elements into a string with a separator.
              - …
            - TableListCountInput: Count the elements of a list value.
              - …
            - TableListPluckInput: Pull one field out of every object in a list. Enrichment payloads routinely carry lists of objects (``[{"value": "Payroll"}, {"value": "HR"}]``) where the useful thing is the field, not the wrapper. Plucking turns that into ``["Payroll", "HR"]`` so ``list_join`` and friends can work on it; items without the field become empty and scalar items pass through unchanged.
              - …
            - TableListUniqueInput: De-duplicate list elements, keeping first-seen order.
              - …
            - TableListSplitInput: Split a string value into a list on a separator.
              - …
            - TableCoalesceInput: Substitute a default (a literal or another column) when the input is empty.
              - …
            - TableIfThenElseInput: Pick one of two values based on a comparison. Each of the three slots takes a literal or a column, so this expresses both "if this column is over that column" and "use A, else use B". Neither of those was reachable while they were constants.
              - …
            - TableConditionsInput: Fold several comparisons into ONE boolean. The engine's only boolean combinator, and the shape a column's ``run_condition`` is authored in: "only run where Employees > 50 AND Country is US". Nothing else here joins predicates: ``if_then_else`` compares exactly one pair and returns a value rather than a verdict. So without this a multi-clause gate could only be reached by chaining steps that pipe a truthy stand-in forward, which no editor could read back. One joiner over clauses and, at most one level down, groups of clauses: "A and (B or C)". That is precisely the row filter's shape, so a view's filter can be saved as a gate and read back as a filter without loss; a deeper tree would be expressible on one side only. Reads its clauses' operands directly and ignores the piped input, so it is a leaf rather than a transform.
              - …
            - TableValueMappingInput: Map input values through a lookup table.
              - …
            - TableToStringInput: Coerce the input to a string.
              - …
            - TableToIntInput: Coerce the input to an integer.
              - …
            - TableToFloatInput: Coerce the input to a float.
              - …
            - TableToBoolInput: Coerce the input to a boolean.
              - …
            - TableToDateInput: Coerce the input to a date.
              - …
            - TablePhoneE164Input: Normalize a phone number to E.164 format.
              - …
            - TableUtmParseInput: Extract a UTM parameter from a URL value.
              - …
            - TableUrlDomainInput: Reduce a URL to its bare registrable-looking host. A website field arrives as a whole URL (``https://www.acme.com/about``) but the thing that joins, dedupes and enriches is ``acme.com``. Doing it with ``regex_extract`` means every caller hand-writes the same fragile pattern, so the parse lives here once and uses a real URL parser.
              - …
            - TableCompanyDomainInput: Reduce a company's website URL to the company's own registrable domain. Three differences from ``url_domain``, which stays the generic read (a column of LinkedIn profile URLs legitimately reduces to ``linkedin.com`` there): Hosts that name a platform rather than the company (LinkedIn and Facebook pages, link aggregators, review sites, vendor partner directories) come out empty. A company whose only listed website is its LinkedIn page has no derivable domain, and an empty cell says so; ``linkedin.com`` is worse than empty because it joins, dedupes and syncs as if it were real. The result is the domain someone REGISTERED, not the bare host: a provider that lists ``careers.acme.com`` is describing ``acme.com``. A subdomain joins against nothing and sends an agent somewhere that often does not resolve. Page builders that give each customer their own label are the exception the Public Suffix List already encodes, so ``acme.wixsite.com`` survives whole rather than collapsing into ``wixsite.com``. ``company_name`` guards the case those two cannot: a directory listing reduces to the DIRECTORY owner's domain, so ``cloudpartners.transform.microsoft.com`` becomes ``microsoft.com``: right shape, wrong company, and nothing downstream can tell. Pointed at the column naming the employer, the domain is dropped when the two disagree. Optional: without it the other two rules still apply.
              - …
            - TableGetPathInput: Read a dotted path out of an object- or list-valued cell. Object and list columns were storable but unreadable: nothing in the catalog could reach a field inside one, so an enrichment payload landed in a cell and stopped there. Segments index dicts by key and lists by integer position: ``employees.count``, ``emails.0.address``. ``output_type`` is declared rather than derived because a JSON path can land on anything, and the column's data type has to be known before a single row is evaluated.
              - …
            - TableFormatInput: Build a string from a positional template and a list of arguments. ``concatenate`` joins whole columns with one separator, which cannot produce "Enterprise: Acme (12.4%)". Placeholders are positional only (``{0}``, ``{1}``) so the template stays data, not an expression language. Like ``concatenate`` this takes no ``source_column_id``: its inputs are its arguments, not the value flowing down the chain.
              - …
            - TableDateDiffInput: The signed duration between this step's date and another date. ``date_arithmetic`` shifts a date by a CONSTANT amount, so the gap between two date columns had no expression. Positive when the step's own date is the later of the two.
              - …
            - TableKeywordsInput: The most frequent meaningful words in a text or list value. Reads a body of text (a scraped page, a bio, a job description) and returns the words that carry its subject, ordered most frequent first. Stopwords ("the", "and", "with") are dropped: a frequency count that keeps them returns the same five words for every row and says nothing about any of them. Deterministic and pure: no model call, so a keyword column costs nothing and re-runs identically.
              - …
            - TableListFilterInput: Keep only the list items whose field passes a test. An enrichment payload lands as a list of objects (every job opening, every funding round, every contact) and the row usually wants a subset of it: the engineering roles, the rounds after 2024, the contacts with an email. Without this the whole list is the only thing a cell can hold. ``field`` is a dotted path INSIDE each item (``location.country``); leaving it empty tests the item itself, which is what a list of plain strings needs. ``exists``/``missing`` ignore ``value``: they ask only whether the field is there.
              - …
            - TableListSortInput: Order a list, ascending or descending. ``list_unique`` and ``list_join`` both preserve whatever order the source happened to arrive in, which is fine until the cell is meant to be READ: a top-3 of anything, a chronological history, an alphabetised tag list. ``field`` names the dotted path to sort objects BY; empty sorts the items themselves. Values that cannot be compared with each other (a number next to a string) are ordered by type first, so the sort is total instead of raising on the row where the data is mixed.
              - …
            - TableListIntersectInput: The values this list shares with another: the overlap, in the first list's order. The scoring question every ICP fit column asks: which of the buyer's tags, technologies or keywords are ALSO on my target list. Doing it by hand meant one ``if_then_else`` per tag. ``other`` is a column holding the second list, or literal text split on ``separator``. Matching ignores case and surrounding spaces, because the two lists come from different sources and "Shopify " never equals "shopify" when it matters most.
              - …
            - TableTextSimilarityInput: How alike two pieces of text are, as a percentage. The dedupe and match question: is "Acme Inc." the same company as "Acme, Inc"? An exact comparison says no and a human says obviously yes, so the honest answer is a number the row can threshold on. Case and surrounding whitespace never count: they are formatting, not difference. 100 means identical after that normalisation, 0 means nothing in common.
              - …
            - TableDetectLanguageInput: The language a piece of text is written in, as an ISO 639-1 code. Routes a row before anything expensive touches it: which sequence to enrol a lead into, which reviewer sees a scraped page, whether to translate at all. Script comes first (Cyrillic, Greek, Hebrew, Arabic, Han, kana and hangul each answer on their own) and Latin text is decided by the function words it uses. That is a heuristic, not a model: it is deterministic, free, and honest about not knowing, returning null when the text is too short or matches nothing.
              - …
            - TableScoreWordsInput: Score text by the weighted words it contains. The rules half of lead scoring, without a model: "enterprise" is worth 3, "student" is worth -5, and the cell adds up whatever the row's text, tags or tech stack actually say. Expressing the same thing with ``if_then_else`` needs one step per word and runs out of chain depth at ten. Weights are a plain object: word or phrase to number. Matching is case-insensitive; a multi-word key matches as a phrase. ``count_repeats`` decides whether saying "enterprise" three times scores three times, which is the difference between weighing a claim and weighing a page.
              - …
            - TableHashInput: Hash a value: the identifier ad platforms and clean rooms ask for. Uploading an audience means handing over hashed emails, never raw ones, and the hash has to be produced the way the platform specifies: lowercased and trimmed first, hex digest out. That normalisation is the part people get wrong by hand, so it happens here rather than in three chained steps.
              - …
            - TableUriEncodeInput: Percent-encode a value so it survives being put in a URL. Every search-URL column builds the same thing (a query string with a company name in it) and every one of them breaks on the first ampersand or accent. Encoding belongs one step before the URL is assembled, not in a regex chain that handles the four characters someone remembered. ``component`` escapes everything reserved, which is what a query value needs; ``full`` leaves ``:/?#`` alone so an entire URL stays usable. Lists are encoded item by item.
              - …
            - TableUrlValidInput: Whether a value is a usable web address. The gate in front of every scrape, screenshot and HTTP column: a row whose "website" cell holds "n/a", "coming soon" or a bare company name should never spend a credit finding that out. True means the value parses as a host with a real-looking domain, not that the site answers. A formula cannot make a request, and pretending otherwise would be the one dishonest thing this function could do.
              - …
            - TableEmailPermutationsInput: The candidate work-email addresses for a name at a domain. What a verifier needs to be pointed at: nine or so patterns companies actually use, in the order they are actually common, so the cheapest verification step has a list to work through instead of one guess. The piped value is the person's name: "Ada Lovelace", or a first name with ``last_name`` supplying the rest. Anything after the first and last token (middle names, suffixes) is ignored rather than permuted, which is what keeps the list nine long instead of ninety.
              - …
            - TableRoundRobinInput: Assign each row to one of a list of owners, evenly. Lead routing, as a column: the rep, the region, the sending inbox. The piped value is the row's IDENTITY (its email, domain or id) and the owner is derived from a hash of it rather than from the row's position. That is a deliberate departure from a counter-based round robin, and it is the only version that behaves: re-running the column, adding rows above, or sorting the view all leave every existing row with the owner it already had. A counter reassigns half the table the first time anything moves, which in a CRM means the wrong rep gets the follow-up.
              - …
            - TableWeightedRoundRobinInput: Assign each row to an owner, in proportion to each owner's share. The version real teams need: a senior rep takes three leads for every one a new hire gets, one region absorbs twice the volume of another. Shares are whole numbers and mean exactly what they look like: 3 and 1 is three quarters and one quarter. Stable per row for the same reason ``round_robin`` is: the owner comes from a hash of the row's identity, so nothing already assigned moves when the table grows or the view is sorted. Changing the SHARES does move rows, because that is what changing them means.
              - …
          - `old` string, required
          - `source_column_id` string, uuid, nullable
          - `source_step` integer, nullable: Read the result of an EARLIER step, by 1-based position, instead of the step immediately before. Lets a later step fork back to an intermediate value (splitting a URL once and then using both the raw split and something derived from it), which a strict pipeline cannot express. Ignored when source_column_id is set (a column wins over a step), and ignored by functions that read their arguments rather than the piped value. None reads the previous step.
        - TableRegexExtractInput: Extract a regex group from a string value.
          - `failure_mode` 'pass_through_raw' | 'set_null' | 'static' | 'skip': What a formula cell resolves to when a step in its chain fails. Applies to the whole chain, read off the top-level function only. ``SKIP`` is equivalent to ``SET_NULL`` for table cells (a cell always has a stored slot, so there is nothing to skip). Kept for shape compatibility.
          - `fallback_value` union
            - string
            - integer
            - number
            - boolean
          - `function` 'regex_extract'
          - `group` integer
          - `next` union
            - TableCopyInput: Copy the input value unchanged.
              - …
            - TableChangeCaseInput: Change the case of a string value.
              - …
            - TableTrimInput: Strip leading and trailing whitespace from a string value.
              - …
            - TableReplaceInput: Replace all occurrences of a substring.
              - …
            - TableRegexExtractInput (recursive)
            - TableRegexReplaceInput: Replace regex matches in a string value.
              - …
            - TableConcatenateInput: Join several values into one string. Sources are ORDERED and may mix columns with the results of earlier steps: ``[First name, step 2]`` and ``[step 2, First name]`` are different strings, which is why there is one list rather than a list of columns beside a list of steps. The field keeps its original name: every stored definition holds ``source_column_ids``, and the list is still overwhelmingly columns. Only the item type widened, so old definitions validate untouched.
              - …
            - TableArithmeticInput: Apply an arithmetic operator with a constant or column-valued operand.
              - …
            - TableRoundInput: Round a numeric value to a precision.
              - …
            - TableClampInput: Clamp a numeric value to an inclusive range.
              - …
            - TableDateFormatInput: Convert a date between iso/unix/unix_ms representations.
              - …
            - TableDateExtractInput: Extract a component (year, month, ...) from a date value.
              - …
            - TableDateArithmeticInput: Add or subtract a fixed duration from a date value.
              - …
            - TableListFirstInput: Take the first element of a list value.
              - …
            - TableListLastInput: Take the last element of a list value.
              - …
            - TableListNthInput: Take the element at an index of a list value.
              - …
            - TableListJoinInput: Join list elements into a string with a separator.
              - …
            - TableListCountInput: Count the elements of a list value.
              - …
            - TableListPluckInput: Pull one field out of every object in a list. Enrichment payloads routinely carry lists of objects (``[{"value": "Payroll"}, {"value": "HR"}]``) where the useful thing is the field, not the wrapper. Plucking turns that into ``["Payroll", "HR"]`` so ``list_join`` and friends can work on it; items without the field become empty and scalar items pass through unchanged.
              - …
            - TableListUniqueInput: De-duplicate list elements, keeping first-seen order.
              - …
            - TableListSplitInput: Split a string value into a list on a separator.
              - …
            - TableCoalesceInput: Substitute a default (a literal or another column) when the input is empty.
              - …
            - TableIfThenElseInput: Pick one of two values based on a comparison. Each of the three slots takes a literal or a column, so this expresses both "if this column is over that column" and "use A, else use B". Neither of those was reachable while they were constants.
              - …
            - TableConditionsInput: Fold several comparisons into ONE boolean. The engine's only boolean combinator, and the shape a column's ``run_condition`` is authored in: "only run where Employees > 50 AND Country is US". Nothing else here joins predicates: ``if_then_else`` compares exactly one pair and returns a value rather than a verdict. So without this a multi-clause gate could only be reached by chaining steps that pipe a truthy stand-in forward, which no editor could read back. One joiner over clauses and, at most one level down, groups of clauses: "A and (B or C)". That is precisely the row filter's shape, so a view's filter can be saved as a gate and read back as a filter without loss; a deeper tree would be expressible on one side only. Reads its clauses' operands directly and ignores the piped input, so it is a leaf rather than a transform.
              - …
            - TableValueMappingInput: Map input values through a lookup table.
              - …
            - TableToStringInput: Coerce the input to a string.
              - …
            - TableToIntInput: Coerce the input to an integer.
              - …
            - TableToFloatInput: Coerce the input to a float.
              - …
            - TableToBoolInput: Coerce the input to a boolean.
              - …
            - TableToDateInput: Coerce the input to a date.
              - …
            - TablePhoneE164Input: Normalize a phone number to E.164 format.
              - …
            - TableUtmParseInput: Extract a UTM parameter from a URL value.
              - …
            - TableUrlDomainInput: Reduce a URL to its bare registrable-looking host. A website field arrives as a whole URL (``https://www.acme.com/about``) but the thing that joins, dedupes and enriches is ``acme.com``. Doing it with ``regex_extract`` means every caller hand-writes the same fragile pattern, so the parse lives here once and uses a real URL parser.
              - …
            - TableCompanyDomainInput: Reduce a company's website URL to the company's own registrable domain. Three differences from ``url_domain``, which stays the generic read (a column of LinkedIn profile URLs legitimately reduces to ``linkedin.com`` there): Hosts that name a platform rather than the company (LinkedIn and Facebook pages, link aggregators, review sites, vendor partner directories) come out empty. A company whose only listed website is its LinkedIn page has no derivable domain, and an empty cell says so; ``linkedin.com`` is worse than empty because it joins, dedupes and syncs as if it were real. The result is the domain someone REGISTERED, not the bare host: a provider that lists ``careers.acme.com`` is describing ``acme.com``. A subdomain joins against nothing and sends an agent somewhere that often does not resolve. Page builders that give each customer their own label are the exception the Public Suffix List already encodes, so ``acme.wixsite.com`` survives whole rather than collapsing into ``wixsite.com``. ``company_name`` guards the case those two cannot: a directory listing reduces to the DIRECTORY owner's domain, so ``cloudpartners.transform.microsoft.com`` becomes ``microsoft.com``: right shape, wrong company, and nothing downstream can tell. Pointed at the column naming the employer, the domain is dropped when the two disagree. Optional: without it the other two rules still apply.
              - …
            - TableGetPathInput: Read a dotted path out of an object- or list-valued cell. Object and list columns were storable but unreadable: nothing in the catalog could reach a field inside one, so an enrichment payload landed in a cell and stopped there. Segments index dicts by key and lists by integer position: ``employees.count``, ``emails.0.address``. ``output_type`` is declared rather than derived because a JSON path can land on anything, and the column's data type has to be known before a single row is evaluated.
              - …
            - TableFormatInput: Build a string from a positional template and a list of arguments. ``concatenate`` joins whole columns with one separator, which cannot produce "Enterprise: Acme (12.4%)". Placeholders are positional only (``{0}``, ``{1}``) so the template stays data, not an expression language. Like ``concatenate`` this takes no ``source_column_id``: its inputs are its arguments, not the value flowing down the chain.
              - …
            - TableDateDiffInput: The signed duration between this step's date and another date. ``date_arithmetic`` shifts a date by a CONSTANT amount, so the gap between two date columns had no expression. Positive when the step's own date is the later of the two.
              - …
            - TableKeywordsInput: The most frequent meaningful words in a text or list value. Reads a body of text (a scraped page, a bio, a job description) and returns the words that carry its subject, ordered most frequent first. Stopwords ("the", "and", "with") are dropped: a frequency count that keeps them returns the same five words for every row and says nothing about any of them. Deterministic and pure: no model call, so a keyword column costs nothing and re-runs identically.
              - …
            - TableListFilterInput: Keep only the list items whose field passes a test. An enrichment payload lands as a list of objects (every job opening, every funding round, every contact) and the row usually wants a subset of it: the engineering roles, the rounds after 2024, the contacts with an email. Without this the whole list is the only thing a cell can hold. ``field`` is a dotted path INSIDE each item (``location.country``); leaving it empty tests the item itself, which is what a list of plain strings needs. ``exists``/``missing`` ignore ``value``: they ask only whether the field is there.
              - …
            - TableListSortInput: Order a list, ascending or descending. ``list_unique`` and ``list_join`` both preserve whatever order the source happened to arrive in, which is fine until the cell is meant to be READ: a top-3 of anything, a chronological history, an alphabetised tag list. ``field`` names the dotted path to sort objects BY; empty sorts the items themselves. Values that cannot be compared with each other (a number next to a string) are ordered by type first, so the sort is total instead of raising on the row where the data is mixed.
              - …
            - TableListIntersectInput: The values this list shares with another: the overlap, in the first list's order. The scoring question every ICP fit column asks: which of the buyer's tags, technologies or keywords are ALSO on my target list. Doing it by hand meant one ``if_then_else`` per tag. ``other`` is a column holding the second list, or literal text split on ``separator``. Matching ignores case and surrounding spaces, because the two lists come from different sources and "Shopify " never equals "shopify" when it matters most.
              - …
            - TableTextSimilarityInput: How alike two pieces of text are, as a percentage. The dedupe and match question: is "Acme Inc." the same company as "Acme, Inc"? An exact comparison says no and a human says obviously yes, so the honest answer is a number the row can threshold on. Case and surrounding whitespace never count: they are formatting, not difference. 100 means identical after that normalisation, 0 means nothing in common.
              - …
            - TableDetectLanguageInput: The language a piece of text is written in, as an ISO 639-1 code. Routes a row before anything expensive touches it: which sequence to enrol a lead into, which reviewer sees a scraped page, whether to translate at all. Script comes first (Cyrillic, Greek, Hebrew, Arabic, Han, kana and hangul each answer on their own) and Latin text is decided by the function words it uses. That is a heuristic, not a model: it is deterministic, free, and honest about not knowing, returning null when the text is too short or matches nothing.
              - …
            - TableScoreWordsInput: Score text by the weighted words it contains. The rules half of lead scoring, without a model: "enterprise" is worth 3, "student" is worth -5, and the cell adds up whatever the row's text, tags or tech stack actually say. Expressing the same thing with ``if_then_else`` needs one step per word and runs out of chain depth at ten. Weights are a plain object: word or phrase to number. Matching is case-insensitive; a multi-word key matches as a phrase. ``count_repeats`` decides whether saying "enterprise" three times scores three times, which is the difference between weighing a claim and weighing a page.
              - …
            - TableHashInput: Hash a value: the identifier ad platforms and clean rooms ask for. Uploading an audience means handing over hashed emails, never raw ones, and the hash has to be produced the way the platform specifies: lowercased and trimmed first, hex digest out. That normalisation is the part people get wrong by hand, so it happens here rather than in three chained steps.
              - …
            - TableUriEncodeInput: Percent-encode a value so it survives being put in a URL. Every search-URL column builds the same thing (a query string with a company name in it) and every one of them breaks on the first ampersand or accent. Encoding belongs one step before the URL is assembled, not in a regex chain that handles the four characters someone remembered. ``component`` escapes everything reserved, which is what a query value needs; ``full`` leaves ``:/?#`` alone so an entire URL stays usable. Lists are encoded item by item.
              - …
            - TableUrlValidInput: Whether a value is a usable web address. The gate in front of every scrape, screenshot and HTTP column: a row whose "website" cell holds "n/a", "coming soon" or a bare company name should never spend a credit finding that out. True means the value parses as a host with a real-looking domain, not that the site answers. A formula cannot make a request, and pretending otherwise would be the one dishonest thing this function could do.
              - …
            - TableEmailPermutationsInput: The candidate work-email addresses for a name at a domain. What a verifier needs to be pointed at: nine or so patterns companies actually use, in the order they are actually common, so the cheapest verification step has a list to work through instead of one guess. The piped value is the person's name: "Ada Lovelace", or a first name with ``last_name`` supplying the rest. Anything after the first and last token (middle names, suffixes) is ignored rather than permuted, which is what keeps the list nine long instead of ninety.
              - …
            - TableRoundRobinInput: Assign each row to one of a list of owners, evenly. Lead routing, as a column: the rep, the region, the sending inbox. The piped value is the row's IDENTITY (its email, domain or id) and the owner is derived from a hash of it rather than from the row's position. That is a deliberate departure from a counter-based round robin, and it is the only version that behaves: re-running the column, adding rows above, or sorting the view all leave every existing row with the owner it already had. A counter reassigns half the table the first time anything moves, which in a CRM means the wrong rep gets the follow-up.
              - …
            - TableWeightedRoundRobinInput: Assign each row to an owner, in proportion to each owner's share. The version real teams need: a senior rep takes three leads for every one a new hire gets, one region absorbs twice the volume of another. Shares are whole numbers and mean exactly what they look like: 3 and 1 is three quarters and one quarter. Stable per row for the same reason ``round_robin`` is: the owner comes from a hash of the row's identity, so nothing already assigned moves when the table grows or the view is sorted. Changing the SHARES does move rows, because that is what changing them means.
              - …
          - `pattern` string, required
          - `source_column_id` string, uuid, nullable
          - `source_step` integer, nullable: Read the result of an EARLIER step, by 1-based position, instead of the step immediately before. Lets a later step fork back to an intermediate value (splitting a URL once and then using both the raw split and something derived from it), which a strict pipeline cannot express. Ignored when source_column_id is set (a column wins over a step), and ignored by functions that read their arguments rather than the piped value. None reads the previous step.
        - TableRegexReplaceInput: Replace regex matches in a string value.
          - `failure_mode` 'pass_through_raw' | 'set_null' | 'static' | 'skip': What a formula cell resolves to when a step in its chain fails. Applies to the whole chain, read off the top-level function only. ``SKIP`` is equivalent to ``SET_NULL`` for table cells (a cell always has a stored slot, so there is nothing to skip). Kept for shape compatibility.
          - `fallback_value` union
            - string
            - integer
            - number
            - boolean
          - `function` 'regex_replace'
          - `next` union
            - TableCopyInput: Copy the input value unchanged.
              - …
            - TableChangeCaseInput: Change the case of a string value.
              - …
            - TableTrimInput: Strip leading and trailing whitespace from a string value.
              - …
            - TableReplaceInput: Replace all occurrences of a substring.
              - …
            - TableRegexExtractInput: Extract a regex group from a string value.
              - …
            - TableRegexReplaceInput (recursive)
            - TableConcatenateInput: Join several values into one string. Sources are ORDERED and may mix columns with the results of earlier steps: ``[First name, step 2]`` and ``[step 2, First name]`` are different strings, which is why there is one list rather than a list of columns beside a list of steps. The field keeps its original name: every stored definition holds ``source_column_ids``, and the list is still overwhelmingly columns. Only the item type widened, so old definitions validate untouched.
              - …
            - TableArithmeticInput: Apply an arithmetic operator with a constant or column-valued operand.
              - …
            - TableRoundInput: Round a numeric value to a precision.
              - …
            - TableClampInput: Clamp a numeric value to an inclusive range.
              - …
            - TableDateFormatInput: Convert a date between iso/unix/unix_ms representations.
              - …
            - TableDateExtractInput: Extract a component (year, month, ...) from a date value.
              - …
            - TableDateArithmeticInput: Add or subtract a fixed duration from a date value.
              - …
            - TableListFirstInput: Take the first element of a list value.
              - …
            - TableListLastInput: Take the last element of a list value.
              - …
            - TableListNthInput: Take the element at an index of a list value.
              - …
            - TableListJoinInput: Join list elements into a string with a separator.
              - …
            - TableListCountInput: Count the elements of a list value.
              - …
            - TableListPluckInput: Pull one field out of every object in a list. Enrichment payloads routinely carry lists of objects (``[{"value": "Payroll"}, {"value": "HR"}]``) where the useful thing is the field, not the wrapper. Plucking turns that into ``["Payroll", "HR"]`` so ``list_join`` and friends can work on it; items without the field become empty and scalar items pass through unchanged.
              - …
            - TableListUniqueInput: De-duplicate list elements, keeping first-seen order.
              - …
            - TableListSplitInput: Split a string value into a list on a separator.
              - …
            - TableCoalesceInput: Substitute a default (a literal or another column) when the input is empty.
              - …
            - TableIfThenElseInput: Pick one of two values based on a comparison. Each of the three slots takes a literal or a column, so this expresses both "if this column is over that column" and "use A, else use B". Neither of those was reachable while they were constants.
              - …
            - TableConditionsInput: Fold several comparisons into ONE boolean. The engine's only boolean combinator, and the shape a column's ``run_condition`` is authored in: "only run where Employees > 50 AND Country is US". Nothing else here joins predicates: ``if_then_else`` compares exactly one pair and returns a value rather than a verdict. So without this a multi-clause gate could only be reached by chaining steps that pipe a truthy stand-in forward, which no editor could read back. One joiner over clauses and, at most one level down, groups of clauses: "A and (B or C)". That is precisely the row filter's shape, so a view's filter can be saved as a gate and read back as a filter without loss; a deeper tree would be expressible on one side only. Reads its clauses' operands directly and ignores the piped input, so it is a leaf rather than a transform.
              - …
            - TableValueMappingInput: Map input values through a lookup table.
              - …
            - TableToStringInput: Coerce the input to a string.
              - …
            - TableToIntInput: Coerce the input to an integer.
              - …
            - TableToFloatInput: Coerce the input to a float.
              - …
            - TableToBoolInput: Coerce the input to a boolean.
              - …
            - TableToDateInput: Coerce the input to a date.
              - …
            - TablePhoneE164Input: Normalize a phone number to E.164 format.
              - …
            - TableUtmParseInput: Extract a UTM parameter from a URL value.
              - …
            - TableUrlDomainInput: Reduce a URL to its bare registrable-looking host. A website field arrives as a whole URL (``https://www.acme.com/about``) but the thing that joins, dedupes and enriches is ``acme.com``. Doing it with ``regex_extract`` means every caller hand-writes the same fragile pattern, so the parse lives here once and uses a real URL parser.
              - …
            - TableCompanyDomainInput: Reduce a company's website URL to the company's own registrable domain. Three differences from ``url_domain``, which stays the generic read (a column of LinkedIn profile URLs legitimately reduces to ``linkedin.com`` there): Hosts that name a platform rather than the company (LinkedIn and Facebook pages, link aggregators, review sites, vendor partner directories) come out empty. A company whose only listed website is its LinkedIn page has no derivable domain, and an empty cell says so; ``linkedin.com`` is worse than empty because it joins, dedupes and syncs as if it were real. The result is the domain someone REGISTERED, not the bare host: a provider that lists ``careers.acme.com`` is describing ``acme.com``. A subdomain joins against nothing and sends an agent somewhere that often does not resolve. Page builders that give each customer their own label are the exception the Public Suffix List already encodes, so ``acme.wixsite.com`` survives whole rather than collapsing into ``wixsite.com``. ``company_name`` guards the case those two cannot: a directory listing reduces to the DIRECTORY owner's domain, so ``cloudpartners.transform.microsoft.com`` becomes ``microsoft.com``: right shape, wrong company, and nothing downstream can tell. Pointed at the column naming the employer, the domain is dropped when the two disagree. Optional: without it the other two rules still apply.
              - …
            - TableGetPathInput: Read a dotted path out of an object- or list-valued cell. Object and list columns were storable but unreadable: nothing in the catalog could reach a field inside one, so an enrichment payload landed in a cell and stopped there. Segments index dicts by key and lists by integer position: ``employees.count``, ``emails.0.address``. ``output_type`` is declared rather than derived because a JSON path can land on anything, and the column's data type has to be known before a single row is evaluated.
              - …
            - TableFormatInput: Build a string from a positional template and a list of arguments. ``concatenate`` joins whole columns with one separator, which cannot produce "Enterprise: Acme (12.4%)". Placeholders are positional only (``{0}``, ``{1}``) so the template stays data, not an expression language. Like ``concatenate`` this takes no ``source_column_id``: its inputs are its arguments, not the value flowing down the chain.
              - …
            - TableDateDiffInput: The signed duration between this step's date and another date. ``date_arithmetic`` shifts a date by a CONSTANT amount, so the gap between two date columns had no expression. Positive when the step's own date is the later of the two.
              - …
            - TableKeywordsInput: The most frequent meaningful words in a text or list value. Reads a body of text (a scraped page, a bio, a job description) and returns the words that carry its subject, ordered most frequent first. Stopwords ("the", "and", "with") are dropped: a frequency count that keeps them returns the same five words for every row and says nothing about any of them. Deterministic and pure: no model call, so a keyword column costs nothing and re-runs identically.
              - …
            - TableListFilterInput: Keep only the list items whose field passes a test. An enrichment payload lands as a list of objects (every job opening, every funding round, every contact) and the row usually wants a subset of it: the engineering roles, the rounds after 2024, the contacts with an email. Without this the whole list is the only thing a cell can hold. ``field`` is a dotted path INSIDE each item (``location.country``); leaving it empty tests the item itself, which is what a list of plain strings needs. ``exists``/``missing`` ignore ``value``: they ask only whether the field is there.
              - …
            - TableListSortInput: Order a list, ascending or descending. ``list_unique`` and ``list_join`` both preserve whatever order the source happened to arrive in, which is fine until the cell is meant to be READ: a top-3 of anything, a chronological history, an alphabetised tag list. ``field`` names the dotted path to sort objects BY; empty sorts the items themselves. Values that cannot be compared with each other (a number next to a string) are ordered by type first, so the sort is total instead of raising on the row where the data is mixed.
              - …
            - TableListIntersectInput: The values this list shares with another: the overlap, in the first list's order. The scoring question every ICP fit column asks: which of the buyer's tags, technologies or keywords are ALSO on my target list. Doing it by hand meant one ``if_then_else`` per tag. ``other`` is a column holding the second list, or literal text split on ``separator``. Matching ignores case and surrounding spaces, because the two lists come from different sources and "Shopify " never equals "shopify" when it matters most.
              - …
            - TableTextSimilarityInput: How alike two pieces of text are, as a percentage. The dedupe and match question: is "Acme Inc." the same company as "Acme, Inc"? An exact comparison says no and a human says obviously yes, so the honest answer is a number the row can threshold on. Case and surrounding whitespace never count: they are formatting, not difference. 100 means identical after that normalisation, 0 means nothing in common.
              - …
            - TableDetectLanguageInput: The language a piece of text is written in, as an ISO 639-1 code. Routes a row before anything expensive touches it: which sequence to enrol a lead into, which reviewer sees a scraped page, whether to translate at all. Script comes first (Cyrillic, Greek, Hebrew, Arabic, Han, kana and hangul each answer on their own) and Latin text is decided by the function words it uses. That is a heuristic, not a model: it is deterministic, free, and honest about not knowing, returning null when the text is too short or matches nothing.
              - …
            - TableScoreWordsInput: Score text by the weighted words it contains. The rules half of lead scoring, without a model: "enterprise" is worth 3, "student" is worth -5, and the cell adds up whatever the row's text, tags or tech stack actually say. Expressing the same thing with ``if_then_else`` needs one step per word and runs out of chain depth at ten. Weights are a plain object: word or phrase to number. Matching is case-insensitive; a multi-word key matches as a phrase. ``count_repeats`` decides whether saying "enterprise" three times scores three times, which is the difference between weighing a claim and weighing a page.
              - …
            - TableHashInput: Hash a value: the identifier ad platforms and clean rooms ask for. Uploading an audience means handing over hashed emails, never raw ones, and the hash has to be produced the way the platform specifies: lowercased and trimmed first, hex digest out. That normalisation is the part people get wrong by hand, so it happens here rather than in three chained steps.
              - …
            - TableUriEncodeInput: Percent-encode a value so it survives being put in a URL. Every search-URL column builds the same thing (a query string with a company name in it) and every one of them breaks on the first ampersand or accent. Encoding belongs one step before the URL is assembled, not in a regex chain that handles the four characters someone remembered. ``component`` escapes everything reserved, which is what a query value needs; ``full`` leaves ``:/?#`` alone so an entire URL stays usable. Lists are encoded item by item.
              - …
            - TableUrlValidInput: Whether a value is a usable web address. The gate in front of every scrape, screenshot and HTTP column: a row whose "website" cell holds "n/a", "coming soon" or a bare company name should never spend a credit finding that out. True means the value parses as a host with a real-looking domain, not that the site answers. A formula cannot make a request, and pretending otherwise would be the one dishonest thing this function could do.
              - …
            - TableEmailPermutationsInput: The candidate work-email addresses for a name at a domain. What a verifier needs to be pointed at: nine or so patterns companies actually use, in the order they are actually common, so the cheapest verification step has a list to work through instead of one guess. The piped value is the person's name: "Ada Lovelace", or a first name with ``last_name`` supplying the rest. Anything after the first and last token (middle names, suffixes) is ignored rather than permuted, which is what keeps the list nine long instead of ninety.
              - …
            - TableRoundRobinInput: Assign each row to one of a list of owners, evenly. Lead routing, as a column: the rep, the region, the sending inbox. The piped value is the row's IDENTITY (its email, domain or id) and the owner is derived from a hash of it rather than from the row's position. That is a deliberate departure from a counter-based round robin, and it is the only version that behaves: re-running the column, adding rows above, or sorting the view all leave every existing row with the owner it already had. A counter reassigns half the table the first time anything moves, which in a CRM means the wrong rep gets the follow-up.
              - …
            - TableWeightedRoundRobinInput: Assign each row to an owner, in proportion to each owner's share. The version real teams need: a senior rep takes three leads for every one a new hire gets, one region absorbs twice the volume of another. Shares are whole numbers and mean exactly what they look like: 3 and 1 is three quarters and one quarter. Stable per row for the same reason ``round_robin`` is: the owner comes from a hash of the row's identity, so nothing already assigned moves when the table grows or the view is sorted. Changing the SHARES does move rows, because that is what changing them means.
              - …
          - `pattern` string, required
          - `replacement` string, required
          - `source_column_id` string, uuid, nullable
          - `source_step` integer, nullable: Read the result of an EARLIER step, by 1-based position, instead of the step immediately before. Lets a later step fork back to an intermediate value (splitting a URL once and then using both the raw split and something derived from it), which a strict pipeline cannot express. Ignored when source_column_id is set (a column wins over a step), and ignored by functions that read their arguments rather than the piped value. None reads the previous step.
        - TableConcatenateInput: Join several values into one string. Sources are ORDERED and may mix columns with the results of earlier steps: ``[First name, step 2]`` and ``[step 2, First name]`` are different strings, which is why there is one list rather than a list of columns beside a list of steps. The field keeps its original name: every stored definition holds ``source_column_ids``, and the list is still overwhelmingly columns. Only the item type widened, so old definitions validate untouched.
          - `failure_mode` 'pass_through_raw' | 'set_null' | 'static' | 'skip': What a formula cell resolves to when a step in its chain fails. Applies to the whole chain, read off the top-level function only. ``SKIP`` is equivalent to ``SET_NULL`` for table cells (a cell always has a stored slot, so there is nothing to skip). Kept for shape compatibility.
          - `fallback_value` union
            - string
            - integer
            - number
            - boolean
          - `function` 'concatenate'
          - `ignore_empty` boolean
          - `next` union
            - TableCopyInput: Copy the input value unchanged.
              - …
            - TableChangeCaseInput: Change the case of a string value.
              - …
            - TableTrimInput: Strip leading and trailing whitespace from a string value.
              - …
            - TableReplaceInput: Replace all occurrences of a substring.
              - …
            - TableRegexExtractInput: Extract a regex group from a string value.
              - …
            - TableRegexReplaceInput: Replace regex matches in a string value.
              - …
            - TableConcatenateInput (recursive)
            - TableArithmeticInput: Apply an arithmetic operator with a constant or column-valued operand.
              - …
            - TableRoundInput: Round a numeric value to a precision.
              - …
            - TableClampInput: Clamp a numeric value to an inclusive range.
              - …
            - TableDateFormatInput: Convert a date between iso/unix/unix_ms representations.
              - …
            - TableDateExtractInput: Extract a component (year, month, ...) from a date value.
              - …
            - TableDateArithmeticInput: Add or subtract a fixed duration from a date value.
              - …
            - TableListFirstInput: Take the first element of a list value.
              - …
            - TableListLastInput: Take the last element of a list value.
              - …
            - TableListNthInput: Take the element at an index of a list value.
              - …
            - TableListJoinInput: Join list elements into a string with a separator.
              - …
            - TableListCountInput: Count the elements of a list value.
              - …
            - TableListPluckInput: Pull one field out of every object in a list. Enrichment payloads routinely carry lists of objects (``[{"value": "Payroll"}, {"value": "HR"}]``) where the useful thing is the field, not the wrapper. Plucking turns that into ``["Payroll", "HR"]`` so ``list_join`` and friends can work on it; items without the field become empty and scalar items pass through unchanged.
              - …
            - TableListUniqueInput: De-duplicate list elements, keeping first-seen order.
              - …
            - TableListSplitInput: Split a string value into a list on a separator.
              - …
            - TableCoalesceInput: Substitute a default (a literal or another column) when the input is empty.
              - …
            - TableIfThenElseInput: Pick one of two values based on a comparison. Each of the three slots takes a literal or a column, so this expresses both "if this column is over that column" and "use A, else use B". Neither of those was reachable while they were constants.
              - …
            - TableConditionsInput: Fold several comparisons into ONE boolean. The engine's only boolean combinator, and the shape a column's ``run_condition`` is authored in: "only run where Employees > 50 AND Country is US". Nothing else here joins predicates: ``if_then_else`` compares exactly one pair and returns a value rather than a verdict. So without this a multi-clause gate could only be reached by chaining steps that pipe a truthy stand-in forward, which no editor could read back. One joiner over clauses and, at most one level down, groups of clauses: "A and (B or C)". That is precisely the row filter's shape, so a view's filter can be saved as a gate and read back as a filter without loss; a deeper tree would be expressible on one side only. Reads its clauses' operands directly and ignores the piped input, so it is a leaf rather than a transform.
              - …
            - TableValueMappingInput: Map input values through a lookup table.
              - …
            - TableToStringInput: Coerce the input to a string.
              - …
            - TableToIntInput: Coerce the input to an integer.
              - …
            - TableToFloatInput: Coerce the input to a float.
              - …
            - TableToBoolInput: Coerce the input to a boolean.
              - …
            - TableToDateInput: Coerce the input to a date.
              - …
            - TablePhoneE164Input: Normalize a phone number to E.164 format.
              - …
            - TableUtmParseInput: Extract a UTM parameter from a URL value.
              - …
            - TableUrlDomainInput: Reduce a URL to its bare registrable-looking host. A website field arrives as a whole URL (``https://www.acme.com/about``) but the thing that joins, dedupes and enriches is ``acme.com``. Doing it with ``regex_extract`` means every caller hand-writes the same fragile pattern, so the parse lives here once and uses a real URL parser.
              - …
            - TableCompanyDomainInput: Reduce a company's website URL to the company's own registrable domain. Three differences from ``url_domain``, which stays the generic read (a column of LinkedIn profile URLs legitimately reduces to ``linkedin.com`` there): Hosts that name a platform rather than the company (LinkedIn and Facebook pages, link aggregators, review sites, vendor partner directories) come out empty. A company whose only listed website is its LinkedIn page has no derivable domain, and an empty cell says so; ``linkedin.com`` is worse than empty because it joins, dedupes and syncs as if it were real. The result is the domain someone REGISTERED, not the bare host: a provider that lists ``careers.acme.com`` is describing ``acme.com``. A subdomain joins against nothing and sends an agent somewhere that often does not resolve. Page builders that give each customer their own label are the exception the Public Suffix List already encodes, so ``acme.wixsite.com`` survives whole rather than collapsing into ``wixsite.com``. ``company_name`` guards the case those two cannot: a directory listing reduces to the DIRECTORY owner's domain, so ``cloudpartners.transform.microsoft.com`` becomes ``microsoft.com``: right shape, wrong company, and nothing downstream can tell. Pointed at the column naming the employer, the domain is dropped when the two disagree. Optional: without it the other two rules still apply.
              - …
            - TableGetPathInput: Read a dotted path out of an object- or list-valued cell. Object and list columns were storable but unreadable: nothing in the catalog could reach a field inside one, so an enrichment payload landed in a cell and stopped there. Segments index dicts by key and lists by integer position: ``employees.count``, ``emails.0.address``. ``output_type`` is declared rather than derived because a JSON path can land on anything, and the column's data type has to be known before a single row is evaluated.
              - …
            - TableFormatInput: Build a string from a positional template and a list of arguments. ``concatenate`` joins whole columns with one separator, which cannot produce "Enterprise: Acme (12.4%)". Placeholders are positional only (``{0}``, ``{1}``) so the template stays data, not an expression language. Like ``concatenate`` this takes no ``source_column_id``: its inputs are its arguments, not the value flowing down the chain.
              - …
            - TableDateDiffInput: The signed duration between this step's date and another date. ``date_arithmetic`` shifts a date by a CONSTANT amount, so the gap between two date columns had no expression. Positive when the step's own date is the later of the two.
              - …
            - TableKeywordsInput: The most frequent meaningful words in a text or list value. Reads a body of text (a scraped page, a bio, a job description) and returns the words that carry its subject, ordered most frequent first. Stopwords ("the", "and", "with") are dropped: a frequency count that keeps them returns the same five words for every row and says nothing about any of them. Deterministic and pure: no model call, so a keyword column costs nothing and re-runs identically.
              - …
            - TableListFilterInput: Keep only the list items whose field passes a test. An enrichment payload lands as a list of objects (every job opening, every funding round, every contact) and the row usually wants a subset of it: the engineering roles, the rounds after 2024, the contacts with an email. Without this the whole list is the only thing a cell can hold. ``field`` is a dotted path INSIDE each item (``location.country``); leaving it empty tests the item itself, which is what a list of plain strings needs. ``exists``/``missing`` ignore ``value``: they ask only whether the field is there.
              - …
            - TableListSortInput: Order a list, ascending or descending. ``list_unique`` and ``list_join`` both preserve whatever order the source happened to arrive in, which is fine until the cell is meant to be READ: a top-3 of anything, a chronological history, an alphabetised tag list. ``field`` names the dotted path to sort objects BY; empty sorts the items themselves. Values that cannot be compared with each other (a number next to a string) are ordered by type first, so the sort is total instead of raising on the row where the data is mixed.
              - …
            - TableListIntersectInput: The values this list shares with another: the overlap, in the first list's order. The scoring question every ICP fit column asks: which of the buyer's tags, technologies or keywords are ALSO on my target list. Doing it by hand meant one ``if_then_else`` per tag. ``other`` is a column holding the second list, or literal text split on ``separator``. Matching ignores case and surrounding spaces, because the two lists come from different sources and "Shopify " never equals "shopify" when it matters most.
              - …
            - TableTextSimilarityInput: How alike two pieces of text are, as a percentage. The dedupe and match question: is "Acme Inc." the same company as "Acme, Inc"? An exact comparison says no and a human says obviously yes, so the honest answer is a number the row can threshold on. Case and surrounding whitespace never count: they are formatting, not difference. 100 means identical after that normalisation, 0 means nothing in common.
              - …
            - TableDetectLanguageInput: The language a piece of text is written in, as an ISO 639-1 code. Routes a row before anything expensive touches it: which sequence to enrol a lead into, which reviewer sees a scraped page, whether to translate at all. Script comes first (Cyrillic, Greek, Hebrew, Arabic, Han, kana and hangul each answer on their own) and Latin text is decided by the function words it uses. That is a heuristic, not a model: it is deterministic, free, and honest about not knowing, returning null when the text is too short or matches nothing.
              - …
            - TableScoreWordsInput: Score text by the weighted words it contains. The rules half of lead scoring, without a model: "enterprise" is worth 3, "student" is worth -5, and the cell adds up whatever the row's text, tags or tech stack actually say. Expressing the same thing with ``if_then_else`` needs one step per word and runs out of chain depth at ten. Weights are a plain object: word or phrase to number. Matching is case-insensitive; a multi-word key matches as a phrase. ``count_repeats`` decides whether saying "enterprise" three times scores three times, which is the difference between weighing a claim and weighing a page.
              - …
            - TableHashInput: Hash a value: the identifier ad platforms and clean rooms ask for. Uploading an audience means handing over hashed emails, never raw ones, and the hash has to be produced the way the platform specifies: lowercased and trimmed first, hex digest out. That normalisation is the part people get wrong by hand, so it happens here rather than in three chained steps.
              - …
            - TableUriEncodeInput: Percent-encode a value so it survives being put in a URL. Every search-URL column builds the same thing (a query string with a company name in it) and every one of them breaks on the first ampersand or accent. Encoding belongs one step before the URL is assembled, not in a regex chain that handles the four characters someone remembered. ``component`` escapes everything reserved, which is what a query value needs; ``full`` leaves ``:/?#`` alone so an entire URL stays usable. Lists are encoded item by item.
              - …
            - TableUrlValidInput: Whether a value is a usable web address. The gate in front of every scrape, screenshot and HTTP column: a row whose "website" cell holds "n/a", "coming soon" or a bare company name should never spend a credit finding that out. True means the value parses as a host with a real-looking domain, not that the site answers. A formula cannot make a request, and pretending otherwise would be the one dishonest thing this function could do.
              - …
            - TableEmailPermutationsInput: The candidate work-email addresses for a name at a domain. What a verifier needs to be pointed at: nine or so patterns companies actually use, in the order they are actually common, so the cheapest verification step has a list to work through instead of one guess. The piped value is the person's name: "Ada Lovelace", or a first name with ``last_name`` supplying the rest. Anything after the first and last token (middle names, suffixes) is ignored rather than permuted, which is what keeps the list nine long instead of ninety.
              - …
            - TableRoundRobinInput: Assign each row to one of a list of owners, evenly. Lead routing, as a column: the rep, the region, the sending inbox. The piped value is the row's IDENTITY (its email, domain or id) and the owner is derived from a hash of it rather than from the row's position. That is a deliberate departure from a counter-based round robin, and it is the only version that behaves: re-running the column, adding rows above, or sorting the view all leave every existing row with the owner it already had. A counter reassigns half the table the first time anything moves, which in a CRM means the wrong rep gets the follow-up.
              - …
            - TableWeightedRoundRobinInput: Assign each row to an owner, in proportion to each owner's share. The version real teams need: a senior rep takes three leads for every one a new hire gets, one region absorbs twice the volume of another. Shares are whole numbers and mean exactly what they look like: 3 and 1 is three quarters and one quarter. Stable per row for the same reason ``round_robin`` is: the owner comes from a hash of the row's identity, so nothing already assigned moves when the table grows or the view is sorted. Changing the SHARES does move rows, because that is what changing them means.
              - …
          - `separator` string
          - `source_column_ids` union[], required: Values to join, in order. A UUID reads that column on the row; a step reference reads an earlier step's output.
            - union
              - …
          - `source_step` integer, nullable: Read the result of an EARLIER step, by 1-based position, instead of the step immediately before. Lets a later step fork back to an intermediate value (splitting a URL once and then using both the raw split and something derived from it), which a strict pipeline cannot express. Ignored when source_column_id is set (a column wins over a step), and ignored by functions that read their arguments rather than the piped value. None reads the previous step.
        - TableArithmeticInput: Apply an arithmetic operator with a constant or column-valued operand.
          - `failure_mode` 'pass_through_raw' | 'set_null' | 'static' | 'skip': What a formula cell resolves to when a step in its chain fails. Applies to the whole chain, read off the top-level function only. ``SKIP`` is equivalent to ``SET_NULL`` for table cells (a cell always has a stored slot, so there is nothing to skip). Kept for shape compatibility.
          - `fallback_value` union
            - string
            - integer
            - number
            - boolean
          - `function` 'arithmetic'
          - `next` union
            - TableCopyInput: Copy the input value unchanged.
              - …
            - TableChangeCaseInput: Change the case of a string value.
              - …
            - TableTrimInput: Strip leading and trailing whitespace from a string value.
              - …
            - TableReplaceInput: Replace all occurrences of a substring.
              - …
            - TableRegexExtractInput: Extract a regex group from a string value.
              - …
            - TableRegexReplaceInput: Replace regex matches in a string value.
              - …
            - TableConcatenateInput: Join several values into one string. Sources are ORDERED and may mix columns with the results of earlier steps: ``[First name, step 2]`` and ``[step 2, First name]`` are different strings, which is why there is one list rather than a list of columns beside a list of steps. The field keeps its original name: every stored definition holds ``source_column_ids``, and the list is still overwhelmingly columns. Only the item type widened, so old definitions validate untouched.
              - …
            - TableArithmeticInput (recursive)
            - TableRoundInput: Round a numeric value to a precision.
              - …
            - TableClampInput: Clamp a numeric value to an inclusive range.
              - …
            - TableDateFormatInput: Convert a date between iso/unix/unix_ms representations.
              - …
            - TableDateExtractInput: Extract a component (year, month, ...) from a date value.
              - …
            - TableDateArithmeticInput: Add or subtract a fixed duration from a date value.
              - …
            - TableListFirstInput: Take the first element of a list value.
              - …
            - TableListLastInput: Take the last element of a list value.
              - …
            - TableListNthInput: Take the element at an index of a list value.
              - …
            - TableListJoinInput: Join list elements into a string with a separator.
              - …
            - TableListCountInput: Count the elements of a list value.
              - …
            - TableListPluckInput: Pull one field out of every object in a list. Enrichment payloads routinely carry lists of objects (``[{"value": "Payroll"}, {"value": "HR"}]``) where the useful thing is the field, not the wrapper. Plucking turns that into ``["Payroll", "HR"]`` so ``list_join`` and friends can work on it; items without the field become empty and scalar items pass through unchanged.
              - …
            - TableListUniqueInput: De-duplicate list elements, keeping first-seen order.
              - …
            - TableListSplitInput: Split a string value into a list on a separator.
              - …
            - TableCoalesceInput: Substitute a default (a literal or another column) when the input is empty.
              - …
            - TableIfThenElseInput: Pick one of two values based on a comparison. Each of the three slots takes a literal or a column, so this expresses both "if this column is over that column" and "use A, else use B". Neither of those was reachable while they were constants.
              - …
            - TableConditionsInput: Fold several comparisons into ONE boolean. The engine's only boolean combinator, and the shape a column's ``run_condition`` is authored in: "only run where Employees > 50 AND Country is US". Nothing else here joins predicates: ``if_then_else`` compares exactly one pair and returns a value rather than a verdict. So without this a multi-clause gate could only be reached by chaining steps that pipe a truthy stand-in forward, which no editor could read back. One joiner over clauses and, at most one level down, groups of clauses: "A and (B or C)". That is precisely the row filter's shape, so a view's filter can be saved as a gate and read back as a filter without loss; a deeper tree would be expressible on one side only. Reads its clauses' operands directly and ignores the piped input, so it is a leaf rather than a transform.
              - …
            - TableValueMappingInput: Map input values through a lookup table.
              - …
            - TableToStringInput: Coerce the input to a string.
              - …
            - TableToIntInput: Coerce the input to an integer.
              - …
            - TableToFloatInput: Coerce the input to a float.
              - …
            - TableToBoolInput: Coerce the input to a boolean.
              - …
            - TableToDateInput: Coerce the input to a date.
              - …
            - TablePhoneE164Input: Normalize a phone number to E.164 format.
              - …
            - TableUtmParseInput: Extract a UTM parameter from a URL value.
              - …
            - TableUrlDomainInput: Reduce a URL to its bare registrable-looking host. A website field arrives as a whole URL (``https://www.acme.com/about``) but the thing that joins, dedupes and enriches is ``acme.com``. Doing it with ``regex_extract`` means every caller hand-writes the same fragile pattern, so the parse lives here once and uses a real URL parser.
              - …
            - TableCompanyDomainInput: Reduce a company's website URL to the company's own registrable domain. Three differences from ``url_domain``, which stays the generic read (a column of LinkedIn profile URLs legitimately reduces to ``linkedin.com`` there): Hosts that name a platform rather than the company (LinkedIn and Facebook pages, link aggregators, review sites, vendor partner directories) come out empty. A company whose only listed website is its LinkedIn page has no derivable domain, and an empty cell says so; ``linkedin.com`` is worse than empty because it joins, dedupes and syncs as if it were real. The result is the domain someone REGISTERED, not the bare host: a provider that lists ``careers.acme.com`` is describing ``acme.com``. A subdomain joins against nothing and sends an agent somewhere that often does not resolve. Page builders that give each customer their own label are the exception the Public Suffix List already encodes, so ``acme.wixsite.com`` survives whole rather than collapsing into ``wixsite.com``. ``company_name`` guards the case those two cannot: a directory listing reduces to the DIRECTORY owner's domain, so ``cloudpartners.transform.microsoft.com`` becomes ``microsoft.com``: right shape, wrong company, and nothing downstream can tell. Pointed at the column naming the employer, the domain is dropped when the two disagree. Optional: without it the other two rules still apply.
              - …
            - TableGetPathInput: Read a dotted path out of an object- or list-valued cell. Object and list columns were storable but unreadable: nothing in the catalog could reach a field inside one, so an enrichment payload landed in a cell and stopped there. Segments index dicts by key and lists by integer position: ``employees.count``, ``emails.0.address``. ``output_type`` is declared rather than derived because a JSON path can land on anything, and the column's data type has to be known before a single row is evaluated.
              - …
            - TableFormatInput: Build a string from a positional template and a list of arguments. ``concatenate`` joins whole columns with one separator, which cannot produce "Enterprise: Acme (12.4%)". Placeholders are positional only (``{0}``, ``{1}``) so the template stays data, not an expression language. Like ``concatenate`` this takes no ``source_column_id``: its inputs are its arguments, not the value flowing down the chain.
              - …
            - TableDateDiffInput: The signed duration between this step's date and another date. ``date_arithmetic`` shifts a date by a CONSTANT amount, so the gap between two date columns had no expression. Positive when the step's own date is the later of the two.
              - …
            - TableKeywordsInput: The most frequent meaningful words in a text or list value. Reads a body of text (a scraped page, a bio, a job description) and returns the words that carry its subject, ordered most frequent first. Stopwords ("the", "and", "with") are dropped: a frequency count that keeps them returns the same five words for every row and says nothing about any of them. Deterministic and pure: no model call, so a keyword column costs nothing and re-runs identically.
              - …
            - TableListFilterInput: Keep only the list items whose field passes a test. An enrichment payload lands as a list of objects (every job opening, every funding round, every contact) and the row usually wants a subset of it: the engineering roles, the rounds after 2024, the contacts with an email. Without this the whole list is the only thing a cell can hold. ``field`` is a dotted path INSIDE each item (``location.country``); leaving it empty tests the item itself, which is what a list of plain strings needs. ``exists``/``missing`` ignore ``value``: they ask only whether the field is there.
              - …
            - TableListSortInput: Order a list, ascending or descending. ``list_unique`` and ``list_join`` both preserve whatever order the source happened to arrive in, which is fine until the cell is meant to be READ: a top-3 of anything, a chronological history, an alphabetised tag list. ``field`` names the dotted path to sort objects BY; empty sorts the items themselves. Values that cannot be compared with each other (a number next to a string) are ordered by type first, so the sort is total instead of raising on the row where the data is mixed.
              - …
            - TableListIntersectInput: The values this list shares with another: the overlap, in the first list's order. The scoring question every ICP fit column asks: which of the buyer's tags, technologies or keywords are ALSO on my target list. Doing it by hand meant one ``if_then_else`` per tag. ``other`` is a column holding the second list, or literal text split on ``separator``. Matching ignores case and surrounding spaces, because the two lists come from different sources and "Shopify " never equals "shopify" when it matters most.
              - …
            - TableTextSimilarityInput: How alike two pieces of text are, as a percentage. The dedupe and match question: is "Acme Inc." the same company as "Acme, Inc"? An exact comparison says no and a human says obviously yes, so the honest answer is a number the row can threshold on. Case and surrounding whitespace never count: they are formatting, not difference. 100 means identical after that normalisation, 0 means nothing in common.
              - …
            - TableDetectLanguageInput: The language a piece of text is written in, as an ISO 639-1 code. Routes a row before anything expensive touches it: which sequence to enrol a lead into, which reviewer sees a scraped page, whether to translate at all. Script comes first (Cyrillic, Greek, Hebrew, Arabic, Han, kana and hangul each answer on their own) and Latin text is decided by the function words it uses. That is a heuristic, not a model: it is deterministic, free, and honest about not knowing, returning null when the text is too short or matches nothing.
              - …
            - TableScoreWordsInput: Score text by the weighted words it contains. The rules half of lead scoring, without a model: "enterprise" is worth 3, "student" is worth -5, and the cell adds up whatever the row's text, tags or tech stack actually say. Expressing the same thing with ``if_then_else`` needs one step per word and runs out of chain depth at ten. Weights are a plain object: word or phrase to number. Matching is case-insensitive; a multi-word key matches as a phrase. ``count_repeats`` decides whether saying "enterprise" three times scores three times, which is the difference between weighing a claim and weighing a page.
              - …
            - TableHashInput: Hash a value: the identifier ad platforms and clean rooms ask for. Uploading an audience means handing over hashed emails, never raw ones, and the hash has to be produced the way the platform specifies: lowercased and trimmed first, hex digest out. That normalisation is the part people get wrong by hand, so it happens here rather than in three chained steps.
              - …
            - TableUriEncodeInput: Percent-encode a value so it survives being put in a URL. Every search-URL column builds the same thing (a query string with a company name in it) and every one of them breaks on the first ampersand or accent. Encoding belongs one step before the URL is assembled, not in a regex chain that handles the four characters someone remembered. ``component`` escapes everything reserved, which is what a query value needs; ``full`` leaves ``:/?#`` alone so an entire URL stays usable. Lists are encoded item by item.
              - …
            - TableUrlValidInput: Whether a value is a usable web address. The gate in front of every scrape, screenshot and HTTP column: a row whose "website" cell holds "n/a", "coming soon" or a bare company name should never spend a credit finding that out. True means the value parses as a host with a real-looking domain, not that the site answers. A formula cannot make a request, and pretending otherwise would be the one dishonest thing this function could do.
              - …
            - TableEmailPermutationsInput: The candidate work-email addresses for a name at a domain. What a verifier needs to be pointed at: nine or so patterns companies actually use, in the order they are actually common, so the cheapest verification step has a list to work through instead of one guess. The piped value is the person's name: "Ada Lovelace", or a first name with ``last_name`` supplying the rest. Anything after the first and last token (middle names, suffixes) is ignored rather than permuted, which is what keeps the list nine long instead of ninety.
              - …
            - TableRoundRobinInput: Assign each row to one of a list of owners, evenly. Lead routing, as a column: the rep, the region, the sending inbox. The piped value is the row's IDENTITY (its email, domain or id) and the owner is derived from a hash of it rather than from the row's position. That is a deliberate departure from a counter-based round robin, and it is the only version that behaves: re-running the column, adding rows above, or sorting the view all leave every existing row with the owner it already had. A counter reassigns half the table the first time anything moves, which in a CRM means the wrong rep gets the follow-up.
              - …
            - TableWeightedRoundRobinInput: Assign each row to an owner, in proportion to each owner's share. The version real teams need: a senior rep takes three leads for every one a new hire gets, one region absorbs twice the volume of another. Shares are whole numbers and mean exactly what they look like: 3 and 1 is three quarters and one quarter. Stable per row for the same reason ``round_robin`` is: the owner comes from a hash of the row's identity, so nothing already assigned moves when the table grows or the view is sorted. Changing the SHARES does move rows, because that is what changing them means.
              - …
          - `operand` union, required
            - ColumnRef: A parameter that reads another column's cell value on the same row.
              - …
            - StepRef: A parameter that reads an EARLIER step's output in the same chain. Without this a chain could fork but never join. ``source_step`` already let a unary step read back to an earlier result, but the only functions that take several inputs at once (``concatenate`` and ``format``) could name columns and literals and nothing else. So "upper-case the initial of one column, do the same to another, then put the two together" had no expression: the two halves could be computed but never combined, and the author had to invert the whole formula into combine-first-then-extract. Reading a step that is not strictly earlier has no value to read, so ``chain_refs.validate_step_references`` rejects it at save time rather than letting the engine quietly substitute something else.
              - …
            - string
            - integer
            - number
            - boolean
          - `operator` 'add' | 'subtract' | 'multiply' | 'divide', required
          - `source_column_id` string, uuid, nullable
          - `source_step` integer, nullable: Read the result of an EARLIER step, by 1-based position, instead of the step immediately before. Lets a later step fork back to an intermediate value (splitting a URL once and then using both the raw split and something derived from it), which a strict pipeline cannot express. Ignored when source_column_id is set (a column wins over a step), and ignored by functions that read their arguments rather than the piped value. None reads the previous step.
        - TableRoundInput: Round a numeric value to a precision.
          - `failure_mode` 'pass_through_raw' | 'set_null' | 'static' | 'skip': What a formula cell resolves to when a step in its chain fails. Applies to the whole chain, read off the top-level function only. ``SKIP`` is equivalent to ``SET_NULL`` for table cells (a cell always has a stored slot, so there is nothing to skip). Kept for shape compatibility.
          - `fallback_value` union
            - string
            - integer
            - number
            - boolean
          - `function` 'round'
          - `mode` 'round' | 'ceil' | 'floor'
          - `next` union
            - TableCopyInput: Copy the input value unchanged.
              - …
            - TableChangeCaseInput: Change the case of a string value.
              - …
            - TableTrimInput: Strip leading and trailing whitespace from a string value.
              - …
            - TableReplaceInput: Replace all occurrences of a substring.
              - …
            - TableRegexExtractInput: Extract a regex group from a string value.
              - …
            - TableRegexReplaceInput: Replace regex matches in a string value.
              - …
            - TableConcatenateInput: Join several values into one string. Sources are ORDERED and may mix columns with the results of earlier steps: ``[First name, step 2]`` and ``[step 2, First name]`` are different strings, which is why there is one list rather than a list of columns beside a list of steps. The field keeps its original name: every stored definition holds ``source_column_ids``, and the list is still overwhelmingly columns. Only the item type widened, so old definitions validate untouched.
              - …
            - TableArithmeticInput: Apply an arithmetic operator with a constant or column-valued operand.
              - …
            - TableRoundInput (recursive)
            - TableClampInput: Clamp a numeric value to an inclusive range.
              - …
            - TableDateFormatInput: Convert a date between iso/unix/unix_ms representations.
              - …
            - TableDateExtractInput: Extract a component (year, month, ...) from a date value.
              - …
            - TableDateArithmeticInput: Add or subtract a fixed duration from a date value.
              - …
            - TableListFirstInput: Take the first element of a list value.
              - …
            - TableListLastInput: Take the last element of a list value.
              - …
            - TableListNthInput: Take the element at an index of a list value.
              - …
            - TableListJoinInput: Join list elements into a string with a separator.
              - …
            - TableListCountInput: Count the elements of a list value.
              - …
            - TableListPluckInput: Pull one field out of every object in a list. Enrichment payloads routinely carry lists of objects (``[{"value": "Payroll"}, {"value": "HR"}]``) where the useful thing is the field, not the wrapper. Plucking turns that into ``["Payroll", "HR"]`` so ``list_join`` and friends can work on it; items without the field become empty and scalar items pass through unchanged.
              - …
            - TableListUniqueInput: De-duplicate list elements, keeping first-seen order.
              - …
            - TableListSplitInput: Split a string value into a list on a separator.
              - …
            - TableCoalesceInput: Substitute a default (a literal or another column) when the input is empty.
              - …
            - TableIfThenElseInput: Pick one of two values based on a comparison. Each of the three slots takes a literal or a column, so this expresses both "if this column is over that column" and "use A, else use B". Neither of those was reachable while they were constants.
              - …
            - TableConditionsInput: Fold several comparisons into ONE boolean. The engine's only boolean combinator, and the shape a column's ``run_condition`` is authored in: "only run where Employees > 50 AND Country is US". Nothing else here joins predicates: ``if_then_else`` compares exactly one pair and returns a value rather than a verdict. So without this a multi-clause gate could only be reached by chaining steps that pipe a truthy stand-in forward, which no editor could read back. One joiner over clauses and, at most one level down, groups of clauses: "A and (B or C)". That is precisely the row filter's shape, so a view's filter can be saved as a gate and read back as a filter without loss; a deeper tree would be expressible on one side only. Reads its clauses' operands directly and ignores the piped input, so it is a leaf rather than a transform.
              - …
            - TableValueMappingInput: Map input values through a lookup table.
              - …
            - TableToStringInput: Coerce the input to a string.
              - …
            - TableToIntInput: Coerce the input to an integer.
              - …
            - TableToFloatInput: Coerce the input to a float.
              - …
            - TableToBoolInput: Coerce the input to a boolean.
              - …
            - TableToDateInput: Coerce the input to a date.
              - …
            - TablePhoneE164Input: Normalize a phone number to E.164 format.
              - …
            - TableUtmParseInput: Extract a UTM parameter from a URL value.
              - …
            - TableUrlDomainInput: Reduce a URL to its bare registrable-looking host. A website field arrives as a whole URL (``https://www.acme.com/about``) but the thing that joins, dedupes and enriches is ``acme.com``. Doing it with ``regex_extract`` means every caller hand-writes the same fragile pattern, so the parse lives here once and uses a real URL parser.
              - …
            - TableCompanyDomainInput: Reduce a company's website URL to the company's own registrable domain. Three differences from ``url_domain``, which stays the generic read (a column of LinkedIn profile URLs legitimately reduces to ``linkedin.com`` there): Hosts that name a platform rather than the company (LinkedIn and Facebook pages, link aggregators, review sites, vendor partner directories) come out empty. A company whose only listed website is its LinkedIn page has no derivable domain, and an empty cell says so; ``linkedin.com`` is worse than empty because it joins, dedupes and syncs as if it were real. The result is the domain someone REGISTERED, not the bare host: a provider that lists ``careers.acme.com`` is describing ``acme.com``. A subdomain joins against nothing and sends an agent somewhere that often does not resolve. Page builders that give each customer their own label are the exception the Public Suffix List already encodes, so ``acme.wixsite.com`` survives whole rather than collapsing into ``wixsite.com``. ``company_name`` guards the case those two cannot: a directory listing reduces to the DIRECTORY owner's domain, so ``cloudpartners.transform.microsoft.com`` becomes ``microsoft.com``: right shape, wrong company, and nothing downstream can tell. Pointed at the column naming the employer, the domain is dropped when the two disagree. Optional: without it the other two rules still apply.
              - …
            - TableGetPathInput: Read a dotted path out of an object- or list-valued cell. Object and list columns were storable but unreadable: nothing in the catalog could reach a field inside one, so an enrichment payload landed in a cell and stopped there. Segments index dicts by key and lists by integer position: ``employees.count``, ``emails.0.address``. ``output_type`` is declared rather than derived because a JSON path can land on anything, and the column's data type has to be known before a single row is evaluated.
              - …
            - TableFormatInput: Build a string from a positional template and a list of arguments. ``concatenate`` joins whole columns with one separator, which cannot produce "Enterprise: Acme (12.4%)". Placeholders are positional only (``{0}``, ``{1}``) so the template stays data, not an expression language. Like ``concatenate`` this takes no ``source_column_id``: its inputs are its arguments, not the value flowing down the chain.
              - …
            - TableDateDiffInput: The signed duration between this step's date and another date. ``date_arithmetic`` shifts a date by a CONSTANT amount, so the gap between two date columns had no expression. Positive when the step's own date is the later of the two.
              - …
            - TableKeywordsInput: The most frequent meaningful words in a text or list value. Reads a body of text (a scraped page, a bio, a job description) and returns the words that carry its subject, ordered most frequent first. Stopwords ("the", "and", "with") are dropped: a frequency count that keeps them returns the same five words for every row and says nothing about any of them. Deterministic and pure: no model call, so a keyword column costs nothing and re-runs identically.
              - …
            - TableListFilterInput: Keep only the list items whose field passes a test. An enrichment payload lands as a list of objects (every job opening, every funding round, every contact) and the row usually wants a subset of it: the engineering roles, the rounds after 2024, the contacts with an email. Without this the whole list is the only thing a cell can hold. ``field`` is a dotted path INSIDE each item (``location.country``); leaving it empty tests the item itself, which is what a list of plain strings needs. ``exists``/``missing`` ignore ``value``: they ask only whether the field is there.
              - …
            - TableListSortInput: Order a list, ascending or descending. ``list_unique`` and ``list_join`` both preserve whatever order the source happened to arrive in, which is fine until the cell is meant to be READ: a top-3 of anything, a chronological history, an alphabetised tag list. ``field`` names the dotted path to sort objects BY; empty sorts the items themselves. Values that cannot be compared with each other (a number next to a string) are ordered by type first, so the sort is total instead of raising on the row where the data is mixed.
              - …
            - TableListIntersectInput: The values this list shares with another: the overlap, in the first list's order. The scoring question every ICP fit column asks: which of the buyer's tags, technologies or keywords are ALSO on my target list. Doing it by hand meant one ``if_then_else`` per tag. ``other`` is a column holding the second list, or literal text split on ``separator``. Matching ignores case and surrounding spaces, because the two lists come from different sources and "Shopify " never equals "shopify" when it matters most.
              - …
            - TableTextSimilarityInput: How alike two pieces of text are, as a percentage. The dedupe and match question: is "Acme Inc." the same company as "Acme, Inc"? An exact comparison says no and a human says obviously yes, so the honest answer is a number the row can threshold on. Case and surrounding whitespace never count: they are formatting, not difference. 100 means identical after that normalisation, 0 means nothing in common.
              - …
            - TableDetectLanguageInput: The language a piece of text is written in, as an ISO 639-1 code. Routes a row before anything expensive touches it: which sequence to enrol a lead into, which reviewer sees a scraped page, whether to translate at all. Script comes first (Cyrillic, Greek, Hebrew, Arabic, Han, kana and hangul each answer on their own) and Latin text is decided by the function words it uses. That is a heuristic, not a model: it is deterministic, free, and honest about not knowing, returning null when the text is too short or matches nothing.
              - …
            - TableScoreWordsInput: Score text by the weighted words it contains. The rules half of lead scoring, without a model: "enterprise" is worth 3, "student" is worth -5, and the cell adds up whatever the row's text, tags or tech stack actually say. Expressing the same thing with ``if_then_else`` needs one step per word and runs out of chain depth at ten. Weights are a plain object: word or phrase to number. Matching is case-insensitive; a multi-word key matches as a phrase. ``count_repeats`` decides whether saying "enterprise" three times scores three times, which is the difference between weighing a claim and weighing a page.
              - …
            - TableHashInput: Hash a value: the identifier ad platforms and clean rooms ask for. Uploading an audience means handing over hashed emails, never raw ones, and the hash has to be produced the way the platform specifies: lowercased and trimmed first, hex digest out. That normalisation is the part people get wrong by hand, so it happens here rather than in three chained steps.
              - …
            - TableUriEncodeInput: Percent-encode a value so it survives being put in a URL. Every search-URL column builds the same thing (a query string with a company name in it) and every one of them breaks on the first ampersand or accent. Encoding belongs one step before the URL is assembled, not in a regex chain that handles the four characters someone remembered. ``component`` escapes everything reserved, which is what a query value needs; ``full`` leaves ``:/?#`` alone so an entire URL stays usable. Lists are encoded item by item.
              - …
            - TableUrlValidInput: Whether a value is a usable web address. The gate in front of every scrape, screenshot and HTTP column: a row whose "website" cell holds "n/a", "coming soon" or a bare company name should never spend a credit finding that out. True means the value parses as a host with a real-looking domain, not that the site answers. A formula cannot make a request, and pretending otherwise would be the one dishonest thing this function could do.
              - …
            - TableEmailPermutationsInput: The candidate work-email addresses for a name at a domain. What a verifier needs to be pointed at: nine or so patterns companies actually use, in the order they are actually common, so the cheapest verification step has a list to work through instead of one guess. The piped value is the person's name: "Ada Lovelace", or a first name with ``last_name`` supplying the rest. Anything after the first and last token (middle names, suffixes) is ignored rather than permuted, which is what keeps the list nine long instead of ninety.
              - …
            - TableRoundRobinInput: Assign each row to one of a list of owners, evenly. Lead routing, as a column: the rep, the region, the sending inbox. The piped value is the row's IDENTITY (its email, domain or id) and the owner is derived from a hash of it rather than from the row's position. That is a deliberate departure from a counter-based round robin, and it is the only version that behaves: re-running the column, adding rows above, or sorting the view all leave every existing row with the owner it already had. A counter reassigns half the table the first time anything moves, which in a CRM means the wrong rep gets the follow-up.
              - …
            - TableWeightedRoundRobinInput: Assign each row to an owner, in proportion to each owner's share. The version real teams need: a senior rep takes three leads for every one a new hire gets, one region absorbs twice the volume of another. Shares are whole numbers and mean exactly what they look like: 3 and 1 is three quarters and one quarter. Stable per row for the same reason ``round_robin`` is: the owner comes from a hash of the row's identity, so nothing already assigned moves when the table grows or the view is sorted. Changing the SHARES does move rows, because that is what changing them means.
              - …
          - `precision` integer
          - `source_column_id` string, uuid, nullable
          - `source_step` integer, nullable: Read the result of an EARLIER step, by 1-based position, instead of the step immediately before. Lets a later step fork back to an intermediate value (splitting a URL once and then using both the raw split and something derived from it), which a strict pipeline cannot express. Ignored when source_column_id is set (a column wins over a step), and ignored by functions that read their arguments rather than the piped value. None reads the previous step.
        - TableClampInput: Clamp a numeric value to an inclusive range.
          - `failure_mode` 'pass_through_raw' | 'set_null' | 'static' | 'skip': What a formula cell resolves to when a step in its chain fails. Applies to the whole chain, read off the top-level function only. ``SKIP`` is equivalent to ``SET_NULL`` for table cells (a cell always has a stored slot, so there is nothing to skip). Kept for shape compatibility.
          - `fallback_value` union
            - string
            - integer
            - number
            - boolean
          - `function` 'clamp'
          - `max_value` union
            - ColumnRef: A parameter that reads another column's cell value on the same row.
              - …
            - StepRef: A parameter that reads an EARLIER step's output in the same chain. Without this a chain could fork but never join. ``source_step`` already let a unary step read back to an earlier result, but the only functions that take several inputs at once (``concatenate`` and ``format``) could name columns and literals and nothing else. So "upper-case the initial of one column, do the same to another, then put the two together" had no expression: the two halves could be computed but never combined, and the author had to invert the whole formula into combine-first-then-extract. Reading a step that is not strictly earlier has no value to read, so ``chain_refs.validate_step_references`` rejects it at save time rather than letting the engine quietly substitute something else.
              - …
            - string
            - integer
            - number
            - boolean
          - `min_value` union
            - ColumnRef: A parameter that reads another column's cell value on the same row.
              - …
            - StepRef: A parameter that reads an EARLIER step's output in the same chain. Without this a chain could fork but never join. ``source_step`` already let a unary step read back to an earlier result, but the only functions that take several inputs at once (``concatenate`` and ``format``) could name columns and literals and nothing else. So "upper-case the initial of one column, do the same to another, then put the two together" had no expression: the two halves could be computed but never combined, and the author had to invert the whole formula into combine-first-then-extract. Reading a step that is not strictly earlier has no value to read, so ``chain_refs.validate_step_references`` rejects it at save time rather than letting the engine quietly substitute something else.
              - …
            - string
            - integer
            - number
            - boolean
          - `next` union
            - TableCopyInput: Copy the input value unchanged.
              - …
            - TableChangeCaseInput: Change the case of a string value.
              - …
            - TableTrimInput: Strip leading and trailing whitespace from a string value.
              - …
            - TableReplaceInput: Replace all occurrences of a substring.
              - …
            - TableRegexExtractInput: Extract a regex group from a string value.
              - …
            - TableRegexReplaceInput: Replace regex matches in a string value.
              - …
            - TableConcatenateInput: Join several values into one string. Sources are ORDERED and may mix columns with the results of earlier steps: ``[First name, step 2]`` and ``[step 2, First name]`` are different strings, which is why there is one list rather than a list of columns beside a list of steps. The field keeps its original name: every stored definition holds ``source_column_ids``, and the list is still overwhelmingly columns. Only the item type widened, so old definitions validate untouched.
              - …
            - TableArithmeticInput: Apply an arithmetic operator with a constant or column-valued operand.
              - …
            - TableRoundInput: Round a numeric value to a precision.
              - …
            - TableClampInput (recursive)
            - TableDateFormatInput: Convert a date between iso/unix/unix_ms representations.
              - …
            - TableDateExtractInput: Extract a component (year, month, ...) from a date value.
              - …
            - TableDateArithmeticInput: Add or subtract a fixed duration from a date value.
              - …
            - TableListFirstInput: Take the first element of a list value.
              - …
            - TableListLastInput: Take the last element of a list value.
              - …
            - TableListNthInput: Take the element at an index of a list value.
              - …
            - TableListJoinInput: Join list elements into a string with a separator.
              - …
            - TableListCountInput: Count the elements of a list value.
              - …
            - TableListPluckInput: Pull one field out of every object in a list. Enrichment payloads routinely carry lists of objects (``[{"value": "Payroll"}, {"value": "HR"}]``) where the useful thing is the field, not the wrapper. Plucking turns that into ``["Payroll", "HR"]`` so ``list_join`` and friends can work on it; items without the field become empty and scalar items pass through unchanged.
              - …
            - TableListUniqueInput: De-duplicate list elements, keeping first-seen order.
              - …
            - TableListSplitInput: Split a string value into a list on a separator.
              - …
            - TableCoalesceInput: Substitute a default (a literal or another column) when the input is empty.
              - …
            - TableIfThenElseInput: Pick one of two values based on a comparison. Each of the three slots takes a literal or a column, so this expresses both "if this column is over that column" and "use A, else use B". Neither of those was reachable while they were constants.
              - …
            - TableConditionsInput: Fold several comparisons into ONE boolean. The engine's only boolean combinator, and the shape a column's ``run_condition`` is authored in: "only run where Employees > 50 AND Country is US". Nothing else here joins predicates: ``if_then_else`` compares exactly one pair and returns a value rather than a verdict. So without this a multi-clause gate could only be reached by chaining steps that pipe a truthy stand-in forward, which no editor could read back. One joiner over clauses and, at most one level down, groups of clauses: "A and (B or C)". That is precisely the row filter's shape, so a view's filter can be saved as a gate and read back as a filter without loss; a deeper tree would be expressible on one side only. Reads its clauses' operands directly and ignores the piped input, so it is a leaf rather than a transform.
              - …
            - TableValueMappingInput: Map input values through a lookup table.
              - …
            - TableToStringInput: Coerce the input to a string.
              - …
            - TableToIntInput: Coerce the input to an integer.
              - …
            - TableToFloatInput: Coerce the input to a float.
              - …
            - TableToBoolInput: Coerce the input to a boolean.
              - …
            - TableToDateInput: Coerce the input to a date.
              - …
            - TablePhoneE164Input: Normalize a phone number to E.164 format.
              - …
            - TableUtmParseInput: Extract a UTM parameter from a URL value.
              - …
            - TableUrlDomainInput: Reduce a URL to its bare registrable-looking host. A website field arrives as a whole URL (``https://www.acme.com/about``) but the thing that joins, dedupes and enriches is ``acme.com``. Doing it with ``regex_extract`` means every caller hand-writes the same fragile pattern, so the parse lives here once and uses a real URL parser.
              - …
            - TableCompanyDomainInput: Reduce a company's website URL to the company's own registrable domain. Three differences from ``url_domain``, which stays the generic read (a column of LinkedIn profile URLs legitimately reduces to ``linkedin.com`` there): Hosts that name a platform rather than the company (LinkedIn and Facebook pages, link aggregators, review sites, vendor partner directories) come out empty. A company whose only listed website is its LinkedIn page has no derivable domain, and an empty cell says so; ``linkedin.com`` is worse than empty because it joins, dedupes and syncs as if it were real. The result is the domain someone REGISTERED, not the bare host: a provider that lists ``careers.acme.com`` is describing ``acme.com``. A subdomain joins against nothing and sends an agent somewhere that often does not resolve. Page builders that give each customer their own label are the exception the Public Suffix List already encodes, so ``acme.wixsite.com`` survives whole rather than collapsing into ``wixsite.com``. ``company_name`` guards the case those two cannot: a directory listing reduces to the DIRECTORY owner's domain, so ``cloudpartners.transform.microsoft.com`` becomes ``microsoft.com``: right shape, wrong company, and nothing downstream can tell. Pointed at the column naming the employer, the domain is dropped when the two disagree. Optional: without it the other two rules still apply.
              - …
            - TableGetPathInput: Read a dotted path out of an object- or list-valued cell. Object and list columns were storable but unreadable: nothing in the catalog could reach a field inside one, so an enrichment payload landed in a cell and stopped there. Segments index dicts by key and lists by integer position: ``employees.count``, ``emails.0.address``. ``output_type`` is declared rather than derived because a JSON path can land on anything, and the column's data type has to be known before a single row is evaluated.
              - …
            - TableFormatInput: Build a string from a positional template and a list of arguments. ``concatenate`` joins whole columns with one separator, which cannot produce "Enterprise: Acme (12.4%)". Placeholders are positional only (``{0}``, ``{1}``) so the template stays data, not an expression language. Like ``concatenate`` this takes no ``source_column_id``: its inputs are its arguments, not the value flowing down the chain.
              - …
            - TableDateDiffInput: The signed duration between this step's date and another date. ``date_arithmetic`` shifts a date by a CONSTANT amount, so the gap between two date columns had no expression. Positive when the step's own date is the later of the two.
              - …
            - TableKeywordsInput: The most frequent meaningful words in a text or list value. Reads a body of text (a scraped page, a bio, a job description) and returns the words that carry its subject, ordered most frequent first. Stopwords ("the", "and", "with") are dropped: a frequency count that keeps them returns the same five words for every row and says nothing about any of them. Deterministic and pure: no model call, so a keyword column costs nothing and re-runs identically.
              - …
            - TableListFilterInput: Keep only the list items whose field passes a test. An enrichment payload lands as a list of objects (every job opening, every funding round, every contact) and the row usually wants a subset of it: the engineering roles, the rounds after 2024, the contacts with an email. Without this the whole list is the only thing a cell can hold. ``field`` is a dotted path INSIDE each item (``location.country``); leaving it empty tests the item itself, which is what a list of plain strings needs. ``exists``/``missing`` ignore ``value``: they ask only whether the field is there.
              - …
            - TableListSortInput: Order a list, ascending or descending. ``list_unique`` and ``list_join`` both preserve whatever order the source happened to arrive in, which is fine until the cell is meant to be READ: a top-3 of anything, a chronological history, an alphabetised tag list. ``field`` names the dotted path to sort objects BY; empty sorts the items themselves. Values that cannot be compared with each other (a number next to a string) are ordered by type first, so the sort is total instead of raising on the row where the data is mixed.
              - …
            - TableListIntersectInput: The values this list shares with another: the overlap, in the first list's order. The scoring question every ICP fit column asks: which of the buyer's tags, technologies or keywords are ALSO on my target list. Doing it by hand meant one ``if_then_else`` per tag. ``other`` is a column holding the second list, or literal text split on ``separator``. Matching ignores case and surrounding spaces, because the two lists come from different sources and "Shopify " never equals "shopify" when it matters most.
              - …
            - TableTextSimilarityInput: How alike two pieces of text are, as a percentage. The dedupe and match question: is "Acme Inc." the same company as "Acme, Inc"? An exact comparison says no and a human says obviously yes, so the honest answer is a number the row can threshold on. Case and surrounding whitespace never count: they are formatting, not difference. 100 means identical after that normalisation, 0 means nothing in common.
              - …
            - TableDetectLanguageInput: The language a piece of text is written in, as an ISO 639-1 code. Routes a row before anything expensive touches it: which sequence to enrol a lead into, which reviewer sees a scraped page, whether to translate at all. Script comes first (Cyrillic, Greek, Hebrew, Arabic, Han, kana and hangul each answer on their own) and Latin text is decided by the function words it uses. That is a heuristic, not a model: it is deterministic, free, and honest about not knowing, returning null when the text is too short or matches nothing.
              - …
            - TableScoreWordsInput: Score text by the weighted words it contains. The rules half of lead scoring, without a model: "enterprise" is worth 3, "student" is worth -5, and the cell adds up whatever the row's text, tags or tech stack actually say. Expressing the same thing with ``if_then_else`` needs one step per word and runs out of chain depth at ten. Weights are a plain object: word or phrase to number. Matching is case-insensitive; a multi-word key matches as a phrase. ``count_repeats`` decides whether saying "enterprise" three times scores three times, which is the difference between weighing a claim and weighing a page.
              - …
            - TableHashInput: Hash a value: the identifier ad platforms and clean rooms ask for. Uploading an audience means handing over hashed emails, never raw ones, and the hash has to be produced the way the platform specifies: lowercased and trimmed first, hex digest out. That normalisation is the part people get wrong by hand, so it happens here rather than in three chained steps.
              - …
            - TableUriEncodeInput: Percent-encode a value so it survives being put in a URL. Every search-URL column builds the same thing (a query string with a company name in it) and every one of them breaks on the first ampersand or accent. Encoding belongs one step before the URL is assembled, not in a regex chain that handles the four characters someone remembered. ``component`` escapes everything reserved, which is what a query value needs; ``full`` leaves ``:/?#`` alone so an entire URL stays usable. Lists are encoded item by item.
              - …
            - TableUrlValidInput: Whether a value is a usable web address. The gate in front of every scrape, screenshot and HTTP column: a row whose "website" cell holds "n/a", "coming soon" or a bare company name should never spend a credit finding that out. True means the value parses as a host with a real-looking domain, not that the site answers. A formula cannot make a request, and pretending otherwise would be the one dishonest thing this function could do.
              - …
            - TableEmailPermutationsInput: The candidate work-email addresses for a name at a domain. What a verifier needs to be pointed at: nine or so patterns companies actually use, in the order they are actually common, so the cheapest verification step has a list to work through instead of one guess. The piped value is the person's name: "Ada Lovelace", or a first name with ``last_name`` supplying the rest. Anything after the first and last token (middle names, suffixes) is ignored rather than permuted, which is what keeps the list nine long instead of ninety.
              - …
            - TableRoundRobinInput: Assign each row to one of a list of owners, evenly. Lead routing, as a column: the rep, the region, the sending inbox. The piped value is the row's IDENTITY (its email, domain or id) and the owner is derived from a hash of it rather than from the row's position. That is a deliberate departure from a counter-based round robin, and it is the only version that behaves: re-running the column, adding rows above, or sorting the view all leave every existing row with the owner it already had. A counter reassigns half the table the first time anything moves, which in a CRM means the wrong rep gets the follow-up.
              - …
            - TableWeightedRoundRobinInput: Assign each row to an owner, in proportion to each owner's share. The version real teams need: a senior rep takes three leads for every one a new hire gets, one region absorbs twice the volume of another. Shares are whole numbers and mean exactly what they look like: 3 and 1 is three quarters and one quarter. Stable per row for the same reason ``round_robin`` is: the owner comes from a hash of the row's identity, so nothing already assigned moves when the table grows or the view is sorted. Changing the SHARES does move rows, because that is what changing them means.
              - …
          - `source_column_id` string, uuid, nullable
          - `source_step` integer, nullable: Read the result of an EARLIER step, by 1-based position, instead of the step immediately before. Lets a later step fork back to an intermediate value (splitting a URL once and then using both the raw split and something derived from it), which a strict pipeline cannot express. Ignored when source_column_id is set (a column wins over a step), and ignored by functions that read their arguments rather than the piped value. None reads the previous step.
        - TableDateFormatInput: Convert a date between iso/unix/unix_ms representations.
          - `failure_mode` 'pass_through_raw' | 'set_null' | 'static' | 'skip': What a formula cell resolves to when a step in its chain fails. Applies to the whole chain, read off the top-level function only. ``SKIP`` is equivalent to ``SET_NULL`` for table cells (a cell always has a stored slot, so there is nothing to skip). Kept for shape compatibility.
          - `fallback_value` union
            - string
            - integer
            - number
            - boolean
          - `function` 'date_format'
          - `input_format` 'iso' | 'unix' | 'unix_ms', required
          - `next` union
            - TableCopyInput: Copy the input value unchanged.
              - …
            - TableChangeCaseInput: Change the case of a string value.
              - …
            - TableTrimInput: Strip leading and trailing whitespace from a string value.
              - …
            - TableReplaceInput: Replace all occurrences of a substring.
              - …
            - TableRegexExtractInput: Extract a regex group from a string value.
              - …
            - TableRegexReplaceInput: Replace regex matches in a string value.
              - …
            - TableConcatenateInput: Join several values into one string. Sources are ORDERED and may mix columns with the results of earlier steps: ``[First name, step 2]`` and ``[step 2, First name]`` are different strings, which is why there is one list rather than a list of columns beside a list of steps. The field keeps its original name: every stored definition holds ``source_column_ids``, and the list is still overwhelmingly columns. Only the item type widened, so old definitions validate untouched.
              - …
            - TableArithmeticInput: Apply an arithmetic operator with a constant or column-valued operand.
              - …
            - TableRoundInput: Round a numeric value to a precision.
              - …
            - TableClampInput: Clamp a numeric value to an inclusive range.
              - …
            - TableDateFormatInput (recursive)
            - TableDateExtractInput: Extract a component (year, month, ...) from a date value.
              - …
            - TableDateArithmeticInput: Add or subtract a fixed duration from a date value.
              - …
            - TableListFirstInput: Take the first element of a list value.
              - …
            - TableListLastInput: Take the last element of a list value.
              - …
            - TableListNthInput: Take the element at an index of a list value.
              - …
            - TableListJoinInput: Join list elements into a string with a separator.
              - …
            - TableListCountInput: Count the elements of a list value.
              - …
            - TableListPluckInput: Pull one field out of every object in a list. Enrichment payloads routinely carry lists of objects (``[{"value": "Payroll"}, {"value": "HR"}]``) where the useful thing is the field, not the wrapper. Plucking turns that into ``["Payroll", "HR"]`` so ``list_join`` and friends can work on it; items without the field become empty and scalar items pass through unchanged.
              - …
            - TableListUniqueInput: De-duplicate list elements, keeping first-seen order.
              - …
            - TableListSplitInput: Split a string value into a list on a separator.
              - …
            - TableCoalesceInput: Substitute a default (a literal or another column) when the input is empty.
              - …
            - TableIfThenElseInput: Pick one of two values based on a comparison. Each of the three slots takes a literal or a column, so this expresses both "if this column is over that column" and "use A, else use B". Neither of those was reachable while they were constants.
              - …
            - TableConditionsInput: Fold several comparisons into ONE boolean. The engine's only boolean combinator, and the shape a column's ``run_condition`` is authored in: "only run where Employees > 50 AND Country is US". Nothing else here joins predicates: ``if_then_else`` compares exactly one pair and returns a value rather than a verdict. So without this a multi-clause gate could only be reached by chaining steps that pipe a truthy stand-in forward, which no editor could read back. One joiner over clauses and, at most one level down, groups of clauses: "A and (B or C)". That is precisely the row filter's shape, so a view's filter can be saved as a gate and read back as a filter without loss; a deeper tree would be expressible on one side only. Reads its clauses' operands directly and ignores the piped input, so it is a leaf rather than a transform.
              - …
            - TableValueMappingInput: Map input values through a lookup table.
              - …
            - TableToStringInput: Coerce the input to a string.
              - …
            - TableToIntInput: Coerce the input to an integer.
              - …
            - TableToFloatInput: Coerce the input to a float.
              - …
            - TableToBoolInput: Coerce the input to a boolean.
              - …
            - TableToDateInput: Coerce the input to a date.
              - …
            - TablePhoneE164Input: Normalize a phone number to E.164 format.
              - …
            - TableUtmParseInput: Extract a UTM parameter from a URL value.
              - …
            - TableUrlDomainInput: Reduce a URL to its bare registrable-looking host. A website field arrives as a whole URL (``https://www.acme.com/about``) but the thing that joins, dedupes and enriches is ``acme.com``. Doing it with ``regex_extract`` means every caller hand-writes the same fragile pattern, so the parse lives here once and uses a real URL parser.
              - …
            - TableCompanyDomainInput: Reduce a company's website URL to the company's own registrable domain. Three differences from ``url_domain``, which stays the generic read (a column of LinkedIn profile URLs legitimately reduces to ``linkedin.com`` there): Hosts that name a platform rather than the company (LinkedIn and Facebook pages, link aggregators, review sites, vendor partner directories) come out empty. A company whose only listed website is its LinkedIn page has no derivable domain, and an empty cell says so; ``linkedin.com`` is worse than empty because it joins, dedupes and syncs as if it were real. The result is the domain someone REGISTERED, not the bare host: a provider that lists ``careers.acme.com`` is describing ``acme.com``. A subdomain joins against nothing and sends an agent somewhere that often does not resolve. Page builders that give each customer their own label are the exception the Public Suffix List already encodes, so ``acme.wixsite.com`` survives whole rather than collapsing into ``wixsite.com``. ``company_name`` guards the case those two cannot: a directory listing reduces to the DIRECTORY owner's domain, so ``cloudpartners.transform.microsoft.com`` becomes ``microsoft.com``: right shape, wrong company, and nothing downstream can tell. Pointed at the column naming the employer, the domain is dropped when the two disagree. Optional: without it the other two rules still apply.
              - …
            - TableGetPathInput: Read a dotted path out of an object- or list-valued cell. Object and list columns were storable but unreadable: nothing in the catalog could reach a field inside one, so an enrichment payload landed in a cell and stopped there. Segments index dicts by key and lists by integer position: ``employees.count``, ``emails.0.address``. ``output_type`` is declared rather than derived because a JSON path can land on anything, and the column's data type has to be known before a single row is evaluated.
              - …
            - TableFormatInput: Build a string from a positional template and a list of arguments. ``concatenate`` joins whole columns with one separator, which cannot produce "Enterprise: Acme (12.4%)". Placeholders are positional only (``{0}``, ``{1}``) so the template stays data, not an expression language. Like ``concatenate`` this takes no ``source_column_id``: its inputs are its arguments, not the value flowing down the chain.
              - …
            - TableDateDiffInput: The signed duration between this step's date and another date. ``date_arithmetic`` shifts a date by a CONSTANT amount, so the gap between two date columns had no expression. Positive when the step's own date is the later of the two.
              - …
            - TableKeywordsInput: The most frequent meaningful words in a text or list value. Reads a body of text (a scraped page, a bio, a job description) and returns the words that carry its subject, ordered most frequent first. Stopwords ("the", "and", "with") are dropped: a frequency count that keeps them returns the same five words for every row and says nothing about any of them. Deterministic and pure: no model call, so a keyword column costs nothing and re-runs identically.
              - …
            - TableListFilterInput: Keep only the list items whose field passes a test. An enrichment payload lands as a list of objects (every job opening, every funding round, every contact) and the row usually wants a subset of it: the engineering roles, the rounds after 2024, the contacts with an email. Without this the whole list is the only thing a cell can hold. ``field`` is a dotted path INSIDE each item (``location.country``); leaving it empty tests the item itself, which is what a list of plain strings needs. ``exists``/``missing`` ignore ``value``: they ask only whether the field is there.
              - …
            - TableListSortInput: Order a list, ascending or descending. ``list_unique`` and ``list_join`` both preserve whatever order the source happened to arrive in, which is fine until the cell is meant to be READ: a top-3 of anything, a chronological history, an alphabetised tag list. ``field`` names the dotted path to sort objects BY; empty sorts the items themselves. Values that cannot be compared with each other (a number next to a string) are ordered by type first, so the sort is total instead of raising on the row where the data is mixed.
              - …
            - TableListIntersectInput: The values this list shares with another: the overlap, in the first list's order. The scoring question every ICP fit column asks: which of the buyer's tags, technologies or keywords are ALSO on my target list. Doing it by hand meant one ``if_then_else`` per tag. ``other`` is a column holding the second list, or literal text split on ``separator``. Matching ignores case and surrounding spaces, because the two lists come from different sources and "Shopify " never equals "shopify" when it matters most.
              - …
            - TableTextSimilarityInput: How alike two pieces of text are, as a percentage. The dedupe and match question: is "Acme Inc." the same company as "Acme, Inc"? An exact comparison says no and a human says obviously yes, so the honest answer is a number the row can threshold on. Case and surrounding whitespace never count: they are formatting, not difference. 100 means identical after that normalisation, 0 means nothing in common.
              - …
            - TableDetectLanguageInput: The language a piece of text is written in, as an ISO 639-1 code. Routes a row before anything expensive touches it: which sequence to enrol a lead into, which reviewer sees a scraped page, whether to translate at all. Script comes first (Cyrillic, Greek, Hebrew, Arabic, Han, kana and hangul each answer on their own) and Latin text is decided by the function words it uses. That is a heuristic, not a model: it is deterministic, free, and honest about not knowing, returning null when the text is too short or matches nothing.
              - …
            - TableScoreWordsInput: Score text by the weighted words it contains. The rules half of lead scoring, without a model: "enterprise" is worth 3, "student" is worth -5, and the cell adds up whatever the row's text, tags or tech stack actually say. Expressing the same thing with ``if_then_else`` needs one step per word and runs out of chain depth at ten. Weights are a plain object: word or phrase to number. Matching is case-insensitive; a multi-word key matches as a phrase. ``count_repeats`` decides whether saying "enterprise" three times scores three times, which is the difference between weighing a claim and weighing a page.
              - …
            - TableHashInput: Hash a value: the identifier ad platforms and clean rooms ask for. Uploading an audience means handing over hashed emails, never raw ones, and the hash has to be produced the way the platform specifies: lowercased and trimmed first, hex digest out. That normalisation is the part people get wrong by hand, so it happens here rather than in three chained steps.
              - …
            - TableUriEncodeInput: Percent-encode a value so it survives being put in a URL. Every search-URL column builds the same thing (a query string with a company name in it) and every one of them breaks on the first ampersand or accent. Encoding belongs one step before the URL is assembled, not in a regex chain that handles the four characters someone remembered. ``component`` escapes everything reserved, which is what a query value needs; ``full`` leaves ``:/?#`` alone so an entire URL stays usable. Lists are encoded item by item.
              - …
            - TableUrlValidInput: Whether a value is a usable web address. The gate in front of every scrape, screenshot and HTTP column: a row whose "website" cell holds "n/a", "coming soon" or a bare company name should never spend a credit finding that out. True means the value parses as a host with a real-looking domain, not that the site answers. A formula cannot make a request, and pretending otherwise would be the one dishonest thing this function could do.
              - …
            - TableEmailPermutationsInput: The candidate work-email addresses for a name at a domain. What a verifier needs to be pointed at: nine or so patterns companies actually use, in the order they are actually common, so the cheapest verification step has a list to work through instead of one guess. The piped value is the person's name: "Ada Lovelace", or a first name with ``last_name`` supplying the rest. Anything after the first and last token (middle names, suffixes) is ignored rather than permuted, which is what keeps the list nine long instead of ninety.
              - …
            - TableRoundRobinInput: Assign each row to one of a list of owners, evenly. Lead routing, as a column: the rep, the region, the sending inbox. The piped value is the row's IDENTITY (its email, domain or id) and the owner is derived from a hash of it rather than from the row's position. That is a deliberate departure from a counter-based round robin, and it is the only version that behaves: re-running the column, adding rows above, or sorting the view all leave every existing row with the owner it already had. A counter reassigns half the table the first time anything moves, which in a CRM means the wrong rep gets the follow-up.
              - …
            - TableWeightedRoundRobinInput: Assign each row to an owner, in proportion to each owner's share. The version real teams need: a senior rep takes three leads for every one a new hire gets, one region absorbs twice the volume of another. Shares are whole numbers and mean exactly what they look like: 3 and 1 is three quarters and one quarter. Stable per row for the same reason ``round_robin`` is: the owner comes from a hash of the row's identity, so nothing already assigned moves when the table grows or the view is sorted. Changing the SHARES does move rows, because that is what changing them means.
              - …
          - `output_format` 'iso' | 'unix' | 'unix_ms', required
          - `source_column_id` string, uuid, nullable
          - `source_step` integer, nullable: Read the result of an EARLIER step, by 1-based position, instead of the step immediately before. Lets a later step fork back to an intermediate value (splitting a URL once and then using both the raw split and something derived from it), which a strict pipeline cannot express. Ignored when source_column_id is set (a column wins over a step), and ignored by functions that read their arguments rather than the piped value. None reads the previous step.
        - TableDateExtractInput: Extract a component (year, month, ...) from a date value.
          - `component` 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second', required
          - `failure_mode` 'pass_through_raw' | 'set_null' | 'static' | 'skip': What a formula cell resolves to when a step in its chain fails. Applies to the whole chain, read off the top-level function only. ``SKIP`` is equivalent to ``SET_NULL`` for table cells (a cell always has a stored slot, so there is nothing to skip). Kept for shape compatibility.
          - `fallback_value` union
            - string
            - integer
            - number
            - boolean
          - `function` 'date_extract'
          - `next` union
            - TableCopyInput: Copy the input value unchanged.
              - …
            - TableChangeCaseInput: Change the case of a string value.
              - …
            - TableTrimInput: Strip leading and trailing whitespace from a string value.
              - …
            - TableReplaceInput: Replace all occurrences of a substring.
              - …
            - TableRegexExtractInput: Extract a regex group from a string value.
              - …
            - TableRegexReplaceInput: Replace regex matches in a string value.
              - …
            - TableConcatenateInput: Join several values into one string. Sources are ORDERED and may mix columns with the results of earlier steps: ``[First name, step 2]`` and ``[step 2, First name]`` are different strings, which is why there is one list rather than a list of columns beside a list of steps. The field keeps its original name: every stored definition holds ``source_column_ids``, and the list is still overwhelmingly columns. Only the item type widened, so old definitions validate untouched.
              - …
            - TableArithmeticInput: Apply an arithmetic operator with a constant or column-valued operand.
              - …
            - TableRoundInput: Round a numeric value to a precision.
              - …
            - TableClampInput: Clamp a numeric value to an inclusive range.
              - …
            - TableDateFormatInput: Convert a date between iso/unix/unix_ms representations.
              - …
            - TableDateExtractInput (recursive)
            - TableDateArithmeticInput: Add or subtract a fixed duration from a date value.
              - …
            - TableListFirstInput: Take the first element of a list value.
              - …
            - TableListLastInput: Take the last element of a list value.
              - …
            - TableListNthInput: Take the element at an index of a list value.
              - …
            - TableListJoinInput: Join list elements into a string with a separator.
              - …
            - TableListCountInput: Count the elements of a list value.
              - …
            - TableListPluckInput: Pull one field out of every object in a list. Enrichment payloads routinely carry lists of objects (``[{"value": "Payroll"}, {"value": "HR"}]``) where the useful thing is the field, not the wrapper. Plucking turns that into ``["Payroll", "HR"]`` so ``list_join`` and friends can work on it; items without the field become empty and scalar items pass through unchanged.
              - …
            - TableListUniqueInput: De-duplicate list elements, keeping first-seen order.
              - …
            - TableListSplitInput: Split a string value into a list on a separator.
              - …
            - TableCoalesceInput: Substitute a default (a literal or another column) when the input is empty.
              - …
            - TableIfThenElseInput: Pick one of two values based on a comparison. Each of the three slots takes a literal or a column, so this expresses both "if this column is over that column" and "use A, else use B". Neither of those was reachable while they were constants.
              - …
            - TableConditionsInput: Fold several comparisons into ONE boolean. The engine's only boolean combinator, and the shape a column's ``run_condition`` is authored in: "only run where Employees > 50 AND Country is US". Nothing else here joins predicates: ``if_then_else`` compares exactly one pair and returns a value rather than a verdict. So without this a multi-clause gate could only be reached by chaining steps that pipe a truthy stand-in forward, which no editor could read back. One joiner over clauses and, at most one level down, groups of clauses: "A and (B or C)". That is precisely the row filter's shape, so a view's filter can be saved as a gate and read back as a filter without loss; a deeper tree would be expressible on one side only. Reads its clauses' operands directly and ignores the piped input, so it is a leaf rather than a transform.
              - …
            - TableValueMappingInput: Map input values through a lookup table.
              - …
            - TableToStringInput: Coerce the input to a string.
              - …
            - TableToIntInput: Coerce the input to an integer.
              - …
            - TableToFloatInput: Coerce the input to a float.
              - …
            - TableToBoolInput: Coerce the input to a boolean.
              - …
            - TableToDateInput: Coerce the input to a date.
              - …
            - TablePhoneE164Input: Normalize a phone number to E.164 format.
              - …
            - TableUtmParseInput: Extract a UTM parameter from a URL value.
              - …
            - TableUrlDomainInput: Reduce a URL to its bare registrable-looking host. A website field arrives as a whole URL (``https://www.acme.com/about``) but the thing that joins, dedupes and enriches is ``acme.com``. Doing it with ``regex_extract`` means every caller hand-writes the same fragile pattern, so the parse lives here once and uses a real URL parser.
              - …
            - TableCompanyDomainInput: Reduce a company's website URL to the company's own registrable domain. Three differences from ``url_domain``, which stays the generic read (a column of LinkedIn profile URLs legitimately reduces to ``linkedin.com`` there): Hosts that name a platform rather than the company (LinkedIn and Facebook pages, link aggregators, review sites, vendor partner directories) come out empty. A company whose only listed website is its LinkedIn page has no derivable domain, and an empty cell says so; ``linkedin.com`` is worse than empty because it joins, dedupes and syncs as if it were real. The result is the domain someone REGISTERED, not the bare host: a provider that lists ``careers.acme.com`` is describing ``acme.com``. A subdomain joins against nothing and sends an agent somewhere that often does not resolve. Page builders that give each customer their own label are the exception the Public Suffix List already encodes, so ``acme.wixsite.com`` survives whole rather than collapsing into ``wixsite.com``. ``company_name`` guards the case those two cannot: a directory listing reduces to the DIRECTORY owner's domain, so ``cloudpartners.transform.microsoft.com`` becomes ``microsoft.com``: right shape, wrong company, and nothing downstream can tell. Pointed at the column naming the employer, the domain is dropped when the two disagree. Optional: without it the other two rules still apply.
              - …
            - TableGetPathInput: Read a dotted path out of an object- or list-valued cell. Object and list columns were storable but unreadable: nothing in the catalog could reach a field inside one, so an enrichment payload landed in a cell and stopped there. Segments index dicts by key and lists by integer position: ``employees.count``, ``emails.0.address``. ``output_type`` is declared rather than derived because a JSON path can land on anything, and the column's data type has to be known before a single row is evaluated.
              - …
            - TableFormatInput: Build a string from a positional template and a list of arguments. ``concatenate`` joins whole columns with one separator, which cannot produce "Enterprise: Acme (12.4%)". Placeholders are positional only (``{0}``, ``{1}``) so the template stays data, not an expression language. Like ``concatenate`` this takes no ``source_column_id``: its inputs are its arguments, not the value flowing down the chain.
              - …
            - TableDateDiffInput: The signed duration between this step's date and another date. ``date_arithmetic`` shifts a date by a CONSTANT amount, so the gap between two date columns had no expression. Positive when the step's own date is the later of the two.
              - …
            - TableKeywordsInput: The most frequent meaningful words in a text or list value. Reads a body of text (a scraped page, a bio, a job description) and returns the words that carry its subject, ordered most frequent first. Stopwords ("the", "and", "with") are dropped: a frequency count that keeps them returns the same five words for every row and says nothing about any of them. Deterministic and pure: no model call, so a keyword column costs nothing and re-runs identically.
              - …
            - TableListFilterInput: Keep only the list items whose field passes a test. An enrichment payload lands as a list of objects (every job opening, every funding round, every contact) and the row usually wants a subset of it: the engineering roles, the rounds after 2024, the contacts with an email. Without this the whole list is the only thing a cell can hold. ``field`` is a dotted path INSIDE each item (``location.country``); leaving it empty tests the item itself, which is what a list of plain strings needs. ``exists``/``missing`` ignore ``value``: they ask only whether the field is there.
              - …
            - TableListSortInput: Order a list, ascending or descending. ``list_unique`` and ``list_join`` both preserve whatever order the source happened to arrive in, which is fine until the cell is meant to be READ: a top-3 of anything, a chronological history, an alphabetised tag list. ``field`` names the dotted path to sort objects BY; empty sorts the items themselves. Values that cannot be compared with each other (a number next to a string) are ordered by type first, so the sort is total instead of raising on the row where the data is mixed.
              - …
            - TableListIntersectInput: The values this list shares with another: the overlap, in the first list's order. The scoring question every ICP fit column asks: which of the buyer's tags, technologies or keywords are ALSO on my target list. Doing it by hand meant one ``if_then_else`` per tag. ``other`` is a column holding the second list, or literal text split on ``separator``. Matching ignores case and surrounding spaces, because the two lists come from different sources and "Shopify " never equals "shopify" when it matters most.
              - …
            - TableTextSimilarityInput: How alike two pieces of text are, as a percentage. The dedupe and match question: is "Acme Inc." the same company as "Acme, Inc"? An exact comparison says no and a human says obviously yes, so the honest answer is a number the row can threshold on. Case and surrounding whitespace never count: they are formatting, not difference. 100 means identical after that normalisation, 0 means nothing in common.
              - …
            - TableDetectLanguageInput: The language a piece of text is written in, as an ISO 639-1 code. Routes a row before anything expensive touches it: which sequence to enrol a lead into, which reviewer sees a scraped page, whether to translate at all. Script comes first (Cyrillic, Greek, Hebrew, Arabic, Han, kana and hangul each answer on their own) and Latin text is decided by the function words it uses. That is a heuristic, not a model: it is deterministic, free, and honest about not knowing, returning null when the text is too short or matches nothing.
              - …
            - TableScoreWordsInput: Score text by the weighted words it contains. The rules half of lead scoring, without a model: "enterprise" is worth 3, "student" is worth -5, and the cell adds up whatever the row's text, tags or tech stack actually say. Expressing the same thing with ``if_then_else`` needs one step per word and runs out of chain depth at ten. Weights are a plain object: word or phrase to number. Matching is case-insensitive; a multi-word key matches as a phrase. ``count_repeats`` decides whether saying "enterprise" three times scores three times, which is the difference between weighing a claim and weighing a page.
              - …
            - TableHashInput: Hash a value: the identifier ad platforms and clean rooms ask for. Uploading an audience means handing over hashed emails, never raw ones, and the hash has to be produced the way the platform specifies: lowercased and trimmed first, hex digest out. That normalisation is the part people get wrong by hand, so it happens here rather than in three chained steps.
              - …
            - TableUriEncodeInput: Percent-encode a value so it survives being put in a URL. Every search-URL column builds the same thing (a query string with a company name in it) and every one of them breaks on the first ampersand or accent. Encoding belongs one step before the URL is assembled, not in a regex chain that handles the four characters someone remembered. ``component`` escapes everything reserved, which is what a query value needs; ``full`` leaves ``:/?#`` alone so an entire URL stays usable. Lists are encoded item by item.
              - …
            - TableUrlValidInput: Whether a value is a usable web address. The gate in front of every scrape, screenshot and HTTP column: a row whose "website" cell holds "n/a", "coming soon" or a bare company name should never spend a credit finding that out. True means the value parses as a host with a real-looking domain, not that the site answers. A formula cannot make a request, and pretending otherwise would be the one dishonest thing this function could do.
              - …
            - TableEmailPermutationsInput: The candidate work-email addresses for a name at a domain. What a verifier needs to be pointed at: nine or so patterns companies actually use, in the order they are actually common, so the cheapest verification step has a list to work through instead of one guess. The piped value is the person's name: "Ada Lovelace", or a first name with ``last_name`` supplying the rest. Anything after the first and last token (middle names, suffixes) is ignored rather than permuted, which is what keeps the list nine long instead of ninety.
              - …
            - TableRoundRobinInput: Assign each row to one of a list of owners, evenly. Lead routing, as a column: the rep, the region, the sending inbox. The piped value is the row's IDENTITY (its email, domain or id) and the owner is derived from a hash of it rather than from the row's position. That is a deliberate departure from a counter-based round robin, and it is the only version that behaves: re-running the column, adding rows above, or sorting the view all leave every existing row with the owner it already had. A counter reassigns half the table the first time anything moves, which in a CRM means the wrong rep gets the follow-up.
              - …
            - TableWeightedRoundRobinInput: Assign each row to an owner, in proportion to each owner's share. The version real teams need: a senior rep takes three leads for every one a new hire gets, one region absorbs twice the volume of another. Shares are whole numbers and mean exactly what they look like: 3 and 1 is three quarters and one quarter. Stable per row for the same reason ``round_robin`` is: the owner comes from a hash of the row's identity, so nothing already assigned moves when the table grows or the view is sorted. Changing the SHARES does move rows, because that is what changing them means.
              - …
          - `source_column_id` string, uuid, nullable
          - `source_step` integer, nullable: Read the result of an EARLIER step, by 1-based position, instead of the step immediately before. Lets a later step fork back to an intermediate value (splitting a URL once and then using both the raw split and something derived from it), which a strict pipeline cannot express. Ignored when source_column_id is set (a column wins over a step), and ignored by functions that read their arguments rather than the piped value. None reads the previous step.
        - TableDateArithmeticInput: Add or subtract a fixed duration from a date value.
          - `amount` integer, required
          - `failure_mode` 'pass_through_raw' | 'set_null' | 'static' | 'skip': What a formula cell resolves to when a step in its chain fails. Applies to the whole chain, read off the top-level function only. ``SKIP`` is equivalent to ``SET_NULL`` for table cells (a cell always has a stored slot, so there is nothing to skip). Kept for shape compatibility.
          - `fallback_value` union
            - string
            - integer
            - number
            - boolean
          - `function` 'date_arithmetic'
          - `next` union
            - TableCopyInput: Copy the input value unchanged.
              - …
            - TableChangeCaseInput: Change the case of a string value.
              - …
            - TableTrimInput: Strip leading and trailing whitespace from a string value.
              - …
            - TableReplaceInput: Replace all occurrences of a substring.
              - …
            - TableRegexExtractInput: Extract a regex group from a string value.
              - …
            - TableRegexReplaceInput: Replace regex matches in a string value.
              - …
            - TableConcatenateInput: Join several values into one string. Sources are ORDERED and may mix columns with the results of earlier steps: ``[First name, step 2]`` and ``[step 2, First name]`` are different strings, which is why there is one list rather than a list of columns beside a list of steps. The field keeps its original name: every stored definition holds ``source_column_ids``, and the list is still overwhelmingly columns. Only the item type widened, so old definitions validate untouched.
              - …
            - TableArithmeticInput: Apply an arithmetic operator with a constant or column-valued operand.
              - …
            - TableRoundInput: Round a numeric value to a precision.
              - …
            - TableClampInput: Clamp a numeric value to an inclusive range.
              - …
            - TableDateFormatInput: Convert a date between iso/unix/unix_ms representations.
              - …
            - TableDateExtractInput: Extract a component (year, month, ...) from a date value.
              - …
            - TableDateArithmeticInput (recursive)
            - TableListFirstInput: Take the first element of a list value.
              - …
            - TableListLastInput: Take the last element of a list value.
              - …
            - TableListNthInput: Take the element at an index of a list value.
              - …
            - TableListJoinInput: Join list elements into a string with a separator.
              - …
            - TableListCountInput: Count the elements of a list value.
              - …
            - TableListPluckInput: Pull one field out of every object in a list. Enrichment payloads routinely carry lists of objects (``[{"value": "Payroll"}, {"value": "HR"}]``) where the useful thing is the field, not the wrapper. Plucking turns that into ``["Payroll", "HR"]`` so ``list_join`` and friends can work on it; items without the field become empty and scalar items pass through unchanged.
              - …
            - TableListUniqueInput: De-duplicate list elements, keeping first-seen order.
              - …
            - TableListSplitInput: Split a string value into a list on a separator.
              - …
            - TableCoalesceInput: Substitute a default (a literal or another column) when the input is empty.
              - …
            - TableIfThenElseInput: Pick one of two values based on a comparison. Each of the three slots takes a literal or a column, so this expresses both "if this column is over that column" and "use A, else use B". Neither of those was reachable while they were constants.
              - …
            - TableConditionsInput: Fold several comparisons into ONE boolean. The engine's only boolean combinator, and the shape a column's ``run_condition`` is authored in: "only run where Employees > 50 AND Country is US". Nothing else here joins predicates: ``if_then_else`` compares exactly one pair and returns a value rather than a verdict. So without this a multi-clause gate could only be reached by chaining steps that pipe a truthy stand-in forward, which no editor could read back. One joiner over clauses and, at most one level down, groups of clauses: "A and (B or C)". That is precisely the row filter's shape, so a view's filter can be saved as a gate and read back as a filter without loss; a deeper tree would be expressible on one side only. Reads its clauses' operands directly and ignores the piped input, so it is a leaf rather than a transform.
              - …
            - TableValueMappingInput: Map input values through a lookup table.
              - …
            - TableToStringInput: Coerce the input to a string.
              - …
            - TableToIntInput: Coerce the input to an integer.
              - …
            - TableToFloatInput: Coerce the input to a float.
              - …
            - TableToBoolInput: Coerce the input to a boolean.
              - …
            - TableToDateInput: Coerce the input to a date.
              - …
            - TablePhoneE164Input: Normalize a phone number to E.164 format.
              - …
            - TableUtmParseInput: Extract a UTM parameter from a URL value.
              - …
            - TableUrlDomainInput: Reduce a URL to its bare registrable-looking host. A website field arrives as a whole URL (``https://www.acme.com/about``) but the thing that joins, dedupes and enriches is ``acme.com``. Doing it with ``regex_extract`` means every caller hand-writes the same fragile pattern, so the parse lives here once and uses a real URL parser.
              - …
            - TableCompanyDomainInput: Reduce a company's website URL to the company's own registrable domain. Three differences from ``url_domain``, which stays the generic read (a column of LinkedIn profile URLs legitimately reduces to ``linkedin.com`` there): Hosts that name a platform rather than the company (LinkedIn and Facebook pages, link aggregators, review sites, vendor partner directories) come out empty. A company whose only listed website is its LinkedIn page has no derivable domain, and an empty cell says so; ``linkedin.com`` is worse than empty because it joins, dedupes and syncs as if it were real. The result is the domain someone REGISTERED, not the bare host: a provider that lists ``careers.acme.com`` is describing ``acme.com``. A subdomain joins against nothing and sends an agent somewhere that often does not resolve. Page builders that give each customer their own label are the exception the Public Suffix List already encodes, so ``acme.wixsite.com`` survives whole rather than collapsing into ``wixsite.com``. ``company_name`` guards the case those two cannot: a directory listing reduces to the DIRECTORY owner's domain, so ``cloudpartners.transform.microsoft.com`` becomes ``microsoft.com``: right shape, wrong company, and nothing downstream can tell. Pointed at the column naming the employer, the domain is dropped when the two disagree. Optional: without it the other two rules still apply.
              - …
            - TableGetPathInput: Read a dotted path out of an object- or list-valued cell. Object and list columns were storable but unreadable: nothing in the catalog could reach a field inside one, so an enrichment payload landed in a cell and stopped there. Segments index dicts by key and lists by integer position: ``employees.count``, ``emails.0.address``. ``output_type`` is declared rather than derived because a JSON path can land on anything, and the column's data type has to be known before a single row is evaluated.
              - …
            - TableFormatInput: Build a string from a positional template and a list of arguments. ``concatenate`` joins whole columns with one separator, which cannot produce "Enterprise: Acme (12.4%)". Placeholders are positional only (``{0}``, ``{1}``) so the template stays data, not an expression language. Like ``concatenate`` this takes no ``source_column_id``: its inputs are its arguments, not the value flowing down the chain.
              - …
            - TableDateDiffInput: The signed duration between this step's date and another date. ``date_arithmetic`` shifts a date by a CONSTANT amount, so the gap between two date columns had no expression. Positive when the step's own date is the later of the two.
              - …
            - TableKeywordsInput: The most frequent meaningful words in a text or list value. Reads a body of text (a scraped page, a bio, a job description) and returns the words that carry its subject, ordered most frequent first. Stopwords ("the", "and", "with") are dropped: a frequency count that keeps them returns the same five words for every row and says nothing about any of them. Deterministic and pure: no model call, so a keyword column costs nothing and re-runs identically.
              - …
            - TableListFilterInput: Keep only the list items whose field passes a test. An enrichment payload lands as a list of objects (every job opening, every funding round, every contact) and the row usually wants a subset of it: the engineering roles, the rounds after 2024, the contacts with an email. Without this the whole list is the only thing a cell can hold. ``field`` is a dotted path INSIDE each item (``location.country``); leaving it empty tests the item itself, which is what a list of plain strings needs. ``exists``/``missing`` ignore ``value``: they ask only whether the field is there.
              - …
            - TableListSortInput: Order a list, ascending or descending. ``list_unique`` and ``list_join`` both preserve whatever order the source happened to arrive in, which is fine until the cell is meant to be READ: a top-3 of anything, a chronological history, an alphabetised tag list. ``field`` names the dotted path to sort objects BY; empty sorts the items themselves. Values that cannot be compared with each other (a number next to a string) are ordered by type first, so the sort is total instead of raising on the row where the data is mixed.
              - …
            - TableListIntersectInput: The values this list shares with another: the overlap, in the first list's order. The scoring question every ICP fit column asks: which of the buyer's tags, technologies or keywords are ALSO on my target list. Doing it by hand meant one ``if_then_else`` per tag. ``other`` is a column holding the second list, or literal text split on ``separator``. Matching ignores case and surrounding spaces, because the two lists come from different sources and "Shopify " never equals "shopify" when it matters most.
              - …
            - TableTextSimilarityInput: How alike two pieces of text are, as a percentage. The dedupe and match question: is "Acme Inc." the same company as "Acme, Inc"? An exact comparison says no and a human says obviously yes, so the honest answer is a number the row can threshold on. Case and surrounding whitespace never count: they are formatting, not difference. 100 means identical after that normalisation, 0 means nothing in common.
              - …
            - TableDetectLanguageInput: The language a piece of text is written in, as an ISO 639-1 code. Routes a row before anything expensive touches it: which sequence to enrol a lead into, which reviewer sees a scraped page, whether to translate at all. Script comes first (Cyrillic, Greek, Hebrew, Arabic, Han, kana and hangul each answer on their own) and Latin text is decided by the function words it uses. That is a heuristic, not a model: it is deterministic, free, and honest about not knowing, returning null when the text is too short or matches nothing.
              - …
            - TableScoreWordsInput: Score text by the weighted words it contains. The rules half of lead scoring, without a model: "enterprise" is worth 3, "student" is worth -5, and the cell adds up whatever the row's text, tags or tech stack actually say. Expressing the same thing with ``if_then_else`` needs one step per word and runs out of chain depth at ten. Weights are a plain object: word or phrase to number. Matching is case-insensitive; a multi-word key matches as a phrase. ``count_repeats`` decides whether saying "enterprise" three times scores three times, which is the difference between weighing a claim and weighing a page.
              - …
            - TableHashInput: Hash a value: the identifier ad platforms and clean rooms ask for. Uploading an audience means handing over hashed emails, never raw ones, and the hash has to be produced the way the platform specifies: lowercased and trimmed first, hex digest out. That normalisation is the part people get wrong by hand, so it happens here rather than in three chained steps.
              - …
            - TableUriEncodeInput: Percent-encode a value so it survives being put in a URL. Every search-URL column builds the same thing (a query string with a company name in it) and every one of them breaks on the first ampersand or accent. Encoding belongs one step before the URL is assembled, not in a regex chain that handles the four characters someone remembered. ``component`` escapes everything reserved, which is what a query value needs; ``full`` leaves ``:/?#`` alone so an entire URL stays usable. Lists are encoded item by item.
              - …
            - TableUrlValidInput: Whether a value is a usable web address. The gate in front of every scrape, screenshot and HTTP column: a row whose "website" cell holds "n/a", "coming soon" or a bare company name should never spend a credit finding that out. True means the value parses as a host with a real-looking domain, not that the site answers. A formula cannot make a request, and pretending otherwise would be the one dishonest thing this function could do.
              - …
            - TableEmailPermutationsInput: The candidate work-email addresses for a name at a domain. What a verifier needs to be pointed at: nine or so patterns companies actually use, in the order they are actually common, so the cheapest verification step has a list to work through instead of one guess. The piped value is the person's name: "Ada Lovelace", or a first name with ``last_name`` supplying the rest. Anything after the first and last token (middle names, suffixes) is ignored rather than permuted, which is what keeps the list nine long instead of ninety.
              - …
            - TableRoundRobinInput: Assign each row to one of a list of owners, evenly. Lead routing, as a column: the rep, the region, the sending inbox. The piped value is the row's IDENTITY (its email, domain or id) and the owner is derived from a hash of it rather than from the row's position. That is a deliberate departure from a counter-based round robin, and it is the only version that behaves: re-running the column, adding rows above, or sorting the view all leave every existing row with the owner it already had. A counter reassigns half the table the first time anything moves, which in a CRM means the wrong rep gets the follow-up.
              - …
            - TableWeightedRoundRobinInput: Assign each row to an owner, in proportion to each owner's share. The version real teams need: a senior rep takes three leads for every one a new hire gets, one region absorbs twice the volume of another. Shares are whole numbers and mean exactly what they look like: 3 and 1 is three quarters and one quarter. Stable per row for the same reason ``round_robin`` is: the owner comes from a hash of the row's identity, so nothing already assigned moves when the table grows or the view is sorted. Changing the SHARES does move rows, because that is what changing them means.
              - …
          - `operator` 'add' | 'subtract', required
          - `source_column_id` string, uuid, nullable
          - `source_step` integer, nullable: Read the result of an EARLIER step, by 1-based position, instead of the step immediately before. Lets a later step fork back to an intermediate value (splitting a URL once and then using both the raw split and something derived from it), which a strict pipeline cannot express. Ignored when source_column_id is set (a column wins over a step), and ignored by functions that read their arguments rather than the piped value. None reads the previous step.
          - `unit` 'days' | 'hours' | 'minutes' | 'seconds', required
        - TableListFirstInput: Take the first element of a list value.
          - `failure_mode` 'pass_through_raw' | 'set_null' | 'static' | 'skip': What a formula cell resolves to when a step in its chain fails. Applies to the whole chain, read off the top-level function only. ``SKIP`` is equivalent to ``SET_NULL`` for table cells (a cell always has a stored slot, so there is nothing to skip). Kept for shape compatibility.
          - `fallback_value` union
            - string
            - integer
            - number
            - boolean
          - `function` 'list_first'
          - `next` union
            - TableCopyInput: Copy the input value unchanged.
              - …
            - TableChangeCaseInput: Change the case of a string value.
              - …
            - TableTrimInput: Strip leading and trailing whitespace from a string value.
              - …
            - TableReplaceInput: Replace all occurrences of a substring.
              - …
            - TableRegexExtractInput: Extract a regex group from a string value.
              - …
            - TableRegexReplaceInput: Replace regex matches in a string value.
              - …
            - TableConcatenateInput: Join several values into one string. Sources are ORDERED and may mix columns with the results of earlier steps: ``[First name, step 2]`` and ``[step 2, First name]`` are different strings, which is why there is one list rather than a list of columns beside a list of steps. The field keeps its original name: every stored definition holds ``source_column_ids``, and the list is still overwhelmingly columns. Only the item type widened, so old definitions validate untouched.
              - …
            - TableArithmeticInput: Apply an arithmetic operator with a constant or column-valued operand.
              - …
            - TableRoundInput: Round a numeric value to a precision.
              - …
            - TableClampInput: Clamp a numeric value to an inclusive range.
              - …
            - TableDateFormatInput: Convert a date between iso/unix/unix_ms representations.
              - …
            - TableDateExtractInput: Extract a component (year, month, ...) from a date value.
              - …
            - TableDateArithmeticInput: Add or subtract a fixed duration from a date value.
              - …
            - TableListFirstInput (recursive)
            - TableListLastInput: Take the last element of a list value.
              - …
            - TableListNthInput: Take the element at an index of a list value.
              - …
            - TableListJoinInput: Join list elements into a string with a separator.
              - …
            - TableListCountInput: Count the elements of a list value.
              - …
            - TableListPluckInput: Pull one field out of every object in a list. Enrichment payloads routinely carry lists of objects (``[{"value": "Payroll"}, {"value": "HR"}]``) where the useful thing is the field, not the wrapper. Plucking turns that into ``["Payroll", "HR"]`` so ``list_join`` and friends can work on it; items without the field become empty and scalar items pass through unchanged.
              - …
            - TableListUniqueInput: De-duplicate list elements, keeping first-seen order.
              - …
            - TableListSplitInput: Split a string value into a list on a separator.
              - …
            - TableCoalesceInput: Substitute a default (a literal or another column) when the input is empty.
              - …
            - TableIfThenElseInput: Pick one of two values based on a comparison. Each of the three slots takes a literal or a column, so this expresses both "if this column is over that column" and "use A, else use B". Neither of those was reachable while they were constants.
              - …
            - TableConditionsInput: Fold several comparisons into ONE boolean. The engine's only boolean combinator, and the shape a column's ``run_condition`` is authored in: "only run where Employees > 50 AND Country is US". Nothing else here joins predicates: ``if_then_else`` compares exactly one pair and returns a value rather than a verdict. So without this a multi-clause gate could only be reached by chaining steps that pipe a truthy stand-in forward, which no editor could read back. One joiner over clauses and, at most one level down, groups of clauses: "A and (B or C)". That is precisely the row filter's shape, so a view's filter can be saved as a gate and read back as a filter without loss; a deeper tree would be expressible on one side only. Reads its clauses' operands directly and ignores the piped input, so it is a leaf rather than a transform.
              - …
            - TableValueMappingInput: Map input values through a lookup table.
              - …
            - TableToStringInput: Coerce the input to a string.
              - …
            - TableToIntInput: Coerce the input to an integer.
              - …
            - TableToFloatInput: Coerce the input to a float.
              - …
            - TableToBoolInput: Coerce the input to a boolean.
              - …
            - TableToDateInput: Coerce the input to a date.
              - …
            - TablePhoneE164Input: Normalize a phone number to E.164 format.
              - …
            - TableUtmParseInput: Extract a UTM parameter from a URL value.
              - …
            - TableUrlDomainInput: Reduce a URL to its bare registrable-looking host. A website field arrives as a whole URL (``https://www.acme.com/about``) but the thing that joins, dedupes and enriches is ``acme.com``. Doing it with ``regex_extract`` means every caller hand-writes the same fragile pattern, so the parse lives here once and uses a real URL parser.
              - …
            - TableCompanyDomainInput: Reduce a company's website URL to the company's own registrable domain. Three differences from ``url_domain``, which stays the generic read (a column of LinkedIn profile URLs legitimately reduces to ``linkedin.com`` there): Hosts that name a platform rather than the company (LinkedIn and Facebook pages, link aggregators, review sites, vendor partner directories) come out empty. A company whose only listed website is its LinkedIn page has no derivable domain, and an empty cell says so; ``linkedin.com`` is worse than empty because it joins, dedupes and syncs as if it were real. The result is the domain someone REGISTERED, not the bare host: a provider that lists ``careers.acme.com`` is describing ``acme.com``. A subdomain joins against nothing and sends an agent somewhere that often does not resolve. Page builders that give each customer their own label are the exception the Public Suffix List already encodes, so ``acme.wixsite.com`` survives whole rather than collapsing into ``wixsite.com``. ``company_name`` guards the case those two cannot: a directory listing reduces to the DIRECTORY owner's domain, so ``cloudpartners.transform.microsoft.com`` becomes ``microsoft.com``: right shape, wrong company, and nothing downstream can tell. Pointed at the column naming the employer, the domain is dropped when the two disagree. Optional: without it the other two rules still apply.
              - …
            - TableGetPathInput: Read a dotted path out of an object- or list-valued cell. Object and list columns were storable but unreadable: nothing in the catalog could reach a field inside one, so an enrichment payload landed in a cell and stopped there. Segments index dicts by key and lists by integer position: ``employees.count``, ``emails.0.address``. ``output_type`` is declared rather than derived because a JSON path can land on anything, and the column's data type has to be known before a single row is evaluated.
              - …
            - TableFormatInput: Build a string from a positional template and a list of arguments. ``concatenate`` joins whole columns with one separator, which cannot produce "Enterprise: Acme (12.4%)". Placeholders are positional only (``{0}``, ``{1}``) so the template stays data, not an expression language. Like ``concatenate`` this takes no ``source_column_id``: its inputs are its arguments, not the value flowing down the chain.
              - …
            - TableDateDiffInput: The signed duration between this step's date and another date. ``date_arithmetic`` shifts a date by a CONSTANT amount, so the gap between two date columns had no expression. Positive when the step's own date is the later of the two.
              - …
            - TableKeywordsInput: The most frequent meaningful words in a text or list value. Reads a body of text (a scraped page, a bio, a job description) and returns the words that carry its subject, ordered most frequent first. Stopwords ("the", "and", "with") are dropped: a frequency count that keeps them returns the same five words for every row and says nothing about any of them. Deterministic and pure: no model call, so a keyword column costs nothing and re-runs identically.
              - …
            - TableListFilterInput: Keep only the list items whose field passes a test. An enrichment payload lands as a list of objects (every job opening, every funding round, every contact) and the row usually wants a subset of it: the engineering roles, the rounds after 2024, the contacts with an email. Without this the whole list is the only thing a cell can hold. ``field`` is a dotted path INSIDE each item (``location.country``); leaving it empty tests the item itself, which is what a list of plain strings needs. ``exists``/``missing`` ignore ``value``: they ask only whether the field is there.
              - …
            - TableListSortInput: Order a list, ascending or descending. ``list_unique`` and ``list_join`` both preserve whatever order the source happened to arrive in, which is fine until the cell is meant to be READ: a top-3 of anything, a chronological history, an alphabetised tag list. ``field`` names the dotted path to sort objects BY; empty sorts the items themselves. Values that cannot be compared with each other (a number next to a string) are ordered by type first, so the sort is total instead of raising on the row where the data is mixed.
              - …
            - TableListIntersectInput: The values this list shares with another: the overlap, in the first list's order. The scoring question every ICP fit column asks: which of the buyer's tags, technologies or keywords are ALSO on my target list. Doing it by hand meant one ``if_then_else`` per tag. ``other`` is a column holding the second list, or literal text split on ``separator``. Matching ignores case and surrounding spaces, because the two lists come from different sources and "Shopify " never equals "shopify" when it matters most.
              - …
            - TableTextSimilarityInput: How alike two pieces of text are, as a percentage. The dedupe and match question: is "Acme Inc." the same company as "Acme, Inc"? An exact comparison says no and a human says obviously yes, so the honest answer is a number the row can threshold on. Case and surrounding whitespace never count: they are formatting, not difference. 100 means identical after that normalisation, 0 means nothing in common.
              - …
            - TableDetectLanguageInput: The language a piece of text is written in, as an ISO 639-1 code. Routes a row before anything expensive touches it: which sequence to enrol a lead into, which reviewer sees a scraped page, whether to translate at all. Script comes first (Cyrillic, Greek, Hebrew, Arabic, Han, kana and hangul each answer on their own) and Latin text is decided by the function words it uses. That is a heuristic, not a model: it is deterministic, free, and honest about not knowing, returning null when the text is too short or matches nothing.
              - …
            - TableScoreWordsInput: Score text by the weighted words it contains. The rules half of lead scoring, without a model: "enterprise" is worth 3, "student" is worth -5, and the cell adds up whatever the row's text, tags or tech stack actually say. Expressing the same thing with ``if_then_else`` needs one step per word and runs out of chain depth at ten. Weights are a plain object: word or phrase to number. Matching is case-insensitive; a multi-word key matches as a phrase. ``count_repeats`` decides whether saying "enterprise" three times scores three times, which is the difference between weighing a claim and weighing a page.
              - …
            - TableHashInput: Hash a value: the identifier ad platforms and clean rooms ask for. Uploading an audience means handing over hashed emails, never raw ones, and the hash has to be produced the way the platform specifies: lowercased and trimmed first, hex digest out. That normalisation is the part people get wrong by hand, so it happens here rather than in three chained steps.
              - …
            - TableUriEncodeInput: Percent-encode a value so it survives being put in a URL. Every search-URL column builds the same thing (a query string with a company name in it) and every one of them breaks on the first ampersand or accent. Encoding belongs one step before the URL is assembled, not in a regex chain that handles the four characters someone remembered. ``component`` escapes everything reserved, which is what a query value needs; ``full`` leaves ``:/?#`` alone so an entire URL stays usable. Lists are encoded item by item.
              - …
            - TableUrlValidInput: Whether a value is a usable web address. The gate in front of every scrape, screenshot and HTTP column: a row whose "website" cell holds "n/a", "coming soon" or a bare company name should never spend a credit finding that out. True means the value parses as a host with a real-looking domain, not that the site answers. A formula cannot make a request, and pretending otherwise would be the one dishonest thing this function could do.
              - …
            - TableEmailPermutationsInput: The candidate work-email addresses for a name at a domain. What a verifier needs to be pointed at: nine or so patterns companies actually use, in the order they are actually common, so the cheapest verification step has a list to work through instead of one guess. The piped value is the person's name: "Ada Lovelace", or a first name with ``last_name`` supplying the rest. Anything after the first and last token (middle names, suffixes) is ignored rather than permuted, which is what keeps the list nine long instead of ninety.
              - …
            - TableRoundRobinInput: Assign each row to one of a list of owners, evenly. Lead routing, as a column: the rep, the region, the sending inbox. The piped value is the row's IDENTITY (its email, domain or id) and the owner is derived from a hash of it rather than from the row's position. That is a deliberate departure from a counter-based round robin, and it is the only version that behaves: re-running the column, adding rows above, or sorting the view all leave every existing row with the owner it already had. A counter reassigns half the table the first time anything moves, which in a CRM means the wrong rep gets the follow-up.
              - …
            - TableWeightedRoundRobinInput: Assign each row to an owner, in proportion to each owner's share. The version real teams need: a senior rep takes three leads for every one a new hire gets, one region absorbs twice the volume of another. Shares are whole numbers and mean exactly what they look like: 3 and 1 is three quarters and one quarter. Stable per row for the same reason ``round_robin`` is: the owner comes from a hash of the row's identity, so nothing already assigned moves when the table grows or the view is sorted. Changing the SHARES does move rows, because that is what changing them means.
              - …
          - `source_column_id` string, uuid, nullable
          - `source_step` integer, nullable: Read the result of an EARLIER step, by 1-based position, instead of the step immediately before. Lets a later step fork back to an intermediate value (splitting a URL once and then using both the raw split and something derived from it), which a strict pipeline cannot express. Ignored when source_column_id is set (a column wins over a step), and ignored by functions that read their arguments rather than the piped value. None reads the previous step.
        - TableListLastInput: Take the last element of a list value.
          - `failure_mode` 'pass_through_raw' | 'set_null' | 'static' | 'skip': What a formula cell resolves to when a step in its chain fails. Applies to the whole chain, read off the top-level function only. ``SKIP`` is equivalent to ``SET_NULL`` for table cells (a cell always has a stored slot, so there is nothing to skip). Kept for shape compatibility.
          - `fallback_value` union
            - string
            - integer
            - number
            - boolean
          - `function` 'list_last'
          - `next` union
            - TableCopyInput: Copy the input value unchanged.
              - …
            - TableChangeCaseInput: Change the case of a string value.
              - …
            - TableTrimInput: Strip leading and trailing whitespace from a string value.
              - …
            - TableReplaceInput: Replace all occurrences of a substring.
              - …
            - TableRegexExtractInput: Extract a regex group from a string value.
              - …
            - TableRegexReplaceInput: Replace regex matches in a string value.
              - …
            - TableConcatenateInput: Join several values into one string. Sources are ORDERED and may mix columns with the results of earlier steps: ``[First name, step 2]`` and ``[step 2, First name]`` are different strings, which is why there is one list rather than a list of columns beside a list of steps. The field keeps its original name: every stored definition holds ``source_column_ids``, and the list is still overwhelmingly columns. Only the item type widened, so old definitions validate untouched.
              - …
            - TableArithmeticInput: Apply an arithmetic operator with a constant or column-valued operand.
              - …
            - TableRoundInput: Round a numeric value to a precision.
              - …
            - TableClampInput: Clamp a numeric value to an inclusive range.
              - …
            - TableDateFormatInput: Convert a date between iso/unix/unix_ms representations.
              - …
            - TableDateExtractInput: Extract a component (year, month, ...) from a date value.
              - …
            - TableDateArithmeticInput: Add or subtract a fixed duration from a date value.
              - …
            - TableListFirstInput: Take the first element of a list value.
              - …
            - TableListLastInput (recursive)
            - TableListNthInput: Take the element at an index of a list value.
              - …
            - TableListJoinInput: Join list elements into a string with a separator.
              - …
            - TableListCountInput: Count the elements of a list value.
              - …
            - TableListPluckInput: Pull one field out of every object in a list. Enrichment payloads routinely carry lists of objects (``[{"value": "Payroll"}, {"value": "HR"}]``) where the useful thing is the field, not the wrapper. Plucking turns that into ``["Payroll", "HR"]`` so ``list_join`` and friends can work on it; items without the field become empty and scalar items pass through unchanged.
              - …
            - TableListUniqueInput: De-duplicate list elements, keeping first-seen order.
              - …
            - TableListSplitInput: Split a string value into a list on a separator.
              - …
            - TableCoalesceInput: Substitute a default (a literal or another column) when the input is empty.
              - …
            - TableIfThenElseInput: Pick one of two values based on a comparison. Each of the three slots takes a literal or a column, so this expresses both "if this column is over that column" and "use A, else use B". Neither of those was reachable while they were constants.
              - …
            - TableConditionsInput: Fold several comparisons into ONE boolean. The engine's only boolean combinator, and the shape a column's ``run_condition`` is authored in: "only run where Employees > 50 AND Country is US". Nothing else here joins predicates: ``if_then_else`` compares exactly one pair and returns a value rather than a verdict. So without this a multi-clause gate could only be reached by chaining steps that pipe a truthy stand-in forward, which no editor could read back. One joiner over clauses and, at most one level down, groups of clauses: "A and (B or C)". That is precisely the row filter's shape, so a view's filter can be saved as a gate and read back as a filter without loss; a deeper tree would be expressible on one side only. Reads its clauses' operands directly and ignores the piped input, so it is a leaf rather than a transform.
              - …
            - TableValueMappingInput: Map input values through a lookup table.
              - …
            - TableToStringInput: Coerce the input to a string.
              - …
            - TableToIntInput: Coerce the input to an integer.
              - …
            - TableToFloatInput: Coerce the input to a float.
              - …
            - TableToBoolInput: Coerce the input to a boolean.
              - …
            - TableToDateInput: Coerce the input to a date.
              - …
            - TablePhoneE164Input: Normalize a phone number to E.164 format.
              - …
            - TableUtmParseInput: Extract a UTM parameter from a URL value.
              - …
            - TableUrlDomainInput: Reduce a URL to its bare registrable-looking host. A website field arrives as a whole URL (``https://www.acme.com/about``) but the thing that joins, dedupes and enriches is ``acme.com``. Doing it with ``regex_extract`` means every caller hand-writes the same fragile pattern, so the parse lives here once and uses a real URL parser.
              - …
            - TableCompanyDomainInput: Reduce a company's website URL to the company's own registrable domain. Three differences from ``url_domain``, which stays the generic read (a column of LinkedIn profile URLs legitimately reduces to ``linkedin.com`` there): Hosts that name a platform rather than the company (LinkedIn and Facebook pages, link aggregators, review sites, vendor partner directories) come out empty. A company whose only listed website is its LinkedIn page has no derivable domain, and an empty cell says so; ``linkedin.com`` is worse than empty because it joins, dedupes and syncs as if it were real. The result is the domain someone REGISTERED, not the bare host: a provider that lists ``careers.acme.com`` is describing ``acme.com``. A subdomain joins against nothing and sends an agent somewhere that often does not resolve. Page builders that give each customer their own label are the exception the Public Suffix List already encodes, so ``acme.wixsite.com`` survives whole rather than collapsing into ``wixsite.com``. ``company_name`` guards the case those two cannot: a directory listing reduces to the DIRECTORY owner's domain, so ``cloudpartners.transform.microsoft.com`` becomes ``microsoft.com``: right shape, wrong company, and nothing downstream can tell. Pointed at the column naming the employer, the domain is dropped when the two disagree. Optional: without it the other two rules still apply.
              - …
            - TableGetPathInput: Read a dotted path out of an object- or list-valued cell. Object and list columns were storable but unreadable: nothing in the catalog could reach a field inside one, so an enrichment payload landed in a cell and stopped there. Segments index dicts by key and lists by integer position: ``employees.count``, ``emails.0.address``. ``output_type`` is declared rather than derived because a JSON path can land on anything, and the column's data type has to be known before a single row is evaluated.
              - …
            - TableFormatInput: Build a string from a positional template and a list of arguments. ``concatenate`` joins whole columns with one separator, which cannot produce "Enterprise: Acme (12.4%)". Placeholders are positional only (``{0}``, ``{1}``) so the template stays data, not an expression language. Like ``concatenate`` this takes no ``source_column_id``: its inputs are its arguments, not the value flowing down the chain.
              - …
            - TableDateDiffInput: The signed duration between this step's date and another date. ``date_arithmetic`` shifts a date by a CONSTANT amount, so the gap between two date columns had no expression. Positive when the step's own date is the later of the two.
              - …
            - TableKeywordsInput: The most frequent meaningful words in a text or list value. Reads a body of text (a scraped page, a bio, a job description) and returns the words that carry its subject, ordered most frequent first. Stopwords ("the", "and", "with") are dropped: a frequency count that keeps them returns the same five words for every row and says nothing about any of them. Deterministic and pure: no model call, so a keyword column costs nothing and re-runs identically.
              - …
            - TableListFilterInput: Keep only the list items whose field passes a test. An enrichment payload lands as a list of objects (every job opening, every funding round, every contact) and the row usually wants a subset of it: the engineering roles, the rounds after 2024, the contacts with an email. Without this the whole list is the only thing a cell can hold. ``field`` is a dotted path INSIDE each item (``location.country``); leaving it empty tests the item itself, which is what a list of plain strings needs. ``exists``/``missing`` ignore ``value``: they ask only whether the field is there.
              - …
            - TableListSortInput: Order a list, ascending or descending. ``list_unique`` and ``list_join`` both preserve whatever order the source happened to arrive in, which is fine until the cell is meant to be READ: a top-3 of anything, a chronological history, an alphabetised tag list. ``field`` names the dotted path to sort objects BY; empty sorts the items themselves. Values that cannot be compared with each other (a number next to a string) are ordered by type first, so the sort is total instead of raising on the row where the data is mixed.
              - …
            - TableListIntersectInput: The values this list shares with another: the overlap, in the first list's order. The scoring question every ICP fit column asks: which of the buyer's tags, technologies or keywords are ALSO on my target list. Doing it by hand meant one ``if_then_else`` per tag. ``other`` is a column holding the second list, or literal text split on ``separator``. Matching ignores case and surrounding spaces, because the two lists come from different sources and "Shopify " never equals "shopify" when it matters most.
              - …
            - TableTextSimilarityInput: How alike two pieces of text are, as a percentage. The dedupe and match question: is "Acme Inc." the same company as "Acme, Inc"? An exact comparison says no and a human says obviously yes, so the honest answer is a number the row can threshold on. Case and surrounding whitespace never count: they are formatting, not difference. 100 means identical after that normalisation, 0 means nothing in common.
              - …
            - TableDetectLanguageInput: The language a piece of text is written in, as an ISO 639-1 code. Routes a row before anything expensive touches it: which sequence to enrol a lead into, which reviewer sees a scraped page, whether to translate at all. Script comes first (Cyrillic, Greek, Hebrew, Arabic, Han, kana and hangul each answer on their own) and Latin text is decided by the function words it uses. That is a heuristic, not a model: it is deterministic, free, and honest about not knowing, returning null when the text is too short or matches nothing.
              - …
            - TableScoreWordsInput: Score text by the weighted words it contains. The rules half of lead scoring, without a model: "enterprise" is worth 3, "student" is worth -5, and the cell adds up whatever the row's text, tags or tech stack actually say. Expressing the same thing with ``if_then_else`` needs one step per word and runs out of chain depth at ten. Weights are a plain object: word or phrase to number. Matching is case-insensitive; a multi-word key matches as a phrase. ``count_repeats`` decides whether saying "enterprise" three times scores three times, which is the difference between weighing a claim and weighing a page.
              - …
            - TableHashInput: Hash a value: the identifier ad platforms and clean rooms ask for. Uploading an audience means handing over hashed emails, never raw ones, and the hash has to be produced the way the platform specifies: lowercased and trimmed first, hex digest out. That normalisation is the part people get wrong by hand, so it happens here rather than in three chained steps.
              - …
            - TableUriEncodeInput: Percent-encode a value so it survives being put in a URL. Every search-URL column builds the same thing (a query string with a company name in it) and every one of them breaks on the first ampersand or accent. Encoding belongs one step before the URL is assembled, not in a regex chain that handles the four characters someone remembered. ``component`` escapes everything reserved, which is what a query value needs; ``full`` leaves ``:/?#`` alone so an entire URL stays usable. Lists are encoded item by item.
              - …
            - TableUrlValidInput: Whether a value is a usable web address. The gate in front of every scrape, screenshot and HTTP column: a row whose "website" cell holds "n/a", "coming soon" or a bare company name should never spend a credit finding that out. True means the value parses as a host with a real-looking domain, not that the site answers. A formula cannot make a request, and pretending otherwise would be the one dishonest thing this function could do.
              - …
            - TableEmailPermutationsInput: The candidate work-email addresses for a name at a domain. What a verifier needs to be pointed at: nine or so patterns companies actually use, in the order they are actually common, so the cheapest verification step has a list to work through instead of one guess. The piped value is the person's name: "Ada Lovelace", or a first name with ``last_name`` supplying the rest. Anything after the first and last token (middle names, suffixes) is ignored rather than permuted, which is what keeps the list nine long instead of ninety.
              - …
            - TableRoundRobinInput: Assign each row to one of a list of owners, evenly. Lead routing, as a column: the rep, the region, the sending inbox. The piped value is the row's IDENTITY (its email, domain or id) and the owner is derived from a hash of it rather than from the row's position. That is a deliberate departure from a counter-based round robin, and it is the only version that behaves: re-running the column, adding rows above, or sorting the view all leave every existing row with the owner it already had. A counter reassigns half the table the first time anything moves, which in a CRM means the wrong rep gets the follow-up.
              - …
            - TableWeightedRoundRobinInput: Assign each row to an owner, in proportion to each owner's share. The version real teams need: a senior rep takes three leads for every one a new hire gets, one region absorbs twice the volume of another. Shares are whole numbers and mean exactly what they look like: 3 and 1 is three quarters and one quarter. Stable per row for the same reason ``round_robin`` is: the owner comes from a hash of the row's identity, so nothing already assigned moves when the table grows or the view is sorted. Changing the SHARES does move rows, because that is what changing them means.
              - …
          - `source_column_id` string, uuid, nullable
          - `source_step` integer, nullable: Read the result of an EARLIER step, by 1-based position, instead of the step immediately before. Lets a later step fork back to an intermediate value (splitting a URL once and then using both the raw split and something derived from it), which a strict pipeline cannot express. Ignored when source_column_id is set (a column wins over a step), and ignored by functions that read their arguments rather than the piped value. None reads the previous step.
        - TableListNthInput: Take the element at an index of a list value.
          - `failure_mode` 'pass_through_raw' | 'set_null' | 'static' | 'skip': What a formula cell resolves to when a step in its chain fails. Applies to the whole chain, read off the top-level function only. ``SKIP`` is equivalent to ``SET_NULL`` for table cells (a cell always has a stored slot, so there is nothing to skip). Kept for shape compatibility.
          - `fallback_value` union
            - string
            - integer
            - number
            - boolean
          - `function` 'list_nth'
          - `index` integer
          - `next` union
            - TableCopyInput: Copy the input value unchanged.
              - …
            - TableChangeCaseInput: Change the case of a string value.
              - …
            - TableTrimInput: Strip leading and trailing whitespace from a string value.
              - …
            - TableReplaceInput: Replace all occurrences of a substring.
              - …
            - TableRegexExtractInput: Extract a regex group from a string value.
              - …
            - TableRegexReplaceInput: Replace regex matches in a string value.
              - …
            - TableConcatenateInput: Join several values into one string. Sources are ORDERED and may mix columns with the results of earlier steps: ``[First name, step 2]`` and ``[step 2, First name]`` are different strings, which is why there is one list rather than a list of columns beside a list of steps. The field keeps its original name: every stored definition holds ``source_column_ids``, and the list is still overwhelmingly columns. Only the item type widened, so old definitions validate untouched.
              - …
            - TableArithmeticInput: Apply an arithmetic operator with a constant or column-valued operand.
              - …
            - TableRoundInput: Round a numeric value to a precision.
              - …
            - TableClampInput: Clamp a numeric value to an inclusive range.
              - …
            - TableDateFormatInput: Convert a date between iso/unix/unix_ms representations.
              - …
            - TableDateExtractInput: Extract a component (year, month, ...) from a date value.
              - …
            - TableDateArithmeticInput: Add or subtract a fixed duration from a date value.
              - …
            - TableListFirstInput: Take the first element of a list value.
              - …
            - TableListLastInput: Take the last element of a list value.
              - …
            - TableListNthInput (recursive)
            - TableListJoinInput: Join list elements into a string with a separator.
              - …
            - TableListCountInput: Count the elements of a list value.
              - …
            - TableListPluckInput: Pull one field out of every object in a list. Enrichment payloads routinely carry lists of objects (``[{"value": "Payroll"}, {"value": "HR"}]``) where the useful thing is the field, not the wrapper. Plucking turns that into ``["Payroll", "HR"]`` so ``list_join`` and friends can work on it; items without the field become empty and scalar items pass through unchanged.
              - …
            - TableListUniqueInput: De-duplicate list elements, keeping first-seen order.
              - …
            - TableListSplitInput: Split a string value into a list on a separator.
              - …
            - TableCoalesceInput: Substitute a default (a literal or another column) when the input is empty.
              - …
            - TableIfThenElseInput: Pick one of two values based on a comparison. Each of the three slots takes a literal or a column, so this expresses both "if this column is over that column" and "use A, else use B". Neither of those was reachable while they were constants.
              - …
            - TableConditionsInput: Fold several comparisons into ONE boolean. The engine's only boolean combinator, and the shape a column's ``run_condition`` is authored in: "only run where Employees > 50 AND Country is US". Nothing else here joins predicates: ``if_then_else`` compares exactly one pair and returns a value rather than a verdict. So without this a multi-clause gate could only be reached by chaining steps that pipe a truthy stand-in forward, which no editor could read back. One joiner over clauses and, at most one level down, groups of clauses: "A and (B or C)". That is precisely the row filter's shape, so a view's filter can be saved as a gate and read back as a filter without loss; a deeper tree would be expressible on one side only. Reads its clauses' operands directly and ignores the piped input, so it is a leaf rather than a transform.
              - …
            - TableValueMappingInput: Map input values through a lookup table.
              - …
            - TableToStringInput: Coerce the input to a string.
              - …
            - TableToIntInput: Coerce the input to an integer.
              - …
            - TableToFloatInput: Coerce the input to a float.
              - …
            - TableToBoolInput: Coerce the input to a boolean.
              - …
            - TableToDateInput: Coerce the input to a date.
              - …
            - TablePhoneE164Input: Normalize a phone number to E.164 format.
              - …
            - TableUtmParseInput: Extract a UTM parameter from a URL value.
              - …
            - TableUrlDomainInput: Reduce a URL to its bare registrable-looking host. A website field arrives as a whole URL (``https://www.acme.com/about``) but the thing that joins, dedupes and enriches is ``acme.com``. Doing it with ``regex_extract`` means every caller hand-writes the same fragile pattern, so the parse lives here once and uses a real URL parser.
              - …
            - TableCompanyDomainInput: Reduce a company's website URL to the company's own registrable domain. Three differences from ``url_domain``, which stays the generic read (a column of LinkedIn profile URLs legitimately reduces to ``linkedin.com`` there): Hosts that name a platform rather than the company (LinkedIn and Facebook pages, link aggregators, review sites, vendor partner directories) come out empty. A company whose only listed website is its LinkedIn page has no derivable domain, and an empty cell says so; ``linkedin.com`` is worse than empty because it joins, dedupes and syncs as if it were real. The result is the domain someone REGISTERED, not the bare host: a provider that lists ``careers.acme.com`` is describing ``acme.com``. A subdomain joins against nothing and sends an agent somewhere that often does not resolve. Page builders that give each customer their own label are the exception the Public Suffix List already encodes, so ``acme.wixsite.com`` survives whole rather than collapsing into ``wixsite.com``. ``company_name`` guards the case those two cannot: a directory listing reduces to the DIRECTORY owner's domain, so ``cloudpartners.transform.microsoft.com`` becomes ``microsoft.com``: right shape, wrong company, and nothing downstream can tell. Pointed at the column naming the employer, the domain is dropped when the two disagree. Optional: without it the other two rules still apply.
              - …
            - TableGetPathInput: Read a dotted path out of an object- or list-valued cell. Object and list columns were storable but unreadable: nothing in the catalog could reach a field inside one, so an enrichment payload landed in a cell and stopped there. Segments index dicts by key and lists by integer position: ``employees.count``, ``emails.0.address``. ``output_type`` is declared rather than derived because a JSON path can land on anything, and the column's data type has to be known before a single row is evaluated.
              - …
            - TableFormatInput: Build a string from a positional template and a list of arguments. ``concatenate`` joins whole columns with one separator, which cannot produce "Enterprise: Acme (12.4%)". Placeholders are positional only (``{0}``, ``{1}``) so the template stays data, not an expression language. Like ``concatenate`` this takes no ``source_column_id``: its inputs are its arguments, not the value flowing down the chain.
              - …
            - TableDateDiffInput: The signed duration between this step's date and another date. ``date_arithmetic`` shifts a date by a CONSTANT amount, so the gap between two date columns had no expression. Positive when the step's own date is the later of the two.
              - …
            - TableKeywordsInput: The most frequent meaningful words in a text or list value. Reads a body of text (a scraped page, a bio, a job description) and returns the words that carry its subject, ordered most frequent first. Stopwords ("the", "and", "with") are dropped: a frequency count that keeps them returns the same five words for every row and says nothing about any of them. Deterministic and pure: no model call, so a keyword column costs nothing and re-runs identically.
              - …
            - TableListFilterInput: Keep only the list items whose field passes a test. An enrichment payload lands as a list of objects (every job opening, every funding round, every contact) and the row usually wants a subset of it: the engineering roles, the rounds after 2024, the contacts with an email. Without this the whole list is the only thing a cell can hold. ``field`` is a dotted path INSIDE each item (``location.country``); leaving it empty tests the item itself, which is what a list of plain strings needs. ``exists``/``missing`` ignore ``value``: they ask only whether the field is there.
              - …
            - TableListSortInput: Order a list, ascending or descending. ``list_unique`` and ``list_join`` both preserve whatever order the source happened to arrive in, which is fine until the cell is meant to be READ: a top-3 of anything, a chronological history, an alphabetised tag list. ``field`` names the dotted path to sort objects BY; empty sorts the items themselves. Values that cannot be compared with each other (a number next to a string) are ordered by type first, so the sort is total instead of raising on the row where the data is mixed.
              - …
            - TableListIntersectInput: The values this list shares with another: the overlap, in the first list's order. The scoring question every ICP fit column asks: which of the buyer's tags, technologies or keywords are ALSO on my target list. Doing it by hand meant one ``if_then_else`` per tag. ``other`` is a column holding the second list, or literal text split on ``separator``. Matching ignores case and surrounding spaces, because the two lists come from different sources and "Shopify " never equals "shopify" when it matters most.
              - …
            - TableTextSimilarityInput: How alike two pieces of text are, as a percentage. The dedupe and match question: is "Acme Inc." the same company as "Acme, Inc"? An exact comparison says no and a human says obviously yes, so the honest answer is a number the row can threshold on. Case and surrounding whitespace never count: they are formatting, not difference. 100 means identical after that normalisation, 0 means nothing in common.
              - …
            - TableDetectLanguageInput: The language a piece of text is written in, as an ISO 639-1 code. Routes a row before anything expensive touches it: which sequence to enrol a lead into, which reviewer sees a scraped page, whether to translate at all. Script comes first (Cyrillic, Greek, Hebrew, Arabic, Han, kana and hangul each answer on their own) and Latin text is decided by the function words it uses. That is a heuristic, not a model: it is deterministic, free, and honest about not knowing, returning null when the text is too short or matches nothing.
              - …
            - TableScoreWordsInput: Score text by the weighted words it contains. The rules half of lead scoring, without a model: "enterprise" is worth 3, "student" is worth -5, and the cell adds up whatever the row's text, tags or tech stack actually say. Expressing the same thing with ``if_then_else`` needs one step per word and runs out of chain depth at ten. Weights are a plain object: word or phrase to number. Matching is case-insensitive; a multi-word key matches as a phrase. ``count_repeats`` decides whether saying "enterprise" three times scores three times, which is the difference between weighing a claim and weighing a page.
              - …
            - TableHashInput: Hash a value: the identifier ad platforms and clean rooms ask for. Uploading an audience means handing over hashed emails, never raw ones, and the hash has to be produced the way the platform specifies: lowercased and trimmed first, hex digest out. That normalisation is the part people get wrong by hand, so it happens here rather than in three chained steps.
              - …
            - TableUriEncodeInput: Percent-encode a value so it survives being put in a URL. Every search-URL column builds the same thing (a query string with a company name in it) and every one of them breaks on the first ampersand or accent. Encoding belongs one step before the URL is assembled, not in a regex chain that handles the four characters someone remembered. ``component`` escapes everything reserved, which is what a query value needs; ``full`` leaves ``:/?#`` alone so an entire URL stays usable. Lists are encoded item by item.
              - …
            - TableUrlValidInput: Whether a value is a usable web address. The gate in front of every scrape, screenshot and HTTP column: a row whose "website" cell holds "n/a", "coming soon" or a bare company name should never spend a credit finding that out. True means the value parses as a host with a real-looking domain, not that the site answers. A formula cannot make a request, and pretending otherwise would be the one dishonest thing this function could do.
              - …
            - TableEmailPermutationsInput: The candidate work-email addresses for a name at a domain. What a verifier needs to be pointed at: nine or so patterns companies actually use, in the order they are actually common, so the cheapest verification step has a list to work through instead of one guess. The piped value is the person's name: "Ada Lovelace", or a first name with ``last_name`` supplying the rest. Anything after the first and last token (middle names, suffixes) is ignored rather than permuted, which is what keeps the list nine long instead of ninety.
              - …
            - TableRoundRobinInput: Assign each row to one of a list of owners, evenly. Lead routing, as a column: the rep, the region, the sending inbox. The piped value is the row's IDENTITY (its email, domain or id) and the owner is derived from a hash of it rather than from the row's position. That is a deliberate departure from a counter-based round robin, and it is the only version that behaves: re-running the column, adding rows above, or sorting the view all leave every existing row with the owner it already had. A counter reassigns half the table the first time anything moves, which in a CRM means the wrong rep gets the follow-up.
              - …
            - TableWeightedRoundRobinInput: Assign each row to an owner, in proportion to each owner's share. The version real teams need: a senior rep takes three leads for every one a new hire gets, one region absorbs twice the volume of another. Shares are whole numbers and mean exactly what they look like: 3 and 1 is three quarters and one quarter. Stable per row for the same reason ``round_robin`` is: the owner comes from a hash of the row's identity, so nothing already assigned moves when the table grows or the view is sorted. Changing the SHARES does move rows, because that is what changing them means.
              - …
          - `source_column_id` string, uuid, nullable
          - `source_step` integer, nullable: Read the result of an EARLIER step, by 1-based position, instead of the step immediately before. Lets a later step fork back to an intermediate value (splitting a URL once and then using both the raw split and something derived from it), which a strict pipeline cannot express. Ignored when source_column_id is set (a column wins over a step), and ignored by functions that read their arguments rather than the piped value. None reads the previous step.
        - TableListJoinInput: Join list elements into a string with a separator.
          - `failure_mode` 'pass_through_raw' | 'set_null' | 'static' | 'skip': What a formula cell resolves to when a step in its chain fails. Applies to the whole chain, read off the top-level function only. ``SKIP`` is equivalent to ``SET_NULL`` for table cells (a cell always has a stored slot, so there is nothing to skip). Kept for shape compatibility.
          - `fallback_value` union
            - string
            - integer
            - number
            - boolean
          - `function` 'list_join'
          - `next` union
            - TableCopyInput: Copy the input value unchanged.
              - …
            - TableChangeCaseInput: Change the case of a string value.
              - …
            - TableTrimInput: Strip leading and trailing whitespace from a string value.
              - …
            - TableReplaceInput: Replace all occurrences of a substring.
              - …
            - TableRegexExtractInput: Extract a regex group from a string value.
              - …
            - TableRegexReplaceInput: Replace regex matches in a string value.
              - …
            - TableConcatenateInput: Join several values into one string. Sources are ORDERED and may mix columns with the results of earlier steps: ``[First name, step 2]`` and ``[step 2, First name]`` are different strings, which is why there is one list rather than a list of columns beside a list of steps. The field keeps its original name: every stored definition holds ``source_column_ids``, and the list is still overwhelmingly columns. Only the item type widened, so old definitions validate untouched.
              - …
            - TableArithmeticInput: Apply an arithmetic operator with a constant or column-valued operand.
              - …
            - TableRoundInput: Round a numeric value to a precision.
              - …
            - TableClampInput: Clamp a numeric value to an inclusive range.
              - …
            - TableDateFormatInput: Convert a date between iso/unix/unix_ms representations.
              - …
            - TableDateExtractInput: Extract a component (year, month, ...) from a date value.
              - …
            - TableDateArithmeticInput: Add or subtract a fixed duration from a date value.
              - …
            - TableListFirstInput: Take the first element of a list value.
              - …
            - TableListLastInput: Take the last element of a list value.
              - …
            - TableListNthInput: Take the element at an index of a list value.
              - …
            - TableListJoinInput (recursive)
            - TableListCountInput: Count the elements of a list value.
              - …
            - TableListPluckInput: Pull one field out of every object in a list. Enrichment payloads routinely carry lists of objects (``[{"value": "Payroll"}, {"value": "HR"}]``) where the useful thing is the field, not the wrapper. Plucking turns that into ``["Payroll", "HR"]`` so ``list_join`` and friends can work on it; items without the field become empty and scalar items pass through unchanged.
              - …
            - TableListUniqueInput: De-duplicate list elements, keeping first-seen order.
              - …
            - TableListSplitInput: Split a string value into a list on a separator.
              - …
            - TableCoalesceInput: Substitute a default (a literal or another column) when the input is empty.
              - …
            - TableIfThenElseInput: Pick one of two values based on a comparison. Each of the three slots takes a literal or a column, so this expresses both "if this column is over that column" and "use A, else use B". Neither of those was reachable while they were constants.
              - …
            - TableConditionsInput: Fold several comparisons into ONE boolean. The engine's only boolean combinator, and the shape a column's ``run_condition`` is authored in: "only run where Employees > 50 AND Country is US". Nothing else here joins predicates: ``if_then_else`` compares exactly one pair and returns a value rather than a verdict. So without this a multi-clause gate could only be reached by chaining steps that pipe a truthy stand-in forward, which no editor could read back. One joiner over clauses and, at most one level down, groups of clauses: "A and (B or C)". That is precisely the row filter's shape, so a view's filter can be saved as a gate and read back as a filter without loss; a deeper tree would be expressible on one side only. Reads its clauses' operands directly and ignores the piped input, so it is a leaf rather than a transform.
              - …
            - TableValueMappingInput: Map input values through a lookup table.
              - …
            - TableToStringInput: Coerce the input to a string.
              - …
            - TableToIntInput: Coerce the input to an integer.
              - …
            - TableToFloatInput: Coerce the input to a float.
              - …
            - TableToBoolInput: Coerce the input to a boolean.
              - …
            - TableToDateInput: Coerce the input to a date.
              - …
            - TablePhoneE164Input: Normalize a phone number to E.164 format.
              - …
            - TableUtmParseInput: Extract a UTM parameter from a URL value.
              - …
            - TableUrlDomainInput: Reduce a URL to its bare registrable-looking host. A website field arrives as a whole URL (``https://www.acme.com/about``) but the thing that joins, dedupes and enriches is ``acme.com``. Doing it with ``regex_extract`` means every caller hand-writes the same fragile pattern, so the parse lives here once and uses a real URL parser.
              - …
            - TableCompanyDomainInput: Reduce a company's website URL to the company's own registrable domain. Three differences from ``url_domain``, which stays the generic read (a column of LinkedIn profile URLs legitimately reduces to ``linkedin.com`` there): Hosts that name a platform rather than the company (LinkedIn and Facebook pages, link aggregators, review sites, vendor partner directories) come out empty. A company whose only listed website is its LinkedIn page has no derivable domain, and an empty cell says so; ``linkedin.com`` is worse than empty because it joins, dedupes and syncs as if it were real. The result is the domain someone REGISTERED, not the bare host: a provider that lists ``careers.acme.com`` is describing ``acme.com``. A subdomain joins against nothing and sends an agent somewhere that often does not resolve. Page builders that give each customer their own label are the exception the Public Suffix List already encodes, so ``acme.wixsite.com`` survives whole rather than collapsing into ``wixsite.com``. ``company_name`` guards the case those two cannot: a directory listing reduces to the DIRECTORY owner's domain, so ``cloudpartners.transform.microsoft.com`` becomes ``microsoft.com``: right shape, wrong company, and nothing downstream can tell. Pointed at the column naming the employer, the domain is dropped when the two disagree. Optional: without it the other two rules still apply.
              - …
            - TableGetPathInput: Read a dotted path out of an object- or list-valued cell. Object and list columns were storable but unreadable: nothing in the catalog could reach a field inside one, so an enrichment payload landed in a cell and stopped there. Segments index dicts by key and lists by integer position: ``employees.count``, ``emails.0.address``. ``output_type`` is declared rather than derived because a JSON path can land on anything, and the column's data type has to be known before a single row is evaluated.
              - …
            - TableFormatInput: Build a string from a positional template and a list of arguments. ``concatenate`` joins whole columns with one separator, which cannot produce "Enterprise: Acme (12.4%)". Placeholders are positional only (``{0}``, ``{1}``) so the template stays data, not an expression language. Like ``concatenate`` this takes no ``source_column_id``: its inputs are its arguments, not the value flowing down the chain.
              - …
            - TableDateDiffInput: The signed duration between this step's date and another date. ``date_arithmetic`` shifts a date by a CONSTANT amount, so the gap between two date columns had no expression. Positive when the step's own date is the later of the two.
              - …
            - TableKeywordsInput: The most frequent meaningful words in a text or list value. Reads a body of text (a scraped page, a bio, a job description) and returns the words that carry its subject, ordered most frequent first. Stopwords ("the", "and", "with") are dropped: a frequency count that keeps them returns the same five words for every row and says nothing about any of them. Deterministic and pure: no model call, so a keyword column costs nothing and re-runs identically.
              - …
            - TableListFilterInput: Keep only the list items whose field passes a test. An enrichment payload lands as a list of objects (every job opening, every funding round, every contact) and the row usually wants a subset of it: the engineering roles, the rounds after 2024, the contacts with an email. Without this the whole list is the only thing a cell can hold. ``field`` is a dotted path INSIDE each item (``location.country``); leaving it empty tests the item itself, which is what a list of plain strings needs. ``exists``/``missing`` ignore ``value``: they ask only whether the field is there.
              - …
            - TableListSortInput: Order a list, ascending or descending. ``list_unique`` and ``list_join`` both preserve whatever order the source happened to arrive in, which is fine until the cell is meant to be READ: a top-3 of anything, a chronological history, an alphabetised tag list. ``field`` names the dotted path to sort objects BY; empty sorts the items themselves. Values that cannot be compared with each other (a number next to a string) are ordered by type first, so the sort is total instead of raising on the row where the data is mixed.
              - …
            - TableListIntersectInput: The values this list shares with another: the overlap, in the first list's order. The scoring question every ICP fit column asks: which of the buyer's tags, technologies or keywords are ALSO on my target list. Doing it by hand meant one ``if_then_else`` per tag. ``other`` is a column holding the second list, or literal text split on ``separator``. Matching ignores case and surrounding spaces, because the two lists come from different sources and "Shopify " never equals "shopify" when it matters most.
              - …
            - TableTextSimilarityInput: How alike two pieces of text are, as a percentage. The dedupe and match question: is "Acme Inc." the same company as "Acme, Inc"? An exact comparison says no and a human says obviously yes, so the honest answer is a number the row can threshold on. Case and surrounding whitespace never count: they are formatting, not difference. 100 means identical after that normalisation, 0 means nothing in common.
              - …
            - TableDetectLanguageInput: The language a piece of text is written in, as an ISO 639-1 code. Routes a row before anything expensive touches it: which sequence to enrol a lead into, which reviewer sees a scraped page, whether to translate at all. Script comes first (Cyrillic, Greek, Hebrew, Arabic, Han, kana and hangul each answer on their own) and Latin text is decided by the function words it uses. That is a heuristic, not a model: it is deterministic, free, and honest about not knowing, returning null when the text is too short or matches nothing.
              - …
            - TableScoreWordsInput: Score text by the weighted words it contains. The rules half of lead scoring, without a model: "enterprise" is worth 3, "student" is worth -5, and the cell adds up whatever the row's text, tags or tech stack actually say. Expressing the same thing with ``if_then_else`` needs one step per word and runs out of chain depth at ten. Weights are a plain object: word or phrase to number. Matching is case-insensitive; a multi-word key matches as a phrase. ``count_repeats`` decides whether saying "enterprise" three times scores three times, which is the difference between weighing a claim and weighing a page.
              - …
            - TableHashInput: Hash a value: the identifier ad platforms and clean rooms ask for. Uploading an audience means handing over hashed emails, never raw ones, and the hash has to be produced the way the platform specifies: lowercased and trimmed first, hex digest out. That normalisation is the part people get wrong by hand, so it happens here rather than in three chained steps.
              - …
            - TableUriEncodeInput: Percent-encode a value so it survives being put in a URL. Every search-URL column builds the same thing (a query string with a company name in it) and every one of them breaks on the first ampersand or accent. Encoding belongs one step before the URL is assembled, not in a regex chain that handles the four characters someone remembered. ``component`` escapes everything reserved, which is what a query value needs; ``full`` leaves ``:/?#`` alone so an entire URL stays usable. Lists are encoded item by item.
              - …
            - TableUrlValidInput: Whether a value is a usable web address. The gate in front of every scrape, screenshot and HTTP column: a row whose "website" cell holds "n/a", "coming soon" or a bare company name should never spend a credit finding that out. True means the value parses as a host with a real-looking domain, not that the site answers. A formula cannot make a request, and pretending otherwise would be the one dishonest thing this function could do.
              - …
            - TableEmailPermutationsInput: The candidate work-email addresses for a name at a domain. What a verifier needs to be pointed at: nine or so patterns companies actually use, in the order they are actually common, so the cheapest verification step has a list to work through instead of one guess. The piped value is the person's name: "Ada Lovelace", or a first name with ``last_name`` supplying the rest. Anything after the first and last token (middle names, suffixes) is ignored rather than permuted, which is what keeps the list nine long instead of ninety.
              - …
            - TableRoundRobinInput: Assign each row to one of a list of owners, evenly. Lead routing, as a column: the rep, the region, the sending inbox. The piped value is the row's IDENTITY (its email, domain or id) and the owner is derived from a hash of it rather than from the row's position. That is a deliberate departure from a counter-based round robin, and it is the only version that behaves: re-running the column, adding rows above, or sorting the view all leave every existing row with the owner it already had. A counter reassigns half the table the first time anything moves, which in a CRM means the wrong rep gets the follow-up.
              - …
            - TableWeightedRoundRobinInput: Assign each row to an owner, in proportion to each owner's share. The version real teams need: a senior rep takes three leads for every one a new hire gets, one region absorbs twice the volume of another. Shares are whole numbers and mean exactly what they look like: 3 and 1 is three quarters and one quarter. Stable per row for the same reason ``round_robin`` is: the owner comes from a hash of the row's identity, so nothing already assigned moves when the table grows or the view is sorted. Changing the SHARES does move rows, because that is what changing them means.
              - …
          - `separator` string
          - `source_column_id` string, uuid, nullable
          - `source_step` integer, nullable: Read the result of an EARLIER step, by 1-based position, instead of the step immediately before. Lets a later step fork back to an intermediate value (splitting a URL once and then using both the raw split and something derived from it), which a strict pipeline cannot express. Ignored when source_column_id is set (a column wins over a step), and ignored by functions that read their arguments rather than the piped value. None reads the previous step.
        - TableListCountInput: Count the elements of a list value.
          - `failure_mode` 'pass_through_raw' | 'set_null' | 'static' | 'skip': What a formula cell resolves to when a step in its chain fails. Applies to the whole chain, read off the top-level function only. ``SKIP`` is equivalent to ``SET_NULL`` for table cells (a cell always has a stored slot, so there is nothing to skip). Kept for shape compatibility.
          - `fallback_value` union
            - string
            - integer
            - number
            - boolean
          - `function` 'list_count'
          - `next` union
            - TableCopyInput: Copy the input value unchanged.
              - …
            - TableChangeCaseInput: Change the case of a string value.
              - …
            - TableTrimInput: Strip leading and trailing whitespace from a string value.
              - …
            - TableReplaceInput: Replace all occurrences of a substring.
              - …
            - TableRegexExtractInput: Extract a regex group from a string value.
              - …
            - TableRegexReplaceInput: Replace regex matches in a string value.
              - …
            - TableConcatenateInput: Join several values into one string. Sources are ORDERED and may mix columns with the results of earlier steps: ``[First name, step 2]`` and ``[step 2, First name]`` are different strings, which is why there is one list rather than a list of columns beside a list of steps. The field keeps its original name: every stored definition holds ``source_column_ids``, and the list is still overwhelmingly columns. Only the item type widened, so old definitions validate untouched.
              - …
            - TableArithmeticInput: Apply an arithmetic operator with a constant or column-valued operand.
              - …
            - TableRoundInput: Round a numeric value to a precision.
              - …
            - TableClampInput: Clamp a numeric value to an inclusive range.
              - …
            - TableDateFormatInput: Convert a date between iso/unix/unix_ms representations.
              - …
- … truncated; see the full OpenAPI document linked below

## Response `200`

Successful Response

- TableColumnPreviewResponseSchema: Preview results over the table's first rows; nothing is persisted.
  - `results` TableColumnPreviewRowSchema[], required
    - `error` string, nullable, required: The evaluation error, when the chain failed.
    - `record_id` string, uuid, required
    - `value` unknown, required

## Other responses

- `401`: Unauthorized
- `403`: Forbidden
- `404`: Table not found
- `422`: Invalid request made to the API.
- `500`: Internal server error.
- `502`: Bad gateway error.
- `503`: Service unavailable.

---

[API](https://skmtc.dev/getoneprofile/apis/api-reference-oneprofile.md) · [All operations](https://skmtc.dev/getoneprofile/apis/api-reference-oneprofile/llms.txt) · [OpenAPI document](https://skmtc.dev/getoneprofile/apis/api-reference-oneprofile/revisions/4a6bd71e3f02?raw)
