Skip to content

Example: Arguments

The arguments document is the contract for a console application's command line: every argument, the syntax forms the framework parser accepts, how validation behaves, and what the operator sees when resolution fails. Doc gen produces one per application at docs/applications/<app-slug>/arguments.md.

What reviewers should check

  • Every writable property on the argument container appears in the contract table, including properties that are bound implicitly rather than configured in BuildArgumentResolvers — an implicitly bound property is still part of the contract.
  • The Binding column is exactly Explicit (Setup) or Implicit (IConvertible), and an Explicit (Setup) row corresponds to a real builder.Setup(x => x.Property) call.
  • Required defaults to Yes: a No must be backed by a .NotRequired() or .NotRequired(default) call, and the Default column then shows that value rather than an em dash.
  • The accepted-syntax table keeps all five forms the parser supports and the flag and duplicate-key sentences, marked with † as inherited framework behaviour; trimming it to the -Name value form the scheduler happens to use is a defect.
  • Validation behaviour states that resolution runs before any application code and that failure exits with code 1 with no partial execution, and the application-specific subsection either lists real extra checks or says none exist.
  • The resolved-argument echo section says whether any argument value is a secret or PII, because the framework prints every resolved value to standard output.
  • The examples are runnable commands for this executable, covering the normal run and at least one alternate mode.

Example

The document below is a complete, correct console-arguments.md for a fictional .NET Framework console application.

View rendered example — the same document as a real page, so you can compare rendering as well as source.

---
title: Arguments
summary: Command-line argument contract, accepted syntax, validation, and failure behavior.
status: draft
owner: Policy Systems Team
last_reviewed: 2026-09-10
---

# Arguments

`SAIF.Policy.RenewalNotice` takes four arguments: the notice date and notice
type that define which policy terms are eligible, a batch size that caps the run,
and a `WhatIf` flag that suppresses delivery. The scheduled nightly task supplies
only `NoticeDate` and `NoticeType`; operators add `BatchSize` when working
through a backlog and `WhatIf` when validating a template change before a real
batch goes out.

Arguments are **named**, not positional. Each argument corresponds to a writable property on `Arguments` (`StandardArgumentContainerBase<Arguments>`); the property name is the argument name, matched case-insensitively.

## Invocation

```
SAIF.Policy.RenewalNotice.exe -NoticeDate 2026-09-18 -NoticeType Standard -BatchSize 500 --WhatIf
```

## Argument contract

| Argument | Property type | Required | Default | Binding | Validation | Purpose |
| --- | --- | --- | --- | --- | --- | --- |
| `NoticeDate` | `DateTime` | Yes | — | Explicit (`Setup`) | Parsed with the invariant culture; `yyyy-MM-dd` is the form the scheduled task passes. Rejected when later than the current date. | Anchors the notice window: terms whose renewal effective date falls between this date and this date plus the template's lead days are eligible. |
| `NoticeType` | `string` | Yes | — | Explicit (`Setup`) | Must be one of `Standard`, `NonRenewal`, or `Conditional`, compared case-insensitively. | Selects the `POLICY.NOTICE_TEMPLATE` row and the statutory lead days applied to the window. |
| `BatchSize` | `int` | No | 500 | Explicit (`Setup`, `.NotRequired(500)`) | Must be between 1 and 5000. | Caps the number of notices generated in one run so a backlog can be split across several runs. |
| `WhatIf` | `bool` | No | false | Implicit (`IConvertible`) | Converted by the framework; a value-less flag binds `"true"`. | Generates and logs notices without writing the print file, the queue row, or the `POLICY.RENEWAL_NOTICE` record. |

`WhatIf` is not configured in `BuildArgumentResolvers`. It is bound by
`HandleUnconfiguredArguments` because `bool` is `IConvertible`, which is why it
is optional and defaults to `false` without a `.NotRequired(...)` call.

## Accepted syntax

The parser (`SaifStandardCommandLineParser`, pattern `^-{1,2}|^/|:|=`) accepts all of these forms for every argument:†

