Policy Schema Export Automation

Audience: developers and release engineers who maintain the Policy Engine run contracts and the generated JSON Schema documents under docs/schemas/. TL;DR: run stella tools policy-schema-export (or the standalone exporter) to regenerate the schemas; there is no active CI job that does this for you today — see CI integration.

This utility generates JSON Schema documents for the Policy Engine run contracts (PolicyRunRequest, PolicyRunStatus, PolicyDiffSummary, PolicyExplainTrace).

Reconciliation note (verified against src/ on 2026-05-30): the exporter is a .NET command-line tool, not a shell script. The historical scripts/export-policy-schemas.sh referenced by older docs does not exist in the repository, and the CI job that invoked it now lives under .gitea/workflows-archived/ (i.e. it is not an active workflow). Sections below are marked where they describe archived/roadmap behavior rather than live automation.

Command

The exporter ships as the policy-schema-export subcommand of the StellaOps CLI tools group (src/Cli/StellaOps.Cli/Commands/ToolsCommandGroup.cs):

stella tools policy-schema-export [--output <dir>] [--repo-root <dir>]

Options (from src/__Libraries/StellaOps.Policy.Tools/PolicySchemaExporterCommand.cs):

The command logic (option parsing, the policy-schema-export verb, and the export Runner) all live in the shared StellaOps.Policy.Tools library (src/__Libraries/StellaOps.Policy.Tools/), which both the CLI subcommand and the standalone tool reference.

A standalone executable equivalent is also available at src/Tools/PolicySchemaExporter/ (entry point Program.cs calls PolicySchemaExporterApp.RunAsync):

dotnet run --project src/Tools/PolicySchemaExporter -- [--output <dir>] [--repo-root <dir>]

When no --output directory is supplied, schemas are written to the repo’s docs/schemas/ directory (see PolicySchemaExporterPaths.ResolveDefaultOutputDirectory, which resolves <repo-root>/docs/schemas). The repo root is located by walking up until src/Directory.Build.props is found; if it cannot be resolved and no --output is given, the tool exits with code 64 (EX_USAGE). If the resolved output directory cannot be created (e.g. the path is an existing file, or directory creation throws), the tool exits with code 73 (EX_CANTCREAT).

The exporter builds schemas against StellaOps.Scheduler.Models (PolicySchemaExporterSchema.BuildExports) and emits:

Schemas are generated with NJsonSchema (SchemaType.JsonSchema) using camelCase property names, additionalProperties: false (AllowAdditionalProperties = false), and NullValueHandling.Ignore. Each generated schema’s title is set to the source type name, and each file is written with a single trailing \n (LF, not CRLF — asserted by PolicySchemaExporterRunnerTests.RunAsync_WritesLfLineEndingsAsync).

CI integration (ARCHIVED — not currently wired)

Status: not active. The job below was defined in .gitea/workflows-archived/build-test-deploy.yml (job step Export policy run schemas) and is no longer part of the active .gitea/workflows/ set. It also invokes scripts/export-policy-schemas.sh, which is missing from the repo, so the archived job would fail if re-enabled as-is. The description is retained for historical context and as the basis for any future re-implementation.

As archived, the job:

CI integration checklist

The following reflects current source reality, not the archived workflow’s checkboxes:

Note: As of this reconciliation the four generated *.schema.json files are not committed under docs/schemas/ (only policy-pack-v2.schema.json is present there), so a fresh export will create them. Verify the intended commit location before wiring any diff-based gate.