Type to search pages and rules.

Browse pages

Maintaining the Standards

LiteSpec publishes each release as one complete contract, so the repository holding the standard needs its own operating rules. This page states them: how a provision, one identified obligation on a page, moves from draft to active to retired, how a rename replaces every citation of the old name in one change, and how a maintainer publishes a release from a git tag. The rules keep every provision identifier resolvable and every release reproducible from its tag.

Markdown7 rules

Stack: any

Layer: workspace

Concepts#

The Provision Lifecycle#

A provision passes through three states.

StateMeaning
draftThe provision is being written and has no verification line yet, so it cannot land.
activeThe provision carries its ID line and its verification line.
retiredThe provision no longer holds and nothing cites it.

A provision moves from draft to active when its verification line is written, and from active to retired when a richer provision folds its assertion in. It never moves back to draft, and retirement is permanent: a retired identifier stays gone, so a reader who meets one knows it names nothing current.

The Identifier#

Every provision ID is litespec/<page>#<slug> as its **ID:** line states it, as litespec/core/authoring#use-the-declared-identifier-grammar states. The ID line is the provision's identity: a heading may change without changing the ID. Within a major version, identifiers stay stable: a minor release adds provisions and changes wording, and removes or renames no identifier, so every citation written against that major version keeps resolving. A major release may remove or rename identifiers, and its changelog carries the generated list of every change. An identifier rename replaces the ID outright: the repository keeps no alias and no map from the old identifier to the new one. That is why an identifier rename replaces every citation in the same change.

Citations#

A citation names the cited provision by its current identifier, whether the citation sits on the same page or another one. Because no alias exists, a citation that names a retired identifier resolves nowhere, and litespec-maintain validate reports it.

The LiteSpec Release#

A LiteSpec release is a tagged snapshot of the repository, and the highest git tag names the current release. Between releases, five places name the release being prepared: the version in litespec.manifest.json, the topmost CHANGELOG.md entry, the consumer template's reviewedLiteSpecVersion, and the package versions in apps/cli/src/LiteSpec.Cli/LiteSpec.Cli.csproj and apps/analyzers/src/LiteSpec.Analyzers/LiteSpec.Analyzers.csproj. Tagging that version number makes it current. The manifest lists every stack, shape, extension, and version pin the release carries. Publishing the release puts the LiteSpec.Cli tool package, the LiteSpec.Analyzers package, and the site at the release version together, so the tool carries the manifest, schemas, docs, and templates the version names. A consumer upgrades by changing the tool version and reviewedLiteSpecVersion together. Each schema $id carries that release under https://litespec.dev/<version>/schemas/, so a consumer that pins the release keeps resolving the shapes it reviewed.

Release Diagnostics#

These checks report a manifest or schema the release cannot ship, so they are listed here instead of beside a provision.

FamilyMeaningCodes
MANIFEST_*The manifest is not valid JSON, names a path or anchor that does not exist, or lists a shape page twice.MANIFEST_JSON, MANIFEST_PATH, MANIFEST_ANCHOR, MANIFEST_DUPLICATE_PATH
SCHEMA_*A schema carries the wrong release $id, is not valid JSON, rejects its values, or uses a keyword the evaluator does not implement.SCHEMA_ID, SCHEMA_JSON, SCHEMA_INVALID, SCHEMA_UNSUPPORTED_KEYWORD

Standards#

State the Provision Lifecycle#

ruleruleguidance
litespec/core/maintaining#state-the-provision-lifecycle
Statement

A maintainer MUST keep each provision in exactly one of three states: draft, active, or retired.

Why

The three states tell a maintainer what an identifier promises. An active identifier names a rule that holds and that its verification line says how to check. A retired identifier names nothing, so a citation to it is a defect rather than a reference. Without the lifecycle, a half-written provision and a removed one look identical to a cited one.

Example

A provision is added in draft. When its verification line is written it becomes active. When its assertion is folded into a richer provision, the provision is retired.

Checka reviewer answers

Reviewed forEach provision sits in exactly one lifecycle state, with retired identifiers cited nowhere.

Marked guidance: a reviewer answers this question.

Replace Every Citation on a Rename#

rulerulecheckable
litespec/core/maintaining#replace-every-citation-on-a-rename
Statement

A provision rename MUST replace every citation of the old identifier in one change.

Why

An identifier rename changes the ID line, and the repository keeps no alias to catch stragglers. Every citation the rename misses names a provision that no longer exists, and readers follow it nowhere. Replacing all of them in one change keeps the repository resolvable at every commit. A heading reword leaves the identifier unchanged, so it needs no citation sweep.

Example

Renaming a provision identifier changes its ID line and every citation together.

Checkchecked by a tool

Checked bylitespec-maintain validate emits no ID_UNKNOWN_REFERENCE diagnostic.

Marked checkable: the tool named here checks it.

Keep Provision Identifiers Stable Within a Major Version#

ruleruleguidance
litespec/core/maintaining#keep-provision-identifiers-stable-within-a-major-version
Statement

A minor LiteSpec release MUST keep every provision identifier of its major version, adding provisions and rewording provision text without removing or renaming an identifier.

Why

Consumers cite provision identifiers in code marks, records, and exceptions, and each citation is written against the major version the project pins. A minor release that removes or renames an identifier breaks those citations inside a version line the consumer took as stable, with no major release to signal the break. A major release may remove or rename identifiers, and the generated provision diff in its changelog lists every added, removed and renamed identifier, so a consumer moving across a major version finds each change in one place.

Example

A release in the 4.x line adds litespec/core/scope#declare-the-conformance-level and rewords a neighboring provision; both keep their identifiers, so every mark and exception written against the 4.x line still resolves.