| Form | Example |
| --- | --- |
| `-name value` | `-NoticeType Standard` |
| `--name` (flag) | `--WhatIf` |
| `/name` (flag) | `/WhatIf` |
| `name:value` | `NoticeDate:2026-09-18` |
| `name=value` | `BatchSize=250` |

A flag supplied with no value binds the string `"true"`. When a key appears more than once, the first occurrence wins.†

In practice this means `-WhatIf true`, `--WhatIf`, `/WhatIf`, `WhatIf:true`, and
`WhatIf=true` are equivalent, and that `-BatchSize 250 -BatchSize 1000` runs with
a batch size of 250. Matching is case-insensitive, so `-noticetype standard`
binds the same property as `-NoticeType Standard`.

## Validation and failure behavior

Validation runs in `ResolveArguments()` before any application code executes. On failure the messages are written to `Console.Error`, the process exits with code `1`, and `Initialize()`/`Execute()`/`Finish()` never run — there is no partial execution.†

| Condition | Message |
| --- | --- |
| Missing required argument | `NOTICEDATE is missing.` |
| Unparseable value | `NOTICEDATE '2026-13-01' is not a valid DateTime.` |

Because resolution precedes dependency registration, a failed command line never
opens the `policyDb` session, never calls `SAIF.Agency.Api`, and never touches
the print vendor drop path. All failures are reported together, so an operator
who mistypes both the date and the notice type sees both messages on the first
attempt.

### Application-specific validation

Two checks run beyond the resolver contract, both inside `Initialize()` and both
throwing `BadParameterException`, which also maps to exit code 1:

- `NoticeType` is matched against the `POLICY.NOTICE_TEMPLATE` rows for the
  current effective date. A value that parses as one of the three accepted
  strings but has no active template row is rejected here rather than failing
  mid-batch.
- `NoticeDate` is rejected when it is more than 30 days in the past, because a
  back-dated run would generate notices whose response window has already
  closed. Reprocessing an older night requires the notice date to be reset by
  the Policy Systems Team.

## Resolved argument echo

Each successfully resolved argument is echoed to standard output as `* Resolved argument - <ARGUMENT>: <value>`.† None of the four arguments carries a secret or
PII value, so the echo block is safe to include verbatim in an incident ticket. A
normal nightly run begins:

```
* Resolved argument - NOTICEDATE: 2026-09-18
* Resolved argument - NOTICETYPE: Standard
* Resolved argument - BATCHSIZE: 500
* Resolved argument - WHATIF: False
```

## Examples

| Scenario | Command |
| --- | --- |
| Nightly standard notice run | `SAIF.Policy.RenewalNotice.exe -NoticeDate 2026-09-18 -NoticeType Standard` |
| Non-renewal run with the statutory 60-day lead time | `SAIF.Policy.RenewalNotice.exe -NoticeDate 2026-09-18 -NoticeType NonRenewal` |
| Backlog run capped to 250 notices | `SAIF.Policy.RenewalNotice.exe -NoticeDate 2026-09-18 -NoticeType Standard -BatchSize 250` |
| Dry run to inspect a template change before delivery | `SAIF.Policy.RenewalNotice.exe -NoticeDate 2026-09-18 -NoticeType Conditional --WhatIf` |
| Alternate syntax accepted by the parser | `SAIF.Policy.RenewalNotice.exe NoticeDate:2026-09-18 NoticeType=Standard /WhatIf` |

## Related documentation
- [Application index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Run lifecycle](run-lifecycle.md)
- [Dependencies](dependencies.md)
- [Configuration](configuration.md)
- [Operations and processes](operations-processes.md)
- [Business rules](business-rules.md)
- [Data model](data-model.md)
- [Operational runbook](operational-runbook.md)
- [Tech debt](tech-debt.md)

## Sources
- `src/SAIF.Policy.RenewalNotice/Arguments.cs`
- `src/SAIF.Policy.RenewalNotice/Program.cs`
- `src/SAIF.Policy.RenewalNotice/RenewalNoticeApplication.cs`
- `deploy/scheduled-tasks/SAIF-RenewalNotice-Nightly.xml`