> ## Documentation Index
> Fetch the complete documentation index at: https://docs.canary.effectiveai.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Run a submission

> Use `rslc submission` to record one submission in a log: open it, answer, sign off, quote options, bind, close or decline, and read the history.

[Install Relativities](https://docs.canary.effectiveai.app/relativities/setup.md) first; it includes `rslc`. This guide runs the staffing
example, a guideline for the synthetic carrier Example Mutual. Run your own guideline the same way.

`rslc examples get staffing` saves the example, and `open` starts a log for its guideline:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc examples get staffing
cd staffing
rslc submission open submission.jsonl --program guideline.rsl --as assistant:intake
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
WROTE staffing/application.json
WROTE staffing/bind.script
WROTE staffing/guideline.rsl
WROTE staffing/rater.rsl
WROTE staffing/stale.script
  1  assistant:intake  opened guideline.rsl (program 6c92e7971a32)
stage: Open
open (4):
  operation           input    any role
  years_in_operation  input    any role
  policy              input    any role
  policy.experience   input    @uw
```

One log holds one submission. `open` pins the log to the program, so later commands name only
the log. Every command prints the entries it wrote, then the status: the stage and the open questions.

The log's name ends in `.jsonl` for a file of JSON lines, or in `.sqlite` for a database.
[Submission log](https://docs.canary.effectiveai.app/rsl/reference/submission-log.md#log-stores) compares the two.

Each command that writes names its writer as `--as role:name`. The role is one that the guideline
declares in `Roles`. The name is free text for the person or the tool.

## Answer questions

A question is an input's path, such as `policy.payroll`, or a referral's name. To answer from a
JSON file, pass `--file`:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission answer submission.jsonl --file application.json --as assistant:intake
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
  2  assistant:intake  answered operation = "staffing" from application.json
  3  assistant:intake  answered policy.limit = 1000000 from application.json
  4  assistant:intake  answered policy.payroll = 2500000 from application.json
  5  assistant:intake  answered years_in_operation = 2 from application.json
stage: Open
open (2):
  policy.experience  input    @uw
  new_venture        signoff  @manager  because: The firm is in operation for less than 3 years.
                       reads years_in_operation = 2
referrals:
  new_venture  Open  @manager
```

The file holds one JSON object. Each top-level key is one question, and each entry names the file
as its source.

To answer on the command line, write `question=value`:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission answer submission.jsonl policy.experience=no_claims --because "Loss runs, five years" --from "loss-runs.pdf" --as uw:alice
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
  6  uw:alice  answered policy.experience = "no_claims" from loss-runs.pdf because "Loss runs, five years"
stage: Open
open (1):
  new_venture  signoff  @manager  because: The firm is in operation for less than 3 years.
                 reads years_in_operation = 2
referrals:
  new_venture  Open  @manager
outcomes known so far:
  premium = 5000
```

* `--because` records why the writer gives the answer.
* `--from` records where the answer comes from, such as a document or a system.
* A value is JSON, or a bare word for a string: `2500000`, `true`, `no_claims`.
* Quote a value that the shell changes, such as `'policy={"payroll": 2500000}'`.
* One command takes several `question=value` pairs and applies all of them or refuses all of them.
* To replace an answer, answer the question again.
* Name a list item by its key, as in `'placements[class="clerical"].share=0.6'`.
  [Submission log](https://docs.canary.effectiveai.app/rsl/reference/submission-log.md#list-items) gives the rules.

## Check the status

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission status submission.jsonl
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
stage: Open
open (1):
  new_venture  signoff  @manager  because: The firm is in operation for less than 3 years.
                 reads years_in_operation = 2
referrals:
  new_venture  Open  @manager
outcomes known so far:
  premium = 5000
```

The `open` block lists each question that still needs an answer, its kind, and the lowest role
that may answer. A `signoff` line is a referral with its reason, and each `reads` line under it
is an answer that the sign-off stands for. `outcomes known so far` lists each outcome that the
answers already decide.

## Retract an answer

To make a question open again, retract its answer by the path it was given at:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission retract submission.jsonl years_in_operation --as assistant:intake
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
  7  assistant:intake  retracted years_in_operation
stage: Open
open (1):
  years_in_operation  input    any role
outcomes known so far:
  premium = 5000
```

The referral leaves the status, because its condition reads the retracted answer. Answer the
question again to continue:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission answer submission.jsonl years_in_operation=2 --as assistant:intake
```

## Sign off a referral

A sign-off is an answer to the referral's name, from the referral's role or a role above it:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission answer submission.jsonl new_venture=Approved --because "Experienced owners." --as manager:morgan
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
  9  manager:morgan  signed off new_venture = Approved on years_in_operation = 2 because "Experienced owners."
stage: Quotable
referrals:
  new_venture  Approved  @manager
outcomes:
  premium = 5000
```

* `Approved` lets the submission go on. `Declined` makes it `Ineligible`; see [Decline a submission](#decline-a-submission).
* The entry records the answers that the manager saw, after `on`.
* `retract` with the referral's name takes a sign-off back.
* A sign-off lapses when an answer that the referral's condition reads changes. Sign off again on the new answers.

## Quote

Give the quote a name:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission quote submission.jsonl q1 --as uw:alice
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
 10  uw:alice  quoted q1: 1 outcomes
stage: Quotable
quotes:
  q1  stands
referrals:
  new_venture  Approved  @manager
outcomes:
  premium = 5000
```

* `quote` works in the `Quotable` stage: every question has an answer and every open referral is approved.
* A quote name starts with a lowercase letter and holds lowercase letters, digits and `_`. A log uses each name once.
* A quote lapses when an answer or a sign-off changes after it. Quote again under a new name.

## Offer quote options

The broker asks for a second quote with a \$2,000,000 limit. Both quotes price the same firm, so
only the limit differs.

The rater marks `limit` with `per quote`:

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
limit: Num {precision: int} per quote where self in [1000000, 2000000] [cite: rules:p3]
```

An input with this mark is a **term**. Every other input is a **fact**, and all quotes of the
submission share one answer to it.

A **quote option** is a named set of answers to terms, laid over the shared answers. Answer the
limit in an option named `high`, with `--in`:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission answer submission.jsonl policy.limit=2000000 --in high --as uw:alice
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
 11  uw:alice  answered policy.limit = 2000000 in high
stage: Quotable
quotes:
  q1  stands
referrals:
  new_venture  Approved  @manager
outcomes:
  premium = 5500
```

The status after a command with `--in` is the status of that option: the premium is \$5,500 at the
higher limit. The shared answers still hold the \$1,000,000 limit, so `q1` stands.

Quote the option under a new name:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission quote submission.jsonl q2 --in high --as uw:alice
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
 12  uw:alice  quoted q2 in high: 1 outcomes
stage: Quotable
quotes:
  q1  stands
  q2  stands
referrals:
  new_venture  Approved  @manager
outcomes:
  premium = 5500
```

Both quotes stand at once: `q1` at \$5,000 and `q2` at \$5,500. A plain `status` reads the shared
answers, at the \$1,000,000 limit:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission status submission.jsonl
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
stage: Quotable
quotes:
  q1  stands
  q2  stands
referrals:
  new_venture  Approved  @manager
outcomes:
  premium = 5000
```

Add `--in high` to read the option, at \$5,500.

An option answers terms only. The log refuses a fact in an option with the code `NOT_A_TERM`:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission answer submission.jsonl policy.payroll=3000000 --in high --as uw:alice
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
refused NOT_A_TERM: `policy.payroll` is a fact every quote shares, so it is answered without `in high`; an option answers only an input marked `per quote`
stage: Quotable
quotes:
  q1  stands
  q2  stands
referrals:
  new_venture  Approved  @manager
outcomes:
  premium = 5500
```

* `--in` works with `answer`, `retract`, `quote` and `status`.
* An option's name follows the rule for a quote's name.
* An option starts with its first answer. `quote --in` on an option that holds zero answers is refused as `NOT_QUOTABLE`.
* `retract --in high` takes back the option's answer, and the option reads the shared answer again.
* A new answer to a fact, given as usual, changes every option. Each quote that it changes lapses.
* A sign-off given as usual counts in each option that holds the answers it read. A sign-off with `--in` counts in that option alone.

## Bind

`bind` names one quote that stands. The insured accepts the higher limit:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission bind submission.jsonl q2 --as uw:alice
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
 13  uw:alice  bound q2
stage: Bound
quotes:
  q1  stands
  q2  bound
referrals:
  new_venture  Approved  @manager
outcomes:
  premium = 5000
```

* `bind` takes a quote that stands. A bound submission is final.
* A quote keeps its option, so `bind` takes the name alone.
* The `outcomes` block of a plain `status` reads the shared answers, here the \$1,000,000 limit.
  The bound policy is the option of `q2`: read it with `status --in high`.

## Read the history

`history` lists every entry, with its number and its writer:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission history submission.jsonl
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
  1  assistant:intake  opened guideline.rsl (program 6c92e7971a32)
  2  assistant:intake  answered operation = "staffing" from application.json
  3  assistant:intake  answered policy.limit = 1000000 from application.json
  4  assistant:intake  answered policy.payroll = 2500000 from application.json
  5  assistant:intake  answered years_in_operation = 2 from application.json
  6  uw:alice  answered policy.experience = "no_claims" from loss-runs.pdf because "Loss runs, five years"
  7  assistant:intake  retracted years_in_operation
  8  assistant:intake  answered years_in_operation = 2
  9  manager:morgan  signed off new_venture = Approved on years_in_operation = 2 because "Experienced owners."
 10  uw:alice  quoted q1: 1 outcomes
 11  uw:alice  answered policy.limit = 2000000 in high
 12  uw:alice  quoted q2 in high: 1 outcomes
 13  uw:alice  bound q2
```

To see the status as it was after an earlier entry, pass its number as `--at`:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission status submission.jsonl --at 6
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
stage: Open
open (1):
  new_venture  signoff  @manager  because: The firm is in operation for less than 3 years.
                 reads years_in_operation = 2
referrals:
  new_venture  Open  @manager
outcomes known so far:
  premium = 5000
```

## Write on what you read

Another person may change a submission between your read and your write. `--based-on` names the
last entry you read, and the log then refuses a write whose facts changed after that entry.

Start a second log, with the application and the loss experience in it:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission open second.jsonl --program guideline.rsl --as uw:alice
rslc submission answer second.jsonl --file application.json policy.experience=no_claims --as uw:alice
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
...
  6  uw:alice  answered policy.experience = "no_claims"
stage: Open
open (1):
  new_venture  signoff  @manager  because: The firm is in operation for less than 3 years.
                 reads years_in_operation = 2
referrals:
  new_venture  Open  @manager
outcomes known so far:
  premium = 5000
```

The manager reads this status, whose last entry is 6. Before the manager decides, the underwriter
corrects the firm's age:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission answer second.jsonl years_in_operation=1 --because "Corrected from the website" --as uw:alice
```

The manager signs off the firm of 2 years that entry 6 showed:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission answer second.jsonl new_venture=Approved --based-on 6 --as manager:morgan
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
refused STALE: signing off `new_venture` is based on entry 6, and years_in_operation changed after it; read the submission again and decide on what it holds now
stage: Open
open (1):
  new_venture  signoff  @manager  because: The firm is in operation for less than 3 years.
                 reads years_in_operation = 1
referrals:
  new_venture  Open  @manager
outcomes known so far:
  premium = 5000
```

The log refuses the sign-off as `STALE` and names the answer that changed. Read the status again,
then write on the entry it shows:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission answer second.jsonl new_venture=Approved --based-on 7 --as manager:morgan
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
  8  manager:morgan  signed off new_venture = Approved on years_in_operation = 1
stage: Quotable
referrals:
  new_venture  Approved  @manager
outcomes:
  premium = 5000
```

* `--based-on` works with `answer`, `retract`, `quote`, `bind` and `close`.
* The log compares only what the command reads. A change elsewhere in the log leaves your write valid.
* With `--in`, the log compares what the command reads in that option.
* The entry number is the last number in `history`, or `seq` in the `--json` output.

## Close a submission

To end a submission before a quote is bound, close it with a reason: `withdrawn`, `expired` or `lost`.

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission close second.jsonl lost --because "Placed with another carrier" --as uw:alice
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
  9  uw:alice  closed (lost) because "Placed with another carrier"
stage: Closed
referrals:
  new_venture  Approved  @manager
outcomes:
  premium = 5000
```

A closed submission is final, like a bound one. Each role closes with these three reasons.

## Decline a submission

A fourth reason, `declined`, records the carrier's decision to turn a submission down. It follows
the `Ineligible` stage.

A third applicant is a PEO that is 2 years old. Open a log for it:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission open peo.jsonl --program guideline.rsl --as assistant:intake
```

Answer two questions from its application:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission answer peo.jsonl operation=peo years_in_operation=2 --as assistant:intake
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
  2  assistant:intake  answered operation = "peo"
  3  assistant:intake  answered years_in_operation = 2
stage: Ineligible
declines:
  PEO_NOT_ESTABLISHED  A PEO must be in operation for at least 3 years and be financially sound.
  the account stays open: correct an answer, or decline it with `close declined`
```

The answers break a rule that has a code, so the stage is `Ineligible`. A sign-off of `Declined`
gives the same stage. The `declines` block lists each rule and each sign-off that declines.

An `Ineligible` submission stays open, because a typing error and a true answer break a rule alike.
The log refuses `quote`, and it accepts two things:

* **A correction.** Answer the question again, and the stage follows the new answers.
* **A decision.** `close declined` turns the submission down for good.

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc submission close peo.jsonl declined --because "A PEO in its second year" --as uw:alice
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
  4  uw:alice  closed (declined) on PEO_NOT_ESTABLISHED because "A PEO in its second year"
stage: Declined
declines:
  PEO_NOT_ESTABLISHED  A PEO must be in operation for at least 3 years and be financially sound.
```

* `close declined` takes the role of the `quote` act, or a role above it.
* The entry lists, after `on`, each code that the decision rests on.
* In the `Open` and `Quotable` stages, the log refuses `close declined` as `NOT_DECLINABLE`.
* `Declined` is final, like `Bound` and `Closed`.

## Read the result from a program

Add `--json` to any command to get one JSON value on standard output. This Python reads the
status of both logs, then sends a write to the bound one:

```python theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
import json
import subprocess
import sys


def submission(*arguments):
    """Run `rslc submission ... --json`; return the exit code and the JSON value."""
    command = [sys.executable, "-m", "rslc", "submission", *arguments, "--json"]
    done = subprocess.run(command, capture_output=True, text=True)
    return done.returncode, json.loads(done.stdout)


code, report = submission("status", "submission.jsonl")
print(code, report["ok"], report["seq"], report["status"]["stage"])
# 0 True 13 Bound
print([(q["name"], q["outcomes"]["premium"], q["stands"], q["bound"]) for q in report["status"]["quotes"]])
# [('q1', 5000, True, False), ('q2', 5500, True, True)]

code, report = submission("status", "second.jsonl", "--at", "5")
print(code, [(q["question"], q["kind"], q["role"]) for q in report["status"]["open"]])
# 0 [('policy.experience', 'input', 'uw'), ('new_venture', 'signoff', 'manager')]

code, report = submission("answer", "submission.jsonl", "years_in_operation=3", "--as", "uw:alice")
print(code, report["ok"], report["refusal"]["code"])
# 2 False CLOSED

code, report = submission("status", "missing.jsonl")
print(code, report["ok"], sorted(report))
# 1 False ['error', 'ok']
```

`submission` is a helper that this page defines, in ordinary Python. A report holds `ok`, the
`applied` entries, the `refusal`, the last entry number `seq`, the `program` hash and the `status`.
[Submission log](https://docs.canary.effectiveai.app/rsl/reference/submission-log.md#json-output) lists every field.

A program that writes to a log needs the questions, the roles and the rules first.
`rslc submission contract submission.jsonl` prints them as one JSON value, and
[Submission log](https://docs.canary.effectiveai.app/rsl/reference/submission-log.md#the-contract) lists its parts.

## Exit codes

| Exit code | Meaning |
| - | - |
| `0` | The log applied the command, or `status` or `history` printed |
| `2` | The log refused the command; the output starts with `refused` and the refusal code |
| `1` | An error: a wrong command line, a missing log, or a program that fails its check |

These codes belong to `rslc submission`. For the other `rslc` commands, `2` marks a wrong command line.
[Submission log](https://docs.canary.effectiveai.app/rsl/reference/submission-log.md#refusal-codes) explains each refusal code.

## Replay a story with a script

A script file plays one submission from its first step and checks the results it expects. The
example's `stale.script` tells the story of the two sign-offs above:

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
# A correction lands between the manager's read and the sign-off: a sign-off based on
# the read before it is refused, and one based on a read that holds it stands.
program "guideline.rsl"
as assistant:intake
open
answer file "application.json"
as uw:alice
answer policy.experience = no_claims because "Loss runs, five years"
# The manager reads the submission here, at entry 6: two years in operation.
as assistant:agent
answer years_in_operation = 1 because "Corrected from the website"
as manager:morgan
refused STALE: based on 6: answer new_venture = Approved because "Two years, experienced owners"
based on 7: answer new_venture = Approved because "One year, experienced owners"
expect stage Quotable
```

Run it with `rslc script`:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc script stale.script
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
PASS stale.script: 7 steps, 0 failed, 8 log entries, stage Quotable
```

| Line | Meaning |
| - | - |
| `# text` | A comment |
| `program "guideline.rsl"` | The program, by its path from the script's folder |
| `as role:name` | The writer of the steps that follow |
| `open`, `answer`, `retract` | A step, written as the command is |
| `quote`, `bind`, `close` | A step, written as the command is |
| `answer ... in option` | A step in a quote option; `retract`, `quote` and `expect` take it too |
| `answer file "file.json"` | One answer for each top-level key of the file |
| `expect ...` | A check of the stage, the open questions, an outcome or a referral |
| `refused CODE: step` | A step that passes when the log refuses it with that code |
| `based on N: step` | A step that names the last entry its writer read |

* The script's log lives in memory. `--keep log.jsonl` writes it to a new log.
* `rslc script` exits with `0` when every step passes, and with `1` otherwise.
* [Submission log](https://docs.canary.effectiveai.app/rsl/reference/submission-log.md#script-files) gives every line form.

## Related

* [Write your first guideline](https://docs.canary.effectiveai.app/rsl/tutorial/first-guideline.md) builds the staffing guideline and works one submission step by step.
* [Raters and guidelines](https://docs.canary.effectiveai.app/rsl/explanation/raters-and-guidelines.md) explains why a sign-off lapses and why a quote keeps its name.
* [Submission log](https://docs.canary.effectiveai.app/rsl/reference/submission-log.md) lists every command, entry, stage and refusal code, and the contract.
* [Examples](https://docs.canary.effectiveai.app/rsl/reference/examples.md) shows each file of the staffing example.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.