Status: accepted. This document defines the implementation for
issue wavenumber-eng/wn-dev-std#13.
The durable governance records are core-adr-0006 and
core-req-0006.
The existing artifact, vendor, and release governance checks validate committed catalogs and tracked source-controlled artifact candidates. That default behavior is correct for normal development because local build products are transient and often ignored by Git.
Release signoff needs a stricter path. When a release is being prepared, maintainers need an audit that inspects the actual payload files selected for promotion and proves they match the authored release-channel contract.
The implemented CLI shape is an audit mode on the existing
audit command:
dev-std audit . --scope docs.release --mode release
The default audit mode remains the current source-governance behavior. Release mode is opt-in and normally runs from an explicit release signoff lane after artifacts have been built.
In this implementation, --mode release only changes the
behavior of the selected docs.release scope. Other scopes run
with their normal behavior. A call with no --scope, or with
--scope all, selects docs.release as part of the
full audit and therefore runs release payload inspection. A call that
selects only non-release scopes accepts the mode but performs no release
payload inspection.
Release artifact declarations live under the release channel that promotes
them. The contract uses nested
[[channels.promoted_artifacts]] tables in
docs/governance/release.toml.
[[channels]]
id = "pypi"
kind = "pypi"
status = "active"
owner = "release"
process_doc = "docs/setup.html"
build_doc = "docs/build.html"
[[channels.promoted_artifacts]]
id = "wheel"
kind = "package_distribution"
paths = ["dist/wn_dev_std-*.whl"]
required = true
build_profile = "release"
license_refs = ["LICENSE"]
Entries may use an exact path or bounded paths
pattern set. Required entries must resolve to at least one produced file.
Optional entries may be absent but must pass all metadata checks when
present.
Date-versioned packages use bounded globs such as
dist/wn_dev_std-*.whl rather than committed literal wheel
filenames. Literal version, source_commit, and
sha256 fields are reserved for pinned or already-promoted
payloads where that metadata is known before the catalog change is
committed. When declared, version is compared to the audited
package version from pyproject.toml,
source_commit is compared as a prefix of
git rev-parse HEAD, and sha256 is computed from
the matched file. A single sha256 requires an exact path or a
pattern that resolves to exactly one file.
destination is optional and channel-relative. It does not
duplicate the parent channel kind. It may identify a GitHub release asset
name, an object-store key prefix, an app/plugin bundle slot, or another
sub-destination inside the configured channel.
Default mode shape-validates any
[[channels.promoted_artifacts]] tables without touching local
payload files. That validation includes unique artifact ids per channel,
known artifact kinds, boolean required values when present,
bounded path or pattern declarations, valid license refs, and path
containment inside the audited package root.
Release mode validates path containment before reading local files. It
fails required missing artifacts, uncataloged files under
configured promoted roots, checksum mismatches when sha256 is
declared, version mismatches when version is declared, and
source-commit mismatches when source_commit is declared.
Missing-required and metadata checks are channel-scoped. Uncataloged
payload detection is catalog-wide so channels sharing a staging root such
as dist/ do not flag each other's declared files.
Native, WASM, app/plugin, and object-store payloads carry target, build-profile, ABI/runtime, destination, and license notes so reviewers can distinguish intentional optional targets from missing release payloads.
Promoted roots are derived from each declared exact path or glob by taking
the static directory prefix before the first wildcard. Exact file entries
use their parent directory. The audit enumerates files below those roots
and matches repository-relative POSIX paths with fnmatch
semantics, matching the existing artifact catalog coverage behavior where
* can cross directory separators. Uncataloged-payload
detection is therefore based on the same catalog-wide pattern semantics
used to decide whether a declared artifact is covered.
Workspace roots remain aggregators. A release-mode workspace audit runs the
selected release-mode checks inside each registered member package.
Each member resolves docs/governance/release.toml and
promoted artifact paths relative to its own package root. Workspace-level
catalogs are not part of the first implementation.
The release-mode audit does not upload artifacts, publish releases, sign files, generate checksums, or replace tools such as Twine, GitHub Release upload actions, object-storage sync tools, or package-manager clients. It checks that the produced local payload set is consistent with the authored release catalog.
The implementation keeps the mode plumbing small: parse the mode in
dev-std audit, thread it through audit execution, and add
release-mode artifact inspection to docs.release. Shared
artifact kinds live in src/wn_dev_std/artifact_policy.py, and
promoted payload declaration and file inspection live in
src/wn_dev_std/release_artifacts.py. Tests prove
the default mode still ignores local build output while default release
governance catches invalid promoted-artifact table shape, and release mode
fails missing required artifacts, uncataloged promoted files, stale
checksums, version mismatches, source-commit mismatches, path escapes, and
shared-root channel regressions.
The implementation slice must update the audited public documentation
surfaces together with code: docs/design/audit-standard.html,
docs/design/artifact-vendor-governance.html,
docs/design/cli.html, CLI help tests, release catalog tests,
and version/release metadata when the change is prepared for release.