Atlas Scripts
mask
A reusable, named mask. Define columns (globs allowed) and a method once at the top level, then apply it via use = [mask.<name>] from any query or script.
mask "pii" {
columns = ["ssn", "*email*"]
method = HASH
}
mask attributes
| Name and description | Required | Value |
|---|---|---|
| false | string |
Output columns to mask, matched case-sensitively; an entry with | false | List of strings |
| false | int |
| false | int |
| false | int |
| false | string |
Masking method ( | false |
|
| false | string |
| false | string |
| false | string |
mask constraints
| Constraint | Value |
|---|---|
| Required | false |
Require Name (e.g., mask "name" ) | true |
| Repeatable | true |
script exec
Runs a sequence of condition, assert, check, exec, and query blocks as a program against the connected database. Blocks execute in their textual order; a failing assert/check/exec aborts the script (and rolls back when on_error = ROLLBACK), while an unmet condition stops it gracefully. A query binds its result for later steps as query.<name>.rows[*].<col>.
script.exec attributes
| Name and description | Required | Value |
|---|---|---|
Free-form description; surfaced in audit logs. | false | string |
script.exec blocks
script.assert
An assert runs inside the script's session and asserts a boolean SQL condition. A failing assertion aborts the script (and rolls back when tx.on_error = ROLLBACK).
assert "is_active" {
sql = "select status = 'active' from users where id = ?"
args = [var.id]
}
sql must return exactly one row, one boolean (or 1/0) column. A truthy value passes; falsy or NULL fails.
script.assert attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Positional bind values can be one of:
|
Message returned to the user when the assertion fails. | false | string |
SQL query whose single boolean (or 1/0) result is asserted. | true | string |
script.assert constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.check
A check runs a SQL query and compares its formatted output to an expected value or pattern - same shape as the exec block in atlas test.
check "user_count" {
sql = "select count(*) from users"
output = "1"
}
script.check attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Positional bind values can be one of:
|
Message returned to the user when the check fails. | false | string |
Serialization format for the query output ( | false |
|
Regular expression the output must match. | false | string |
Expected output, compared after trimming surrounding whitespace. | false | string |
SQL query whose output is compared. | true | string |
script.check constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
| Mutually exclusive sets | [output, match] |
script.condition
A guard evaluated in textual order with the other steps. When its boolean SQL is not satisfied, the script stops gracefully at that point - committing the work done so far - without reporting a failure.
condition "user_exists" {
sql = "select count(*) > 0 from users where id = ?"
args = [var.id]
}
sql must return exactly one row, one boolean (or 1/0) column. A truthy value lets the program continue; falsy or NULL stops it gracefully.
script.condition attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Positional bind values can be one of:
|
SQL query whose single boolean (or 1/0) result is the guard. | true | string |
script.condition constraints
| Constraint | Value |
|---|---|
| Required | false |
Require Name (e.g., script.condition "name" ) | true |
| Repeatable | true |
script.exec
The mutation to run. The name label is optional and surfaces in logs.
script.exec attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Positional bind values can be one of:
|
Expected number of rows affected by | false | int |
SQL statement (or batch) to execute. | true | string |
script.exec constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.output
Emit a line of script output, e.g. "archived ${length(query.dormant.rows)} users". Unlike log (diagnostics), output is part of the script's result and is printed even by a quiet logger.
script.output attributes
| Name and description | Required | Value |
|---|---|---|
The line to emit; may interpolate scope values, e.g. | true | string |
script.output constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.query
A read whose result later steps reference as query.<name>.rows[*].<col> (a list), .rows[N].<col> (one row), or length(query.<name>.rows).
query "batch" {
sql = "SELECT id, email FROM staging WHERE batch = ? ORDER BY id"
args = [iterator.range.from]
rows { id = int email = string }
}
script.query attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Positional bind values can be one of:
|
SQL query to run. Atlas binds | true | string |
script.query blocks
script.query.rows
The result columns, declared as typed columns (name = <type>). Atlas reads only these columns, by name, and exposes them as query.<name>.rows[*].<col>.
script.query.rows constraints
| Constraint | Value |
|---|---|
| Required | true |
| Require Name | false |
| Allow unknown attributes | true |
script.query constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.tx
Transactional envelope for the script.
script.tx attributes
| Name and description | Required | Value |
|---|---|---|
Transaction mode. | false |
|
Behavior when the script errors. | false |
|
script.exec constraints
| Constraint | Value |
|---|---|
| Required | false |
| Repeatable | true |
script loop
Batched/repeated loop: pre-loop condition gates, one iterator + one do body, post-loop assert/check, and an optional policy block (tx/schedule/ramp).
script.loop attributes
| Name and description | Required | Value |
|---|---|---|
Free-form description; surfaced in audit logs. | false | string |
script.loop blocks
script.assert
An assert runs inside the script's session and asserts a boolean SQL condition. A failing assertion aborts the script (and rolls back when tx.on_error = ROLLBACK).
assert "is_active" {
sql = "select status = 'active' from users where id = ?"
args = [var.id]
}
sql must return exactly one row, one boolean (or 1/0) column. A truthy value passes; falsy or NULL fails.
script.assert attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Any value |
Message returned to the user when the assertion fails. | false | string |
SQL query whose single boolean (or 1/0) result is asserted. | true | string |
script.assert constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.check
A check runs a SQL query and compares its formatted output to an expected value or pattern - same shape as the exec block in atlas test.
check "user_count" {
sql = "select count(*) from users"
output = "1"
}
script.check attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Any value |
Message returned to the user when the check fails. | false | string |
Serialization format for the query output ( | false |
|
Regular expression the output must match. | false | string |
Expected output, compared after trimming surrounding whitespace. | false | string |
SQL query whose output is compared. | true | string |
script.check constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
| Mutually exclusive sets | [output, match] |
script.condition
A guard evaluated in textual order with the other steps. When its boolean SQL is not satisfied, the script stops gracefully at that point - committing the work done so far - without reporting a failure.
condition "user_exists" {
sql = "select count(*) > 0 from users where id = ?"
args = [var.id]
}
sql must return exactly one row, one boolean (or 1/0) column. A truthy value lets the program continue; falsy or NULL stops it gracefully.
script.condition attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Any value |
SQL query whose single boolean (or 1/0) result is the guard. | true | string |
script.condition constraints
| Constraint | Value |
|---|---|
| Required | false |
Require Name (e.g., script.condition "name" ) | true |
| Repeatable | true |
script.do
The per-iteration body. Same shape as an exec script; args may reference iterator.<mode>.* (e.g. batch). With tx.mode = MANUAL, wrap atomic statements in tx { } blocks.
script.do attributes
| Name and description | Required | Value |
|---|---|---|
On a failing iteration: | false |
|
script.do blocks
script.do.assert
An assert runs inside the script's session and asserts a boolean SQL condition. A failing assertion aborts the script (and rolls back when tx.on_error = ROLLBACK).
assert "is_active" {
sql = "select status = 'active' from users where id = ?"
args = [var.id]
}
sql must return exactly one row, one boolean (or 1/0) column. A truthy value passes; falsy or NULL fails.
script.do.assert attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Positional bind values can be one of:
|
Message returned to the user when the assertion fails. | false | string |
SQL query whose single boolean (or 1/0) result is asserted. | true | string |
script.do.assert constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.do.break
Stop the loop when its boolean SQL is true - committing the work done so far this iteration, then running the post-loop assert/check.
break "disk_pressure" {
sql = "select pg_database_size(current_database()) > 5e11"
}
script.do.break attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Positional bind values can be one of:
|
Boolean SQL; when true (truthy), the loop stops. | true | string |
script.do.break constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.do.check
A check runs a SQL query and compares its formatted output to an expected value or pattern - same shape as the exec block in atlas test.
check "user_count" {
sql = "select count(*) from users"
output = "1"
}
script.do.check attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Positional bind values can be one of:
|
Message returned to the user when the check fails. | false | string |
Serialization format for the query output ( | false |
|
Regular expression the output must match. | false | string |
Expected output, compared after trimming surrounding whitespace. | false | string |
SQL query whose output is compared. | true | string |
script.do.check constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
| Mutually exclusive sets | [output, match] |
script.do.continue
Skip the rest of the current iteration when its boolean SQL is true - committing the work done so far - and advance to the next iteration.
continue "already_done" {
sql = "select count(*) = 0 from staging where batch = ?"
args = [iterator.range.from]
}
script.do.continue attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Positional bind values can be one of:
|
Boolean SQL; when true (truthy), skip to the next iteration. | true | string |
script.do.continue constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.do.exec
The mutation to run. The name label is optional and surfaces in logs.
script.do.exec attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Positional bind values can be one of:
|
Expected number of rows affected by | false | int |
SQL statement (or batch) to execute. | true | string |
script.do.exec constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.do.http
Call an external HTTP endpoint (e.g. a service's deletion API that also cleans up blob storage). url/headers/body may interpolate scope like query.<name>.rows[*].id. Requires tx { mode = MANUAL } - a fired request cannot be rolled back.
http "del" {
url = var.deletion_endpoint
method = POST
body = jsonencode({ ids = query.batch.rows[*].id })
response = object({ data = object({ deleteUsers = object({ deleted = number }) }) })
}
script.do.http attributes
| Name and description | Required | Value |
|---|---|---|
Request body, e.g. | false | string |
Certificate Authority (CA) in PEM format. | false | string |
Client certificate in PEM format. | false | string |
Client key in PEM format. | false | string |
Expected HTTP status code; a mismatch fails the step. | false | int |
Request headers, e.g. | false | map |
Disable verification of the server's certificate chain and hostname. Defaults to | false | bool |
HTTP method ( | false |
|
Request timeout in milliseconds. | false | int |
Expected JSON response shape as a type, e.g. | false | HCL type ( |
The endpoint URL. Supported schemes are | true | string |
script.do.http blocks
script.do.http.check
Assert a boolean condition over the decoded response; a false or null result fails the step (and the loop, per on_error). No SQL - evaluated in-process.
check {
condition = length(http.del.errors) == 0
error_message = "deletion service returned errors"
}
script.do.http.check attributes
| Name and description | Required | Value |
|---|---|---|
Boolean expression over the response, e.g. | true | Boolean condition over the response can be one of:
|
Message returned to the user when the condition fails. | false | string |
script.do.http.check constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.do.http.retry
Retry the request on a transient failure (a network error or a 5xx response).
script.do.http.retry attributes
| Name and description | Required | Value |
|---|---|---|
Maximum number of retries after the first attempt. | false | int |
Maximum backoff between attempts, in milliseconds. | false | int |
Minimum backoff between attempts, in milliseconds. | false | int |
script.do.http constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
| Mutually exclusive sets | [ca_cert_pem, insecure] |
script.do.log
Emit a line to the run log. message may interpolate scope values, e.g. "page ${self.index}".
script.do.log attributes
| Name and description | Required | Value |
|---|---|---|
The line to log; may interpolate ${self.index}, ${iterator.<mode>.*}, etc. | true | string |
script.do.log constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.do.output
Emit a line of script output, e.g. "archived ${length(query.dormant.rows)} users". Unlike log (diagnostics), output is part of the script's result and is printed even by a quiet logger.
script.do.output attributes
| Name and description | Required | Value |
|---|---|---|
The line to emit; may interpolate scope values, e.g. | true | string |
script.do.output constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.do.query
A read whose result later steps reference as query.<name>.rows[*].<col> (a list), .rows[N].<col> (one row), or length(query.<name>.rows).
query "batch" {
sql = "SELECT id, email FROM staging WHERE batch = ? ORDER BY id"
args = [iterator.range.from]
rows { id = int email = string }
}
script.do.query attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Positional bind values can be one of:
|
SQL query to run. Atlas binds | true | string |
script.do.query blocks
script.do.query.rows
The result columns, declared as typed columns (name = <type>). Atlas reads only these columns, by name, and exposes them as query.<name>.rows[*].<col>.
script.do.query.rows constraints
| Constraint | Value |
|---|---|
| Required | true |
| Require Name | false |
| Allow unknown attributes | true |
script.do.query constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.do.sleep
Pause for a fixed duration within the iteration, e.g. 500ms or 5s.
script.do.sleep attributes
| Name and description | Required | Value |
|---|---|---|
Go duration string, e.g. | true | string |
script.do.sleep constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.do.tx
An atomic group: the wrapped statements commit or roll back together. Requires the loop-level tx { mode = MANUAL }.
script.do.tx blocks
script.do.tx.assert
An assert runs inside the script's session and asserts a boolean SQL condition. A failing assertion aborts the script (and rolls back when tx.on_error = ROLLBACK).
assert "is_active" {
sql = "select status = 'active' from users where id = ?"
args = [var.id]
}
sql must return exactly one row, one boolean (or 1/0) column. A truthy value passes; falsy or NULL fails.
script.do.tx.assert attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Positional bind values can be one of:
|
Message returned to the user when the assertion fails. | false | string |
SQL query whose single boolean (or 1/0) result is asserted. | true | string |
script.do.tx.assert constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.do.tx.check
A check runs a SQL query and compares its formatted output to an expected value or pattern - same shape as the exec block in atlas test.
check "user_count" {
sql = "select count(*) from users"
output = "1"
}
script.do.tx.check attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Positional bind values can be one of:
|
Message returned to the user when the check fails. | false | string |
Serialization format for the query output ( | false |
|
Regular expression the output must match. | false | string |
Expected output, compared after trimming surrounding whitespace. | false | string |
SQL query whose output is compared. | true | string |
script.do.tx.check constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
| Mutually exclusive sets | [output, match] |
script.do.tx.exec
The mutation to run. The name label is optional and surfaces in logs.
script.do.tx.exec attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Positional bind values can be one of:
|
Expected number of rows affected by | false | int |
SQL statement (or batch) to execute. | true | string |
script.do.tx.exec constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.do.tx constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.do constraints
| Constraint | Value |
|---|---|
| Required | true |
| Require Name | false |
script.iterator.keyset
Cursor-paginated iteration. Declare the seek cursor, optionally the exposed batch, and the init/next SELECTs Atlas threads the cursor through.
script.iterator.keyset blocks
script.iterator.batch
Optional. The page rows exposed to do as iterator.keyset.batch[*].<col>. Defaults to the cursor columns; declare it only to expose a different or extra set.
script.iterator.batch constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Allow unknown attributes | true |
script.iterator.cursor
The seek state, declared as typed columns (name = <type>). Atlas carries these across iterations and binds them as cursor.<col> in next.args.
cursor {
created_at = time
id = int
}
script.iterator.cursor constraints
| Constraint | Value |
|---|---|
| Required | true |
| Require Name | false |
| Allow unknown attributes | true |
script.iterator.init
The init page SELECT. It must return the cursor (and batch) columns; Atlas never rewrites it.
script.iterator.init attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Positional bind values can be one of:
|
The paginated SELECT - you own the | true | string |
script.iterator.init constraints
| Constraint | Value |
|---|---|
| Required | true |
| Require Name | false |
script.iterator.next
The next page SELECT. It must return the cursor (and batch) columns; Atlas never rewrites it.
script.iterator.next attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Positional bind values can be one of:
|
The paginated SELECT - you own the | true | string |
script.iterator.next constraints
| Constraint | Value |
|---|---|
| Required | true |
| Require Name | false |
script.iterator.range
Numeric range iteration. Atlas walks from..to in step-sized chunks, binding the current chunk as iterator.range.from/iterator.range.to in do.
script.iterator.range attributes
| Name and description | Required | Value |
|---|---|---|
Inclusive lower bound of the range. | true | int |
Chunk size: how far each iteration advances (>= 1). Defaults to 1. | false | int |
Inclusive upper bound of the range. | true | int |
script.iterator.range exposed references
| Name | Value |
|---|---|
from | int |
step | int |
to | int |
script.policy
Operational policy for the loop: tx (transaction mode), schedule (cadence, bounds, back-pressure), and ramp (batch-size dial-up).
script.policy blocks
script.policy.ramp
Staged dial-up of the batch size: run small first (catch mistakes cheaply, watch the logs), then grow after each stage's hold. The current size is bound into the iterator SQL as ${ramp.size}.
ramp {
stage { size = 10 hold = "168h" } # week 1: tiny
stage { size = 500000 } # then full speed
}
script.policy.ramp blocks
script.policy.ramp.stage
One ramp step: a size held for iterations or hold before advancing.
script.policy.ramp.stage attributes
| Name and description | Required | Value |
|---|---|---|
Advance after this duration at this stage, e.g. | false | string |
Advance after this many iterations at this stage (mutually exclusive with | false | int |
Delay between iterations at this stage (overrides | false | string |
The chunk size for this stage, bound into the iterator SQL as | true | int |
script.policy.ramp.stage constraints
| Constraint | Value |
|---|---|
| Required | true |
| Require Name | false |
| Repeatable | true |
| Mutually exclusive sets | [iterations, hold] |
script.policy.schedule
How often and how long the loop runs: cadence, bounds, and back-pressure.
script.policy.schedule attributes
| Name and description | Required | Value |
|---|---|---|
Fixed delay between iterations, e.g. | false | string |
Maximum number of iterations before the loop stops. | false | int |
Boolean probe (one row, one boolean/1-0): while true the loop pauses and re-probes, then resumes. Back off on replica lag, lock waits, or queue depth. | false | string |
Wall-clock bound, e.g. | false | string |
script.policy.tx
Transaction policy for the loop body.
script.policy.tx attributes
| Name and description | Required | Value |
|---|---|---|
| false |
|
script.loop constraints
| Constraint | Value |
|---|---|
| Required | false |
| Repeatable | true |
script query
Single-DB query script. Contains one or more query blocks; each runs in textual order and writes its result as a section of the output.
script.query attributes
| Name and description | Required | Value |
|---|---|---|
Free-form description of the script. | false | string |
script.query blocks
script.mask
Redacts one or more columns of the query result before serialization. Select columns with columns and a method, or apply top-level named masks with use. At script level a mask applies to every query; a query's own mask wins (first match).
mask {
columns = ["email", "phone*"]
method = REDACT
}
mask { use = [mask.pii] }
script.mask attributes
| Name and description | Required | Value |
|---|---|---|
| false | string |
Output columns to mask, matched case-sensitively; an entry with | false | List of strings |
| false | int |
| false | int |
| false | int |
| false | string |
Masking method ( | false |
|
| false | string |
| false | string |
Top-level named masks to apply, e.g. | false | List of object reference to |
| false | string |
script.mask constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
| Mutually exclusive sets | [use, columns], [use, method] |
script.output
Emit a line of script output, e.g. "archived ${length(query.dormant.rows)} users". Unlike log (diagnostics), output is part of the script's result and is printed even by a quiet logger.
script.output attributes
| Name and description | Required | Value |
|---|---|---|
The line to emit; may interpolate scope values, e.g. | true | string |
script.output constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.query
A single read. Runs sql, optionally redacts columns via mask blocks, and serializes the result per format as a section of the script's output. With a rows block it prints nothing; the result is bound for later blocks as query.<name>.rows[*].<col>.
query "user_by_id" {
sql = "select id, email from users where id = ?"
args = [var.id]
format = CSV
}
script.query attributes
| Name and description | Required | Value |
|---|---|---|
Positional values bound to placeholders in | false | Positional bind values can be one of:
|
Serialization format for this query's result ( | false |
|
SQL query to run. | true | string |
script.query blocks
script.query.mask
Redacts one or more columns of the query result before serialization. Select columns with columns and a method, or apply top-level named masks with use. At script level a mask applies to every query; a query's own mask wins (first match).
mask {
columns = ["email", "phone*"]
method = REDACT
}
mask { use = [mask.pii] }
script.query.mask attributes
| Name and description | Required | Value |
|---|---|---|
| false | string |
Output columns to mask, matched case-sensitively; an entry with | false | List of strings |
| false | int |
| false | int |
| false | int |
| false | string |
Masking method ( | false |
|
| false | string |
| false | string |
Top-level named masks to apply, e.g. | false | List of object reference to |
| false | string |
script.query.mask constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
| Mutually exclusive sets | [use, columns], [use, method] |
script.query.rows
The result columns, declared as typed columns (name = <type>). Atlas reads only these columns, by name, and exposes them as query.<name>.rows[*].<col>.
script.query.rows constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Allow unknown attributes | true |
script.query constraints
| Constraint | Value |
|---|---|
| Required | false |
| Require Name | false |
| Repeatable | true |
script.query constraints
| Constraint | Value |
|---|---|
| Required | false |
| Repeatable | true |