Checka reviewer answers

Reviewed forWhich provision identifiers did a minor release remove or rename? Compare the provision index at the previous tag with the provision index of the release, beside the changelog entry that lists the generated diff.

Marked guidance: a reviewer answers this question.

Publish a LiteSpec Release from a Tag#

rulerulecheckable
litespec/core/maintaining#publish-a-litespec-release-from-a-tag
Statement

A LiteSpec release MUST carry the highest git tag in the manifest version, the changelog entry, the consumer template version, and the tool and analyzer package versions.

Why

A git tag is the only durable artifact that names a release: branches move and files change, but the tag stays. Reading the current release from the highest tag gives maintainers, consumers, and tools one shared answer. Writing that version into the manifest, the changelog, the template, and the tool package in the same release keeps the four from disagreeing.

Checkchecked by a tool

Checked bydotnet test --solution LiteSpec.slnx fails ReleaseVersionTests when the changelog, the template, or either package version differs from the manifest version, and .github/workflows/release.yml refuses a tag that does not name the manifest version.

Marked checkable: the tool named here checks it.

List Every Stack Shape and Extension in the Manifest#

rulerulecheckable
litespec/core/maintaining#list-every-stack-shape-and-extension-in-the-manifest
Statement

The LiteSpec manifest MUST list every stack, shape, extension, and version pin the release carries.

Why

The manifest is the release record that tools read: stacks and shapes decide which pages apply, extensions decide which conditional bundles a project selects from, and pins decide which versions build. A stack, shape, extension, or pin the manifest omits is one no consumer selects and no tool resolves. Listing all of them in one file keeps the release reproducible from its tag.

Example

The Behavior extensions privacy, devices, automation, workflow-engine, pipeline, queues, and ai each appear with their page path and activation scope.

Checkchecked by a tool

Checked bylitespec-maintain validate fails when a stack, shape, extension, or pin the release carries is missing from the manifest.

Marked checkable: the tool named here checks it.

Mark the Tools with the Provisions They Follow#

rulerulecheckable
litespec/core/maintaining#mark-the-tools-with-the-provisions-they-follow
Statement

Every top-level class that declares a method in a .NET source project under apps/, and every test that verifies a provision, MUST name its provision in a mark: a follows mark on the class and a proves mark on the test.

Why

LiteSpec's own tools are technical classes: they serve no product record, and each exists because a provision requires a check, a reader, or a generator of its shape. A follows mark is the reverse index from that code to the provision, so a retired or renamed provision finds every class still built for it, and a proves mark finds the tests that keep its check honest. LiteSpec keeps the research and decisions behind its provisions as records under docs/intent/, in the shapes a consumer uses; its provisions remain its specification, and the marks point at them directly. The site under apps/site is TypeScript with no mark form in the maintainer tool, so it carries no marks.

Example

The .NET scenario reader carries /// <follows>litespec/core/model#name-the-lowest-record-each-test-proves</follows>, and the test that confirms a scenario driven through a shared probe step carries /// <proves>litespec/core/model#name-the-lowest-record-each-test-proves</proves>.

Checkchecked by a tool

Checked bylitespec-maintain validate emits MARK_MISSING for a class with a method and no follows mark in a source project under apps/, and MARK_UNRESOLVED for a follows or proves mark in a .NET project under apps/, outside its Fixtures folders, that names no provision in docs/reference/provisions.md.

Marked checkable: the tool named here checks it.

Record the Reasoning Behind Each Release#

rulerulecheckable
litespec/core/maintaining#record-the-reasoning-behind-each-release
Statement

A maintainer MUST keep the research and decisions behind each release as records under docs/intent/.

Why

Provisions state obligations without the questions, sources, or conclusions behind them, so a later change cannot tell why a rule reads as it does. Settled by decision/0001-keep-release-reasoning-as-records on the evidence in research/comparable-rationale-practice.

Example

Claimwick states its five-day reimbursement target in a provision, and the benchmark behind the number sits in a research record beside it.

Checkchecked by a tool

Checked bylitespec-maintain validate emits no RECORD_SCHEMA, RECORD_ID_MISMATCH, RECORD_SOURCE, RECORD_UNKNOWN_REFERENCE, or RECORD_DECISION_UNCITED diagnostic.

Marked checkable: the tool named here checks it.

Conventions#

None.

Reference Example#

This informative example demonstrates litespec/core/maintaining#state-the-provision-lifecycle, litespec/core/maintaining#replace-every-citation-on-a-rename, and litespec/core/maintaining#publish-a-litespec-release-from-a-tag.

Step One, Adding a Provision#

A maintainer writes a new provision on a page. The provision stays in draft until it carries its ID line and its verification line.

Text
### Submit Each Expense Once

**Statement:** A spender MUST submit each expense once.

**Rationale:** A second submission of one receipt pays it twice.

The validator reports the provision with no ID line and no verification line. The maintainer adds both, and the provision becomes active:

Text
### Submit Each Expense Once

**ID:** `litespec/core/example#submit-each-expense-once`

**Statement:** A spender MUST submit each expense once.

**Rationale:** A second submission of one receipt pays it twice.

**Reviewed for:** Which expense was submitted twice? Look at the submitted expenses for one receipt.

Step Two, Renaming#

A rule changes, so the maintainer updates the heading; the identifier stays. When the identifier itself must change, the maintainer replaces the ID line and every citation of it in one change. When the change lands, no citation names the old identifier.

Step Three, Releasing#

The maintainer runs git describe --tags --abbrev=0 to find the tag with the highest version number. That tag names the current release. The maintainer sets the manifest and tool package versions, writes the changelog entry for the release, and tags the commit with the new version number.