Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions scripts/affected_set.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
# crates/<pkg>/... the package + its reverse-dependency closure (cargo metadata)
# a CORE crate ALL (its closure is the workspace; naming it would only hide that)
# Cargo.toml of a crate ALL (a manifest edit changes features/deps, which no path can bound)
# docs/, root *.md, ci/ (sections.yml, explicit-test-commands.d/, ...), Cargo.lock, root Cargo.toml,
# rust-toolchain.toml, .cargo/, .github/, Makefile, any other path outside a crate
# ALL (tests read README.md, CLAUDE.md, ci/sections.yml and docs/ at run time)
# ci/ (sections.yml, explicit-test-commands.d/, ...), Cargo.lock, root Cargo.toml, rust-toolchain.toml, .cargo/, .github/, Makefile,
# any other path outside a crate ALL
# docs/, contracts/, root *.md READERS only (FLOW-010 b): their run-time readers are all in READERS. Exceptions, ALL:
# contracts binding.yaml, contracts model-families and the BUILD_CONTRACTS files (compiled into a crate)
# docs/findings/, .claude/, ci/shard-step-costs.tsv
# NO-READER list (#5809): the only run-time readers of these paths (grep of crates/**/*.rs: contracts-cli,
# orchestrate, core, mcp, apr-cli) are all in READERS, so the set is READERS alone. Alone or
Expand All @@ -32,7 +33,7 @@ set -euo pipefail
CORE="${AFFECTED_CORE:-aprender-core aprender-compute aprender-contracts apr-cli aprender-quant}"
# READERS = crates whose tests read OTHER crates' files at run time (CARGO_MANIFEST_DIR/.., crates/, ../<crate>). CORE ones are ALL on touch, but that does not put them in a non-ALL set; every non-ALL set includes them, because the touched crate may be what they read. scripts/check_affected_readers.sh
# goes RED on a reader this list (or CORE) lacks.
READERS="${AFFECTED_READERS:-apr-cli aprender-build-sha aprender-cbtop aprender-cgp aprender-ci-tools aprender-compute aprender-compute-xtask aprender-contracts aprender-contracts-cli aprender-contrastive-data aprender-core aprender-data aprender-db aprender-decide aprender-distribute aprender-explain aprender-gpu aprender-mcp aprender-orchestrate aprender-present-cli aprender-present-core aprender-present-lib aprender-present-terminal aprender-present-yaml aprender-profile aprender-qa-certify aprender-qa-cli aprender-qa-gen aprender-qa-report aprender-qa-runner aprender-quant aprender-rag aprender-registry aprender-review-experiment aprender-rollup aprender-serve aprender-shell aprender-simulate aprender-test-cli aprender-test-lib aprender-train aprender-train-distill aprender-train-inspect aprender-train-shell aprender-tsp aprender-update aprender-verify-ml aprender-viz aprender-viz-ttop facades}"
READERS="${AFFECTED_READERS:-apr-cli apr-format aprender-build-sha aprender-cbtop aprender-cgp aprender-ci-tools aprender-compute aprender-compute-xtask aprender-contracts aprender-contracts-cli aprender-contracts-macros aprender-contrastive-data aprender-core aprender-data aprender-db aprender-decide aprender-distribute aprender-explain aprender-gpu aprender-graph aprender-mcp aprender-orchestrate aprender-present-cli aprender-present-core aprender-present-layout aprender-present-lib aprender-present-terminal aprender-present-widgets aprender-present-yaml aprender-profile aprender-ptx-debug aprender-qa-certify aprender-qa-cli aprender-qa-gen aprender-qa-report aprender-qa-runner aprender-quant aprender-rag aprender-rag-cli aprender-registry aprender-review-experiment aprender-rollup aprender-serve aprender-shell aprender-simulate aprender-test-cli aprender-test-lib aprender-train aprender-train-bench aprender-train-distill aprender-train-inspect aprender-train-lora aprender-train-shell aprender-tsp aprender-update aprender-verify-ml aprender-viz aprender-viz-ttop aprender-zram aprender-zram-cli aprender-zram-generator facades}"
filter=0 from=""
while [ $# -gt 0 ]; do
case "$1" in
Expand All @@ -54,10 +55,18 @@ else meta="$(cargo metadata --no-deps --format-version 1 --offline 2>/dev/null |
root="${AFFECTED_ROOT:-$(git rev-parse --show-toplevel)}"
dirs="$(jq -r --arg root "$root/" '.packages[] | [.name, (.manifest_path | sub($root;"") | sub("/?Cargo.toml$";""))] | @tsv' <<<"$meta")" || { emit ALL; exit 0; }
[ -n "$dirs" ] || { emit ALL; exit 0; }
# Root contracts/ files that build.rs or include_str!/include! turn into compiled code or constants (aprender-serve build.rs generates
# arch/tensor-name code from three of them; apr-cli and mcp embed others). A change reaches dependents of the compiling crate, so these are ALL.
# check_affected_readers.sh derives this list from the tree and is RED on a file it omits.
BUILD_CONTRACTS="${AFFECTED_BUILD_CONTRACTS:-apr-mcp-tool-schemas-v1.yaml apr-model-capability-v1.yaml arch-constraints-v1.yaml architecture-requirements-v1.yaml kernel-fusion-v1.yaml layer-parity-v1.yaml softmax-kernel-v1.yaml tensor-names-v1.yaml thinking-budgets-v1.yaml}"
touched="" skipped=0
while IFS= read -r f; do
case "$f" in */*) ;; *.md) skipped=1; continue ;; esac # root *.md: its run-time readers are in READERS
case "$f" in contracts/*) case " $BUILD_CONTRACTS " in *" ${f#contracts/} "*) emit ALL; exit 0 ;; esac ;; esac
case "$f" in
'') continue ;;
contracts/binding.yaml | contracts/*/binding.yaml | contracts/model-families/* | contracts/*/model-families/*) emit ALL; exit 0 ;; # build inputs of core/compute/contracts/simulate/train: their generated code reaches dependents
contracts/* | docs/*) skipped=1; continue ;; # FLOW-010(b): run-time readers are in READERS
docs/findings/* | .claude/* | ci/shard-step-costs.tsv) skipped=1; continue ;;
crates/*/build.rs) emit ALL; exit 0 ;;
crates/*.rs) ;;
Expand Down
9 changes: 9 additions & 0 deletions scripts/check_affected_readers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,18 @@ hits() { # $1 = crates dir; prints crate names
| grep -vE '^[^:]*/target/' | grep -vE '^[^:]+:[0-9]+:[[:space:]]*//' \
| awk -F: -v allow=" $ALLOW " '{ k = $1 ":" $2; if (index(allow, " " k " ")) next; n = split($1, a, "/"); print a[2] }' | sort -u
}
build_listed() { sed -n 's/^BUILD_CONTRACTS="\${AFFECTED_BUILD_CONTRACTS:-\(.*\)}"$/\1/p' "$SET" | tr ' ' '\n' | grep -v '^$' | sort -u; }
# Root contracts/<file> that a build.rs names (any quoted *-vN.yaml) or an include*! macro embeds: compiled into a crate, so ALL.
build_inputs() { # $1 = crates dir; root contracts dir = ${CONTRACTS_DIR:-contracts}
{ grep -rhE --include=build.rs '[A-Za-z0-9_-]+\.yaml"' "$1" 2>/dev/null | grep -vE '^\s*//' | grep -oE '[A-Za-z0-9_-]+\.yaml"' | tr -d '"'
grep -rhE --include='*.rs' 'include(_str|_bytes)?!' "$1" 2>/dev/null | grep -vE '^\s*//' | grep -oE 'contracts/[A-Za-z0-9_-]+\.yaml' | sed 's#contracts/##'
} | sort -u | while read -r f; do [ -f "${CONTRACTS_DIR:-contracts}/$f" ] && echo "$f"; done | grep -v 'binding\.yaml$' || true
}
check() {
local bad="" l c; l="$(listed)"
for c in $(hits "$1"); do printf '%s\n' "$l" | grep -qx "$c" || bad="$bad $c"; done
local bl; bl="$(build_listed)"
for c in $(build_inputs "$1"); do printf '%s\n' "$bl" | grep -qx "$c" || bad="$bad contracts/$c(BUILD_CONTRACTS)"; done
if [ -n "$bad" ]; then echo "RED: crates can reach other crates' files but are not in READERS (scripts/affected_set.sh):$bad"; return 1; fi
echo "ok: every crate with a path-escape form is in READERS"
}
Expand Down
41 changes: 28 additions & 13 deletions scripts/check_affected_set.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# FLOW-010 E5 RED rows for scripts/affected_set.sh. Oracle for the closure is
# `cargo tree -i` (a different code path from the tool's cargo-metadata jq).
set -euo pipefail
export LC_ALL=C # sort order must match jq's codepoint order (apr-format vs aprender-*)
# the CI container runs as root over a host-owned checkout: git would refuse it (dubious ownership)
export GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=safe.directory GIT_CONFIG_VALUE_0='*'
A=scripts/affected_set.sh
Expand Down Expand Up @@ -47,12 +48,21 @@ row "docs/findings ledger alone -> READERS only, not ALL (#5809)" "$(printf '%s\
row ".claude agent-memory alone -> READERS only" "$(printf '%s\n' $readers | sort -u)" "$(run .claude/agent-memory/x/MEMORY.md | sort -u)"
row "shard cost table alone -> READERS only" "$(printf '%s\n' $readers | sort -u)" "$(run ci/shard-step-costs.tsv | sort -u)"
row "no-reader path next to a leaf .rs -> leaf + READERS" "$lc" "$(run docs/findings/s1.jsonl "$ld/src/lib.rs" | sort -u)"
row "no-reader path next to docs/x.md -> ALL" ALL "$(run docs/findings/s1.jsonl docs/x.md)"
row "no-reader path next to docs/x.md -> READERS only (FLOW-010 b)" "$(printf '%s\n' $readers | sort -u)" "$(run docs/findings/s1.jsonl docs/x.md | sort -u)"
row "no-reader path next to a CORE crate -> ALL" ALL "$(run .claude/x docs/findings/s1.jsonl crates/aprender-core/src/lib.rs)"
row "docs/findings lookalike (docs/findings-x.md) -> ALL" ALL "$(run docs/findings-x.md)"
row "docs file -> ALL (tests read docs/ at run time)" ALL "$(run docs/x.md)"
row "root README.md -> ALL" ALL "$(run README.md)"
row "root CLAUDE.md -> ALL" ALL "$(run CLAUDE.md)"
row "docs/findings lookalike (docs/findings-x.md) -> READERS only" "$(printf '%s\n' $readers | sort -u)" "$(run docs/findings-x.md | sort -u)"
row "docs file -> READERS only (their run-time readers are in READERS)" "$(printf '%s\n' $readers | sort -u)" "$(run docs/x.md | sort -u)"
row "contracts yaml -> READERS only" "$(printf '%s\n' $readers | sort -u)" "$(run contracts/foo-v1.yaml | sort -u)"
row "contracts/<x>/binding.yaml -> ALL (build input of core/compute/contracts/simulate/train)" ALL "$(run contracts/aprender/binding.yaml)"
row "serve build.rs input contracts/tensor-names-v1.yaml -> ALL" ALL "$(run contracts/tensor-names-v1.yaml)"
row "serve build.rs input contracts/architecture-requirements-v1.yaml -> ALL" ALL "$(run contracts/architecture-requirements-v1.yaml)"
row "serve build.rs input contracts/arch-constraints-v1.yaml -> ALL" ALL "$(run contracts/arch-constraints-v1.yaml)"
row "BUILD_CONTRACTS file next to a leaf .rs -> ALL" ALL "$(run contracts/tensor-names-v1.yaml "$ld/src/lib.rs")"
row "contracts/binding.yaml -> ALL" ALL "$(run contracts/binding.yaml)"
row "contracts/model-families -> ALL (aprender-core build.rs generates code from it)" ALL "$(run contracts/model-families/q.yaml)"
row "contracts yaml next to a leaf .rs -> leaf + READERS" "$lc" "$(run contracts/foo-v1.yaml "$ld/src/lib.rs" | sort -u)"
row "root README.md -> READERS only" "$(printf '%s\n' $readers | sort -u)" "$(run README.md | sort -u)"
row "root CLAUDE.md -> READERS only" "$(printf '%s\n' $readers | sort -u)" "$(run CLAUDE.md | sort -u)"
row "ci/sections.yml -> ALL (it holds the CI job bodies: editing it changes what CI runs, not only what tests read)" ALL "$(run ci/sections.yml)"
row "ci/explicit-test-commands.d fragment -> ALL" ALL "$(run ci/explicit-test-commands.d/815-affected-set-rows.cmd)"
row "a crate's own Cargo.toml -> ALL" ALL "$(run "$ld/Cargo.toml")"
Expand Down Expand Up @@ -98,17 +108,22 @@ else row "MUTANT: letting git detect renames is caught by the rename row" "c" "$
sed '/^ crates\/\*\/build.rs)/d' "$A" >"$t/mut-build.sh"
if cmp -s "$A" "$t/mut-build.sh"; then echo "FAIL build.rs mutant did not apply"; fail=1
else printf '%s\n' "$ld/build.rs" >"$t/db"; row "MUTANT: dropping the build.rs arm is caught by the build.rs row" "$lc" "$(bash "$t/mut-build.sh" --diff-from "$t/db" | sort -u || true)"; fi
# mutants: the skip list that used to exist (docs/*, *.md) must be caught by the ALL rows above.
sed 's#^ crates/\*.rs) ;;# docs/* | *.md) continue ;;\n crates/*.rs) ;;#' "$A" >"$t/mut-docs.sh"
if cmp -s "$A" "$t/mut-docs.sh"; then echo "FAIL docs-skip mutant did not apply"; fail=1
else printf '%s\n%s\n' docs/x.md "$ld/src/lib.rs" >"$t/dd"; row "MUTANT: skipping docs/*.md is caught by the docs-ALL row" "$lc" "$(bash "$t/mut-docs.sh" --diff-from "$t/dd" | sort -u || true)"; fi
# mutant: dropping the contracts build-input arm must be caught by the binding/model-families ALL rows
sed '/^ contracts\/binding.yaml /d' "$A" >"$t/mut-bind.sh"
if cmp -s "$A" "$t/mut-bind.sh"; then echo "FAIL binding mutant did not apply"; fail=1
else printf '%s\n' contracts/aprender/binding.yaml >"$t/db2"; row "MUTANT: dropping the binding/model-families ALL arm is caught" "$(printf '%s\n' $readers | sort -u)" "$(bash "$t/mut-bind.sh" --diff-from "$t/db2" | sort -u)"; fi
# mutant: the checker must go RED when a build.rs-read root contract is missing from BUILD_CONTRACTS
sed 's/ tensor-names-v1.yaml//' "$A" >"$t/mut-bc.sh"
if cmp -s "$A" "$t/mut-bc.sh"; then echo "FAIL build-contracts mutant did not apply"; fail=1
elif AFFECTED_SET_SH="$t/mut-bc.sh" bash scripts/check_affected_readers.sh >/dev/null 2>&1; then echo "FAIL MUTANT: a build.rs-read contract missing from BUILD_CONTRACTS is not caught"; fail=1
else echo "ok MUTANT: a build.rs-read contract missing from BUILD_CONTRACTS is caught by check_affected_readers.sh"; fi
# mutant: root-md arm that also skips crate-level .md must be caught by the leaf README row
sed 's#case "\$f" in \*/\*) ;; \*.md)#case "\$f" in *.md)#' "$A" >"$t/mut-md.sh"
if cmp -s "$A" "$t/mut-md.sh"; then echo "FAIL md mutant did not apply"; fail=1
else printf '%s\n%s\n' "$ld/README.md" "$ld/src/lib.rs" >"$t/dmd"; row "MUTANT: skipping crate-level .md is caught by the leaf README row" "$lc" "$(bash "$t/mut-md.sh" --diff-from "$t/dmd" | sort -u)"; fi
sed 's#^ crates/\*) emit ALL.*# crates/*) continue ;;#' "$A" >"$t/mut-toml.sh"
if cmp -s "$A" "$t/mut-toml.sh"; then echo "FAIL manifest mutant did not apply"; fail=1
else printf '%s\n%s\n' "$ld/Cargo.toml" "$ld/src/lib.rs" >"$t/dt"; row "MUTANT: skipping non-.rs crate files is caught by the manifest row" "$lc" "$(bash "$t/mut-toml.sh" --diff-from "$t/dt" | sort -u || true)"; fi
# mutant: a no-reader arm that also skips docs/* must be seen by the docs-next-to-no-reader row
sed 's#^ docs\/findings\/\* # docs/* | docs/findings/* #' "$A" >"$t/mut-nr.sh"
if cmp -s "$A" "$t/mut-nr.sh"; then echo "FAIL no-reader mutant did not apply"; fail=1
else printf '%s\n%s\n' docs/findings/s1.jsonl docs/x.md >"$t/dnr"; row "MUTANT: widening the no-reader list to docs/* is caught by the docs-next-to-no-reader row" "not-ALL" "$([ "$(bash "$t/mut-nr.sh" --diff-from "$t/dnr" | head -n1)" != ALL ] && echo not-ALL || echo ALL)"; fi
# CORE crates: each must give ALL, and dropping each from CORE must be seen (its dependents alone are not the workspace)
for c in aprender-compute aprender-contracts aprender-quant; do
cd_=$(jq -r --arg p "$c" '.packages[]|select(.name==$p)|.manifest_path' <<<"$meta" | sed "s|$(git rev-parse --show-toplevel)/||; s|/Cargo.toml||")
Expand Down