ULC v1.2.0
ulc CLI v1.2.0
Download a single-file binary for your platform below. See CHANGELOG.md
at the tag for what landed in this release.
A new CLI subcommand, ulc scope, that exports the conformance rubric's applicability determination as a versioned JSON document. The rubric is already class-aware: when grading a record it decides which blocks and graded items apply to that product class and which do not, and until now that decision was internal. Exposing it in result form lets any tool built on the CLI present, collect, or check the right fields without re-deriving the rubric, and keeps the rubric the single source of that judgement. This release is purely additive: no conformance grade moves, no computed index changes, there is no schema or taxonomy change, and neither the exit code nor the output of ulc validate or ulc build-index changes. Every golden file is byte-identical, and no example record changed a byte.
For consumers
Nothing to do. Records, indices, and existing tooling are unaffected; the new subcommand is entirely opt-in. If you build on the CLI, ulc scope <record.ulc> now prints a manifest naming that record's in-scope blocks and graded items, each with the rubric's own path, source document, and governing standard, so scope minus the gaps ulc validate reports gives you the satisfied set.
That join works because item identity is stable. Identity is the (tier, path) pair, and the path, source_document, and standard values are stable identifiers shared verbatim with conformance/gap findings, so you may key on them and match the two surfaces by string equality. A few paths are graded at two tiers, which is why identity is the pair, but path is unique within any single manifest, so a per-record join on path alone is sound. New items may appear at a ULC minor; an existing item's identity does not change.
The manifest carries its own contract version, scope_version, starting at 1.0.0 and independent of both the CLI version and the index builder version. It is additive-only: the minor bumps when fields, kind values, or arrays are added, you must ignore any tier or kind value you do not recognize, and no existing field, key string, item identity, or semantic changes for the lifetime of scope_version 1.x. That stability statement is scoped to scope_version; the ULC version line governs the schema surface (see ROADMAP.md), which the manifest is not part of. items carries gating rows only and always will; if the non-gating enrichment guidance is ever exported it arrives in a separate array, so a loop over items stays correct.
Two cautions. blocks is a rollup, not a judgement: a named block means at least one in-scope item's evidence lives there, never that the whole block is graded, and attestations appears in every manifest because the safety-listing row is universal. And record_id and ulc_version are echoed from a record that has passed no schema validation, so treat both as untrusted strings: never a filesystem path, a cache key, or a trust anchor. They are echoed rather than dropped so that concatenating manifests across a corpus keeps the record pairing. Every other field is a static rubric or CLI string.
Validator
- New subcommand
ulc scope <record.ulc>, which prints one JSON document on stdout and takes no flags. The envelope carriesscope_version,cli_version, andrecord_idandulc_versionechoed from the record when it holds a non-empty string there.blocksis a derived rollup, the sorted union of the top-level blocks the in-scope items' evidence lives in;itemsis authoritative. Each item carriestier(core,standard, orfull),kind,path,source_document, andstandard, using the rubric's own path strings, the same onesconformance/gapfindings already emit, so the two surfaces can never disagree on identity. kinddescribes the form of the path string only, with three values:pointer, a JSON Pointer naming the graded location, which may be a leaf, an object, or an array;choice, a pointer carrying an alternative where either location satisfies; andrequirement, a prose label for a requirement no single pointer names. An item states no presence or satisfaction state.- The manifest covers the gating tiers only. The non-gating enrichment and observation guidance stays where it is, in
ulc validate. It is also distinct from the record'sapplicabilityblock, which declares the range of orderable SKU configurations. cli_versionidentifies the binary, not the rubric: it equals the ULC release for a release binary and is a development placeholder for a build from source.- Exit codes: 0 when a manifest is emitted or
-his given; 1 when the record cannot be read, parsed, or used as a ULC record, or the manifest cannot be written, always with a diagnostic on stderr; 2 on a usage error. A read, parse, or encode failure writes nothing at all to stdout, since the document is encoded in full before any of it is written; only a write failure itself can leave a partial document, which no buffering can prevent. The subcommand runs no schema validation and reads nothing but the record, so it is report-time only. - The manifest is two-space-indented JSON with a trailing newline, and escapes
<,>and&.ulc build-index --stdoutis unchanged and still does not escape them, because its output must preserve the record's own byte shape. ulc from-sheetnow treats an A1 column reference beyondXFD, the format's maximum column, as malformed and skips its cell, the same handling a reference carrying no column letters already receives. No workbook a spreadsheet application can author reaches that bound, so conversion output is unchanged for every legal workbook.
Docs
tools/validator/README.md: the shipped-features checklist gains theulc scopeentry and the column-reference clause.tools/README.md: theulcsubcommand inventory now lists four subcommands.docs/how-it-works.md: the CLI walkthrough namesulc scope <record>.docs/methodology.md: the applicability-predicates section records that the determination is also exported in result form.README.md: the current-release version line.ROADMAP.md: the active-version heading now names the current line, the applicability item moves out of deferred work because this release ships it, and the deferred list gains theulc validate --jsonescaping-consistency item.