Shared traceability tooling, generalised for every component
Moves the extractor, its tests and the gate from scene-actor-extraction into the project home, so all three components run one implementation rather than each growing its own. The gate logic is unchanged; what changes is that the two repo-specific constants become arguments. Both were hard blockers rather than inconveniences. LOCAL_TYPES was fixed at the extraction set, so a register using UR/DR parsed to zero requirements; SOURCE_SUFFIXES covered C++/Python only, so a Rust or C# tree scanned zero files. The gate correctly refuses to report coverage in either state, which is how both surfaced. They are now --types, --suffixes and --scan-roots, with the extraction defaults preserved: that repo runs unchanged with no flags. traceability-gate.sh gains REPO_ROOT, REQUIREMENTS, TYPES, SUFFIXES and SCAN_ROOTS environment overrides. Its REPO_ROOT default of SCRIPT_DIR/../.. is correct when the tooling sits in the repo it checks, but resolves to the submodule itself once vendored, so a consuming repo must set it. Fixes a latent bug found while testing the override: iter_source_files bound SCAN_ROOTS as a default argument, evaluated at import, so configure_scan_roots could never affect it. 58 tests pass. The two that read a live register now take LIVE_REGISTER from the environment and skip without it — they asserted against AR-012/AR-027, which belong to scene-actor-extraction rather than to a shared tool. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Executable
+89
@@ -0,0 +1,89 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Requirement traceability gate. Run locally exactly as CI runs it:
|
||||
#
|
||||
# scripts/traceability/traceability-gate.sh
|
||||
#
|
||||
# Writes traces-report.json and docs/traceability.md, prints the coverage
|
||||
# report, and exits non-zero when the gate fails.
|
||||
#
|
||||
# Environment:
|
||||
# MIN_COVERAGE minimum overall coverage percent (default 0 - see below)
|
||||
# ALLOW_ORPHANS set to 1 to report orphan tags without failing
|
||||
# TRACES_JSON JSON report path (default traces-report.json)
|
||||
# TRACES_MD markdown matrix path (default docs/traceability.md)
|
||||
# REPO_ROOT repository to scan. Defaults to two levels above this
|
||||
# script, which is correct when the tooling lives in the repo
|
||||
# it checks. **When vendored as a submodule that default is
|
||||
# the submodule itself**, so a consuming repo must set this —
|
||||
# its wrapper does.
|
||||
# TYPES comma-separated requirement prefixes (e.g. UR,DR). Defaults
|
||||
# to the extraction set; a repo whose prefixes differ parses
|
||||
# to zero requirements without this.
|
||||
# SUFFIXES comma-separated file extensions (e.g. .rs). Defaults to the
|
||||
# C++/Python set; a repo whose language differs scans zero
|
||||
# files without this.
|
||||
# SCAN_ROOTS comma-separated directories to walk, relative to REPO_ROOT.
|
||||
# SYSTEM_SPEC optional path to the system SPEC.md, which defines the PR/SR
|
||||
# IDs; when given, PR/SR orphans are reported too. It lives in
|
||||
# the project home (jray-project) — when this tooling is
|
||||
# vendored from there, it is a sibling of this script.
|
||||
#
|
||||
# Threshold policy lives here and nowhere else. It is deliberately NOT
|
||||
# duplicated into the workflow YAML: a threshold written in two places is a
|
||||
# threshold that will disagree with itself.
|
||||
#
|
||||
# MIN_COVERAGE defaults to 0 because almost nothing is tagged yet - tags are
|
||||
# added as the pipeline is built, so a low number today is accurate rather than
|
||||
# alarming. A zero threshold does NOT mean the gate cannot fail: orphan tags,
|
||||
# a >100% ratio, a register that parses to nothing, and an empty source scan
|
||||
# are all hard failures from day one. Raise MIN_COVERAGE as tags land; treat
|
||||
# every raise as a ratchet, never a reset.
|
||||
#
|
||||
# POSIX sh, no bashisms, no jq - the extractor does its own arithmetic and
|
||||
# printing so CI needs nothing beyond python3.
|
||||
|
||||
set -eu
|
||||
|
||||
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
REPO_ROOT="${REPO_ROOT:-$(CDPATH= cd -- "$SCRIPT_DIR/../.." && pwd)}"
|
||||
|
||||
MIN_COVERAGE="${MIN_COVERAGE:-0}"
|
||||
TRACES_JSON="${TRACES_JSON:-$REPO_ROOT/traces-report.json}"
|
||||
TRACES_MD="${TRACES_MD:-$REPO_ROOT/docs/traceability.md}"
|
||||
|
||||
PYTHON="${PYTHON:-python3}"
|
||||
command -v "$PYTHON" >/dev/null 2>&1 || {
|
||||
echo "FAILED: $PYTHON not found. The traceability gate needs Python 3.9+" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
set -- \
|
||||
--root "$REPO_ROOT" \
|
||||
--requirements "${REQUIREMENTS:-$REPO_ROOT/docs/requirements.md}" \
|
||||
--format coverage \
|
||||
--json-out "$TRACES_JSON" \
|
||||
--markdown-out "$TRACES_MD" \
|
||||
--min-coverage "$MIN_COVERAGE"
|
||||
|
||||
if [ "${ALLOW_ORPHANS:-0}" = "1" ]; then
|
||||
set -- "$@" --allow-orphans
|
||||
fi
|
||||
|
||||
if [ -n "${SYSTEM_SPEC:-}" ]; then
|
||||
set -- "$@" --system-spec "$SYSTEM_SPEC"
|
||||
fi
|
||||
|
||||
if [ -n "${TYPES:-}" ]; then
|
||||
set -- "$@" --types "$TYPES"
|
||||
fi
|
||||
|
||||
if [ -n "${SUFFIXES:-}" ]; then
|
||||
set -- "$@" --suffixes "$SUFFIXES"
|
||||
fi
|
||||
|
||||
if [ -n "${SCAN_ROOTS:-}" ]; then
|
||||
set -- "$@" --scan-roots "$SCAN_ROOTS"
|
||||
fi
|
||||
|
||||
exec "$PYTHON" "$SCRIPT_DIR/extract_traces.py" "$@"
|
||||
Reference in New Issue
Block a user