diff --git a/contracts/dogfood-runner-unification-v1.yaml b/contracts/dogfood-runner-unification-v1.yaml index 2b12f57d69..c03af9181f 100644 --- a/contracts/dogfood-runner-unification-v1.yaml +++ b/contracts/dogfood-runner-unification-v1.yaml @@ -9,6 +9,7 @@ metadata: - 'scripts/check_verifier_pinning.sh — the gate: static scan + behavioural probe of both pins' - 'scripts/check_dogfood_shim.sh — the gate: one runner, one prose, and the user-scope copy stays a gated shim' - 'scripts/check_dogfood_row_order.sh — the guard (report mode until three green nights): long rows last, no early stop, a red cheap row keeps the verdict red, row times (aprender#4672)' + - 'scripts/check_dogfood_reads_ci.sh + scripts/release/sha_checks.sh — pre-publish reads fmt and test from the CI of the same commit and coverage from the receipt cut_tag requires (tag_coverage_gate.sh --resolve); no green receipt for that sha is red; clippy stays measured (aprender#4672)' - 'scripts/.dogfood-shim-reference.sh — the reviewed text of the user-scope shim' - '.claude/skills/dogfood/SKILL.md — the one canonical prose, with an explicit `name:` (#2332)' - 'aprender#2361 — a user-scope skill shadowed the repo one; hardening it edited a file that never ran' @@ -443,6 +444,37 @@ falsification_tests: test: 'bash scripts/check_dogfood_row_order.sh --self-test # the five timing rows' if_fails: 'a release-day check over its budget passes its own timing row, or a missing measurement reads as on time' mutation: 'the six planted timing rows (ok, over, at budget, hole, absent, a budget of 15m) must give rc 0, 1, 0, 2, 2, 2 (observed 2026-10-04)' +- id: F-DOG1-032 + rule: in --phase pre-publish, fmt and test read the commit's CI and coverage reads the receipt cut_tag requires; none re-runs; clippy stays measured + prediction: > + In scripts/dogfood.sh the fmt and test rows are ci_mark calls inside the pre-publish + branch (fmt reads `ci / gate`, test reads `workspace-test`), and the coverage row is + cov_mark, which PASSes only when `tag_coverage_gate.sh --resolve HEAD` exits 0: the + coverage-nightly receipt (#4734) that autopilot cut_tag already requires before the tag. + Their measuring commands sit only in that branch's else, so every other phase still + measures them. clippy is measured in every phase, because the `ci / gate` lint is + narrower (default features, unused-variables allowed, a lib-only fallback). + `workspace-test` is nextest --lib over the workspace; the root facade's doctests and + bin tests are not in it. Reviews and a C314 round on aprender#4886 settled these. + test: 'bash scripts/check_dogfood_reads_ci.sh # R2' + if_fails: 'the release dogfood re-runs work CI already did for the same commit, a row reads the wrong check, clippy reads a narrower lint, or pre-publish passes a coverage row it never read' + mutation: 'put `gate fmt` back in pre-publish (rerun), point test at `ci / gate` (wrongspec), read clippy from CI (clippyread), pass coverage unread (covpass), drop the coverage row (covmissing); each must turn RED (observed 2026-10-06 in --self-test)' +- id: F-DOG1-033 + rule: no green receipt for the exact sha is RED, never a skip + prediction: > + The runner's own CI-read block, ci_mark() and cov_mark(), lifted and driven against + planted check rows and a planted coverage reader for a real commit, give PASS only + when each check, or the coverage receipt, is green for THAT sha, and FAIL on a red + check for the sha, a missing check, a green check on a different sha, a refused or + other-sha coverage receipt, a failed GitHub read, missing readers and a tree with + uncommitted tracked changes. scripts/release/sha_checks.sh holds the same rule on its + own (newest run wins, a queued rerun counts as newest, runs that disagree at one start + time are red, pending, cancelled and skipped are red, a same-named check in another + workflow does not count); tag_coverage_gate.sh --self-test holds it for coverage (no + receipt, other sha, below COV_FLOOR, gh failing). + test: 'bash scripts/check_dogfood_reads_ci.sh --self-test; bash scripts/release/sha_checks.sh --self-test; bash scripts/release/tag_coverage_gate.sh --self-test' + if_fails: 'a check or receipt that is red, absent, or for another commit lets the release dogfood say GO' + mutation: 'let a dirty tree read HEAD (nodirty), make the no-receipt fallback a PASS (skipread), pass a refused coverage receipt (covskip), resolve another sha (covwrongsha); each must turn RED; sha_checks.sh plants 21 rows (observed 2026-10-06)' proof_obligations: - id: DRU-INV-001 type: invariant diff --git a/evidence/pr-review/4886/6bac6be648bdcee2c8b8c0c7c640d1419d34703b/findings.sarif b/evidence/pr-review/4886/6bac6be648bdcee2c8b8c0c7c640d1419d34703b/findings.sarif new file mode 100644 index 0000000000..76193371c7 --- /dev/null +++ b/evidence/pr-review/4886/6bac6be648bdcee2c8b8c0c7c640d1419d34703b/findings.sarif @@ -0,0 +1,136 @@ +{ + "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json", + "version": "2.1.0", + "runs": [ + { + "tool": {"driver": {"name": "pmat"}}, + "invocations": [{"executionSuccessful": true, "toolExecutionNotifications": []}], + "results": [ + { + "ruleId": "duplication_scan_no_hits", + "level": "note", + "message": {"text": "The lexical duplication scan over head, all 1540 unmerged sibling branches and the merge-base-to-main range (0 files) found 0 hits for the 13 symbols the diff adds. The diff changes no Rust file, so the pmat semantic index (Rust-only) was queried but cannot reach it."}, + "properties": { + "grounding": "measured", + "command": ["bash", "scripts/pr_review_duplication_scan.sh", "--base", "88bf12c8710dd29617a28add806a37c3edac42d2", "--head", "6bac6be648bdcee2c8b8c0c7c640d1419d34703b", "--json", ""], + "exit_code": 0, + "stdout_sha256": "35d6586b94bd0567dd5909f59e9a6a8041e90d521e3fdcd466b93441535574fc", + "failure_scenario": "A re-implementation under a different name is invisible to a name match; that residual is not covered.", + "precision_class": "advisory" + } + }, + { + "ruleId": "diff_patch_id_run_by_parent", + "level": "note", + "message": {"text": "diff_patch_id 30be26cb97a09421c8df64ea78e5fa9bd2505a7d over 88bf12c871..6bac6be648 (evidence/pr-review/4886/ excluded) was computed by the PARENT session, not by this lane, under a cop ruling: subagent-lock.sh exempts the parent by design. Control by the parent: the same function over e95ae8280f..deb4f19d5e gives 6ff6a07990, equal to the A2 line CI printed. The stdout_sha256 here is the digest of the reported id plus a newline, taken by this lane from the value relayed to it; this lane did not observe that stdout."}, + "properties": { + "grounding": "measured", + "command": ["bash", "-c", ". scripts/lib/pr_review_patch_id.sh && prpid_compute 88bf12c8710dd29617a28add806a37c3edac42d2 6bac6be648bdcee2c8b8c0c7c640d1419d34703b 4886"], + "exit_code": 0, + "stdout_sha256": "4ea3e412e1fbb421c8243f3851823ac59632a5d513949ef8636ebfb92f6aa850", + "failure_scenario": "If the relayed id were wrong, Arm 4 would find no receipt bound to the subject diff and refuse the merge, so the error cannot arm a merge that should not land.", + "precision_class": "advisory" + } + }, + { + "ruleId": "lane_hook_refusals", + "level": "note", + "message": {"text": "This lane was refused by the PreToolUse hook subagent-lock.sh (a review lane runs read-only git only) on two git subcommands: patch-id (via prpid_compute) and archive (the disposable tree for the agy lane). Neither was routed around: the patch-id was relayed by the parent; the disposable tree was built with tar from the clean worktree (tracked files, no .git, with evidence/, target/ and .pmat/ left out), a file copy and not a git operation."}, + "properties": { + "grounding": "asserted", + "rationale": "The refusals are the hook output this lane received verbatim; no command ran, so there is no exit code or stdout to measure.", + "failure_scenario": "A reader of the receipt would otherwise take the tar-built agy workspace for a git-archive tree, and the patch-id for one this lane computed.", + "precision_class": "advisory" + } + }, + { + "ruleId": "dead_elif_pre_publish_coverage", + "level": "warning", + "message": {"text": "scripts/dogfood.sh line 1857, `elif [ \"$DOGFOOD_PHASE\" = pre-publish ]`, sits inside the `else` (line 1819) of the new `if [ \"$DOGFOOD_PHASE\" = pre-publish ]` at line 1816, which closes at line 1865. It can never be true, so the #3957 F1b branch and its FAIL message are dead code; pre-publish coverage is now decided only by cov_mark."}, + "properties": { + "grounding": "measured", + "command": ["sed", "-n", "1816p;1819p;1857p;1865p", "scripts/dogfood.sh"], + "exit_code": 0, + "stdout_sha256": "24dcf29e1f7cec413070882991cd914f534409f6da1bbcee4e21703639b01afa", + "failure_scenario": "A later edit trusts the F1b branch (coverage below floor in pre-publish is RED with its owed-by message) to run; it does not.", + "precision_class": "advisory" + } + }, + { + "ruleId": "ci_read_narrower_than_measured_test", + "level": "note", + "message": {"text": "In pre-publish the test row reads `workspace-test` (nextest --lib over the workspace) where the replaced row ran `cargo test $FEATS` (doctests, integration targets, bin tests). The runner comment in the 2c block discloses this; the receipt row says only `read, not re-run`."}, + "properties": { + "grounding": "asserted", + "rationale": "Taken from the diff comment in scripts/dogfood.sh and CLAUDE.md Testing (only a subset of integration targets is wired into CI). Not measured by running anything.", + "failure_scenario": "A doctest or integration-only failure that CI does not run passes the pre-publish test row.", + "precision_class": "advisory" + } + } + ] + }, + { + "tool": {"driver": {"name": "cargo-mutants"}}, + "invocations": [{"executionSuccessful": true, "toolExecutionNotifications": []}], + "results": [ + { + "ruleId": "committed_plants_killed", + "level": "note", + "message": {"text": "All 9 committed planted defects of check_dogfood_reads_ci.sh are killed (--self-test exits 0); sha_checks.sh --self-test is 21/21."}, + "properties": { + "grounding": "measured", + "command": ["bash", "scripts/check_dogfood_reads_ci.sh", "--self-test"], + "exit_code": 0, + "stdout_sha256": "542142ef51e2f92a7d6370d1e99d028e0e81b1e4b2ef29ee09f04a2e63adb258", + "failure_scenario": "If a plant survived, a runner defect the guard claims to catch would pass unnoticed.", + "precision_class": "advisory" + } + }, + { + "ruleId": "extra_mutant_cov_inverted_killed", + "level": "note", + "message": {"text": "Extra mutant: cov_mark records PASS when the reader's rc is non-zero (-eq 0 changed to -ne 0), in a scratch copy of the guard tree. Killed: the guard exits 1 with 8 FAIL lines."}, + "properties": { + "grounding": "measured", + "command": ["bash", "/scripts/check_dogfood_reads_ci.sh"], + "exit_code": 1, + "stdout_sha256": "66bab24d53e48cbc40b95cf25f5836e858a2f4d0a88c6a5006da929a6059c8df", + "failure_scenario": "If it survived, an inverted coverage verdict would pass.", + "precision_class": "advisory" + } + }, + { + "ruleId": "extra_mutant_git_dir_survives", + "level": "warning", + "message": {"text": "Extra mutant outside the committed set: cov_mark without the GIT_DIR prefix on the tag_coverage_gate.sh call (the commit message says the gate's git reads go through GIT_DIR, with no cd). The guard on a scratch copy with that edit still exits 0: R3 drives cov_mark against a planted reader that does not read git."}, + "properties": { + "grounding": "measured", + "command": ["bash", "/scripts/check_dogfood_reads_ci.sh"], + "exit_code": 0, + "stdout_sha256": "bd261c161c3a1c825e81c5cbf508bf68441b1f404b40fdb1f83a8a0f48bcfe60", + "failure_scenario": "A later edit drops GIT_DIR and the real tag_coverage_gate.sh reads git from the caller's cwd; the guard stays green and the commit message's claim is untested.", + "precision_class": "advisory" + } + }, + { + "ruleId": "extra_mutant_spec_substring_survives", + "level": "warning", + "message": {"text": "Extra mutant outside the committed set: ci_mark matching the sha_checks line by a substring of the spec instead of the ` -- ` field. The guard on a scratch copy still exits 0. Likely behaviourally equivalent today (the two specs share no text); that is not proven."}, + "properties": { + "grounding": "measured", + "command": ["bash", "/scripts/check_dogfood_reads_ci.sh"], + "exit_code": 0, + "stdout_sha256": "bd261c161c3a1c825e81c5cbf508bf68441b1f404b40fdb1f83a8a0f48bcfe60", + "failure_scenario": "A future spec that is a substring of another check's name would read that check's line and could PASS on it.", + "precision_class": "advisory" + } + } + ] + }, + { + "tool": {"driver": {"name": "antigravity"}}, + "invocations": [{"executionSuccessful": true, "toolExecutionNotifications": []}], + "results": [] + } + ] +} diff --git a/evidence/pr-review/4886/6bac6be648bdcee2c8b8c0c7c640d1419d34703b/receipt.intoto.jsonl b/evidence/pr-review/4886/6bac6be648bdcee2c8b8c0c7c640d1419d34703b/receipt.intoto.jsonl new file mode 100644 index 0000000000..bd51855ff2 --- /dev/null +++ b/evidence/pr-review/4886/6bac6be648bdcee2c8b8c0c7c640d1419d34703b/receipt.intoto.jsonl @@ -0,0 +1 @@ +{"_type":"https://in-toto.io/Statement/v1","subject":[{"name":"git+https://github.com/paiml/aprender","digest":{"sha1":"6bac6be648bdcee2c8b8c0c7c640d1419d34703b"}}],"predicateType":"https://paiml.dev/attestations/pr-review/v2","predicate":{"skill_version":"2.1.0","attestation_level":"L1-self","pr":4886,"base_sha":"88bf12c8710dd29617a28add806a37c3edac42d2","head_sha":"6bac6be648bdcee2c8b8c0c7c640d1419d34703b","author_actor":{"kind":"agent","id":"agent:claude-opus-5-5/build-kaizen-4672-2c"},"reviewer_actor":{"kind":"agent","id":"agent:claude-sonnet-5-5/pr-review-4886-lane"},"affected_crates":[],"verdict":"FINDINGS","consultations":{"pmat":{"status":"consulted","transport":"cli","transport_unavailable":["mcp: not attempted this run (cli answered)"],"index_commit":"6bac6be648bdcee2c8b8c0c7c640d1419d34703b","index_is_ancestor":true,"index_worktree_dirty":false,"complexity_delta":[],"tdg_delta":[],"satd_introduced":[],"cache_hits":0,"duplication_hits":[],"duplication_coverage":{"rust":"lexical","shell":"lexical","python":"lexical","config":"lexical","docs":"lexical","other":"lexical","sibling_branches":"lexical","merge_base_to_main":"lexical"},"duplication_horizon":["head=6bac6be648bdcee2c8b8c0c7c640d1419d34703b","siblings=refs/remotes/origin/* unmerged into origin/main","merge_base_to_main=88bf12c8710dd29617a28add806a37c3edac42d2..refs/remotes/origin/main"],"horizon_branches_total":1540,"horizon_branches_scanned":1540,"merge_base_to_main_files":0,"symbols_searched":13,"queries":[{"q":"pre-publish coverage reads receipt tag_coverage_gate","command":["pmat","query","pre-publish coverage reads receipt tag_coverage_gate","--limit","10"],"cwd":"the review worktree at head","results":10,"note":"The stale index was rebuilt at head (94427 functions) by this query. The semantic index is Rust-only and the diff changes no Rust. No TODO/FIXME/HACK/XXX on any added line.","stdout_sha256":"0c2f0cb4a5ba3de18e72e2138df7d266883a839a2f4b44fb0539dcf7e65726ad"}]},"cuda":{"status":"not-triggered","trigger_reason":"no changed path or commit message matches a section 3.B pattern (guard --match-path on all 4 paths and --match-message both exit 1) and the diff makes no device-behaviour claim: a shell runner, a guard, a helper and a contract"},"crux":{"status":"not-triggered","trigger_reason":"the guard --match-crux-surface predicate matches none of the diff added lines, and the diff changes no subcommand, flag, route, MCP tool, config key or output format"},"mutation":{"status":"consulted","scope":"guard","attempted":12,"killed":10,"survivors":[{"mutant":"cov_mark without the GIT_DIR prefix on the tag_coverage_gate.sh call","file":"scripts/dogfood.sh","line":697,"killed":false},{"mutant":"ci_mark matches the sha_checks line by a bare spec substring","file":"scripts/dogfood.sh","line":687,"killed":false}]},"antigravity":{"status":"consulted","attempted":1,"agy_version":"agy 1.3.0","binary_path":"/home/noah/.local/bin/agy","model_id":"gemini-3.1-pro-high","model_family":"google/gemini (requested id; unverifiable from the receipt)","exit_code":0,"duration_seconds":109.296312252,"agy_status":"SUCCESS","usage":{"input_tokens":108355,"output_tokens":8950,"thinking_tokens":7055,"cache_read_tokens":758376,"total_tokens":117305},"output_check":{"structured_output_present":true,"reviewed":true,"schema_valid":true},"reverified_by_primary":false,"divergence":{"agreed":0,"agy_only":0,"primary_only":2,"contradicted":0},"findings":[]}},"findings_ref":{"path":"findings.sarif","sha256":"3925c7448eb668ad6c20319a8a3757ac829d6be324761ab801eeafdd235fa900"},"cost":{"input_tokens":108355,"output_tokens":8950,"wall_seconds":1500},"diff_patch_id":"30be26cb97a09421c8df64ea78e5fa9bd2505a7d","diff_patch_id_algo":"git-patch-id-verbatim/pinned-diff-v1","notes":["diff_patch_id was computed by the parent session under a cop ruling (subagent-lock.sh exempts the parent); control e95ae8280f..deb4f19d5e gives 6ff6a07990, equal to the CI A2 line. This lane was refused by subagent-lock.sh on patch-id and on archive and did not route around either; see SARIF rules diff_patch_id_run_by_parent and lane_hook_refusals."]}} diff --git a/evidence/pr-review/4886/b5daf308f7d22333bbdc65b484d9e18ec5510fa2/findings.sarif b/evidence/pr-review/4886/b5daf308f7d22333bbdc65b484d9e18ec5510fa2/findings.sarif new file mode 100644 index 0000000000..8f3468d3b2 --- /dev/null +++ b/evidence/pr-review/4886/b5daf308f7d22333bbdc65b484d9e18ec5510fa2/findings.sarif @@ -0,0 +1,231 @@ +{ + "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "pmat" + } + }, + "invocations": [ + { + "executionSuccessful": true, + "toolExecutionNotifications": [] + } + ], + "results": [ + { + "ruleId": "duplication_scan_no_hits", + "level": "note", + "message": { + "text": "The lexical duplication scan over head, all 1539 unmerged sibling branches and the merge-base-to-main range (7 files) found 0 hits for the 13 symbols the diff adds. The diff changes no Rust file, so the pmat semantic index (Rust-only) was queried but cannot reach it." + }, + "properties": { + "grounding": "measured", + "command": [ + "bash", + "scripts/pr_review_duplication_scan.sh", + "--base", + "88bf12c8710dd29617a28add806a37c3edac42d2", + "--head", + "b5daf308f7d22333bbdc65b484d9e18ec5510fa2", + "--json", + "" + ], + "exit_code": 0, + "stdout_sha256": "81818df8c471f9d5b1aa9d55c8c5721c31b874161cf2f7b1061a6d8d26b1109a", + "failure_scenario": "A re-implementation under a different name is invisible to a name match; that residual is not covered.", + "precision_class": "advisory" + } + }, + { + "ruleId": "diff_patch_id_run_by_parent", + "level": "note", + "message": { + "text": "diff_patch_id c3fb6c97c18ef8eb23d9e20e76fd739588e52906 over 88bf12c871..b5daf308f7 (evidence/pr-review/4886/ excluded) was computed by the PARENT session, not by this lane: subagent-lock.sh refuses git patch-id in a review lane by design. Control by the parent on the previous head 6bac6be648 reproduced 30be26cb97a09421c8df64ea78e5fa9bd2505a7d, the value in that head receipt. The stdout_sha256 here is the digest of the reported id plus a newline, taken by this lane from the value relayed to it; this lane did not observe that stdout." + }, + "properties": { + "grounding": "measured", + "command": [ + "bash", + "-c", + ". scripts/lib/pr_review_patch_id.sh && prpid_compute 88bf12c8710dd29617a28add806a37c3edac42d2 b5daf308f7d22333bbdc65b484d9e18ec5510fa2 4886" + ], + "exit_code": 0, + "stdout_sha256": "6c433b5a78c6fa36ca7bc587116722b6b6476964011958ecd81f6e0630a17382", + "failure_scenario": "If the relayed id were wrong, Arm 4 would find no receipt bound to the subject diff and refuse the merge, so the error cannot arm a merge that should not land.", + "precision_class": "advisory" + } + }, + { + "ruleId": "lane_hook_refusals", + "level": "note", + "message": { + "text": "This lane never ran git patch-id or git archive (the previous receipt records the hook refusing both), so nothing was routed around: the patch-id was relayed by the parent and the agy workspace was built with tar from the tracked files of the clean worktree (no .git, evidence/ left out), a file copy and not a git operation. One refusal this run: the PreToolUse hook subagent-lock.sh refused an rm of a scratch directory under /tmp/claude-1000/ outside the lane own dir; that command did not run, was not retried that way, and the scratch copy of scripts/ it named was left in place outside the worktree. A same-named scratch dir was then built under the lane own scratchpad and removed there." + }, + "properties": { + "grounding": "asserted", + "rationale": "The refusals are the hook output this lane received verbatim; no command ran, so there is no exit code or stdout to measure.", + "failure_scenario": "A reader of the receipt would otherwise take the tar-built agy workspace for a git-archive tree, and the patch-id for one this lane computed.", + "precision_class": "advisory" + } + }, + { + "ruleId": "dead_elif_pre_publish_coverage", + "level": "warning", + "message": { + "text": "scripts/dogfood.sh line 1857, `elif [ \"$DOGFOOD_PHASE\" = pre-publish ]`, sits inside the `else` (line 1819) of the new `if [ \"$DOGFOOD_PHASE\" = pre-publish ]` at line 1816, which closes at line 1865. It can never be true, so the #3957 F1b branch and its FAIL message are dead code; pre-publish coverage is now decided only by cov_mark." + }, + "properties": { + "grounding": "measured", + "command": [ + "sed", + "-n", + "1816p;1819p;1857p;1865p", + "scripts/dogfood.sh" + ], + "exit_code": 0, + "stdout_sha256": "24dcf29e1f7cec413070882991cd914f534409f6da1bbcee4e21703639b01afa", + "failure_scenario": "A later edit trusts the F1b branch (coverage below floor in pre-publish is RED with its owed-by message) to run; it does not.", + "precision_class": "advisory" + } + }, + { + "ruleId": "ci_read_narrower_than_measured_test", + "level": "note", + "message": { + "text": "In pre-publish the test row reads `workspace-test` (nextest --lib over the workspace) where the replaced row ran `cargo test $FEATS` (doctests, integration targets, bin tests). The runner comment in the 2c block discloses this; the receipt row says only `read, not re-run`." + }, + "properties": { + "grounding": "asserted", + "rationale": "Taken from the diff comment in scripts/dogfood.sh and CLAUDE.md Testing (only a subset of integration targets is wired into CI). Not measured by running anything.", + "failure_scenario": "A doctest or integration-only failure that CI does not run passes the pre-publish test row.", + "precision_class": "advisory" + } + } + ] + }, + { + "tool": { + "driver": { + "name": "cargo-mutants" + } + }, + "invocations": [ + { + "executionSuccessful": true, + "toolExecutionNotifications": [] + } + ], + "results": [ + { + "ruleId": "committed_plants_killed", + "level": "note", + "message": { + "text": "All 9 committed planted defects of check_dogfood_reads_ci.sh are killed (--self-test exits 0); sha_checks.sh --self-test is 21/21." + }, + "properties": { + "grounding": "measured", + "command": [ + "bash", + "scripts/check_dogfood_reads_ci.sh", + "--self-test" + ], + "exit_code": 0, + "stdout_sha256": "542142ef51e2f92a7d6370d1e99d028e0e81b1e4b2ef29ee09f04a2e63adb258", + "failure_scenario": "If a plant survived, a runner defect the guard claims to catch would pass unnoticed.", + "precision_class": "advisory" + } + }, + { + "ruleId": "extra_mutant_cov_inverted_killed", + "level": "note", + "message": { + "text": "Extra mutant: cov_mark records PASS when the reader's rc is non-zero (-eq 0 changed to -ne 0), in a scratch copy of the guard tree. Killed: the guard exits 1 with 9 FAIL lines." + }, + "properties": { + "grounding": "measured", + "command": [ + "bash", + "/scripts/check_dogfood_reads_ci.sh" + ], + "exit_code": 1, + "stdout_sha256": "4adee19aa73b74b0bac8f879f68d0c1bbf40358e06dd6aba88e15d399c8e2dcc", + "failure_scenario": "If it survived, an inverted coverage verdict would pass.", + "precision_class": "advisory" + } + }, + { + "ruleId": "guard_tree_m5_green_at_head", + "level": "note", + "message": { + "text": "guard-tree#m5 (the guard-tree#m5 S4 script) had matched the old log name and the two old case labels as receipt readers. At b5daf308f7 the rename to coverage-gate.log and coverage_gate_* makes it exit 0: 21 rows + 4 structural, every mutant killed." + }, + "properties": { + "grounding": "measured", + "command": [ + "bash", + "-c", + "bash scripts/check_cov*_receipt.sh" + ], + "exit_code": 0, + "stdout_sha256": "23c3e4a959ba20ce28eabb544922ec4f32a8cbced220a9eacb99dd01a185f93a", + "failure_scenario": "If S4 still matched the old names, the guard-tree job would be RED and the PR could not merge; the same run shows it does not.", + "precision_class": "advisory" + } + }, + { + "ruleId": "extra_mutant_git_dir_survives", + "level": "warning", + "message": { + "text": "Extra mutant outside the committed set: cov_mark without the GIT_DIR prefix on the tag_coverage_gate.sh call (the commit message says the gate's git reads go through GIT_DIR, with no cd). The guard on a scratch copy with that edit still exits 0: R3 drives cov_mark against a planted reader that does not read git." + }, + "properties": { + "grounding": "measured", + "command": [ + "bash", + "/scripts/check_dogfood_reads_ci.sh" + ], + "exit_code": 0, + "stdout_sha256": "cbac28680162cef946dc16e5b3c097ca6286f73b198d4ec6a42ad9f377aa4475", + "failure_scenario": "A later edit drops GIT_DIR and the real tag_coverage_gate.sh reads git from the caller's cwd; the guard stays green and the commit message's claim is untested.", + "precision_class": "advisory" + } + }, + { + "ruleId": "extra_mutant_spec_substring_survives", + "level": "warning", + "message": { + "text": "Extra mutant outside the committed set: ci_mark matching the sha_checks line by a substring of the spec instead of the ` -- ` field. The guard on a scratch copy still exits 0. Likely behaviourally equivalent today (the two specs share no text); that is not proven." + }, + "properties": { + "grounding": "measured", + "command": [ + "bash", + "/scripts/check_dogfood_reads_ci.sh" + ], + "exit_code": 0, + "stdout_sha256": "cbac28680162cef946dc16e5b3c097ca6286f73b198d4ec6a42ad9f377aa4475", + "failure_scenario": "A future spec that is a substring of another check's name would read that check's line and could PASS on it.", + "precision_class": "advisory" + } + } + ] + }, + { + "tool": { + "driver": { + "name": "antigravity" + } + }, + "invocations": [ + { + "executionSuccessful": true, + "toolExecutionNotifications": [] + } + ], + "results": [] + } + ] +} diff --git a/evidence/pr-review/4886/b5daf308f7d22333bbdc65b484d9e18ec5510fa2/receipt.intoto.jsonl b/evidence/pr-review/4886/b5daf308f7d22333bbdc65b484d9e18ec5510fa2/receipt.intoto.jsonl new file mode 100644 index 0000000000..0ded3f3fe3 --- /dev/null +++ b/evidence/pr-review/4886/b5daf308f7d22333bbdc65b484d9e18ec5510fa2/receipt.intoto.jsonl @@ -0,0 +1 @@ +{"_type":"https://in-toto.io/Statement/v1","subject":[{"name":"git+https://github.com/paiml/aprender","digest":{"sha1":"b5daf308f7d22333bbdc65b484d9e18ec5510fa2"}}],"predicateType":"https://paiml.dev/attestations/pr-review/v2","predicate":{"skill_version":"2.1.0","attestation_level":"L1-self","pr":4886,"base_sha":"88bf12c8710dd29617a28add806a37c3edac42d2","head_sha":"b5daf308f7d22333bbdc65b484d9e18ec5510fa2","author_actor":{"kind":"agent","id":"agent:claude-opus-5-5/build-kaizen-4672-2c"},"reviewer_actor":{"kind":"agent","id":"agent:claude-sonnet-5-5/pr-review-4886-lane"},"affected_crates":[],"verdict":"FINDINGS","consultations":{"pmat":{"status":"consulted","transport":"cli","transport_unavailable":["mcp: not attempted this run (cli answered)"],"index_commit":"b5daf308f7d22333bbdc65b484d9e18ec5510fa2","index_is_ancestor":true,"index_worktree_dirty":false,"complexity_delta":[],"tdg_delta":[],"satd_introduced":[],"cache_hits":0,"duplication_hits":[],"duplication_coverage":{"rust":"lexical","shell":"lexical","python":"lexical","config":"lexical","docs":"lexical","other":"lexical","sibling_branches":"lexical","merge_base_to_main":"lexical"},"duplication_horizon":["head=b5daf308f7d22333bbdc65b484d9e18ec5510fa2","siblings=refs/remotes/origin/* unmerged into origin/main","merge_base_to_main=88bf12c8710dd29617a28add806a37c3edac42d2..refs/remotes/origin/main"],"horizon_branches_total":1539,"horizon_branches_scanned":1539,"merge_base_to_main_files":7,"symbols_searched":13,"queries":[{"q":"pre-publish coverage reads receipt tag_coverage_gate","command":["pmat","query","pre-publish coverage reads receipt tag_coverage_gate","--limit","10"],"cwd":"the review worktree at head","results":10,"note":"The index was rebuilt at head by this query (1m41s). The semantic index is Rust-only and the diff changes no Rust. No TODO/FIXME/HACK/XXX on any added line.","stdout_sha256":"2b7388a57a42ca5919de13b645d5b8b9958a8aa8db8bd2ae17d9fe8a44e4f0e3"}]},"cuda":{"status":"not-triggered","trigger_reason":"no changed path or commit message matches a section 3.B pattern (guard --match-path on all 4 non-evidence paths and --match-message both exit 1) and the diff makes no device-behaviour claim: a shell runner, a guard, a helper and a contract"},"crux":{"status":"not-triggered","trigger_reason":"the guard --match-crux-surface predicate matches none of the diff added lines, and the diff changes no subcommand, flag, route, MCP tool, config key or output format"},"mutation":{"status":"consulted","scope":"guard","attempted":12,"killed":10,"survivors":[{"mutant":"cov_mark without the GIT_DIR prefix on the tag_coverage_gate.sh call","file":"scripts/dogfood.sh","line":697,"killed":false},{"mutant":"ci_mark matches the sha_checks line by a bare spec substring","file":"scripts/dogfood.sh","line":687,"killed":false}]},"antigravity":{"status":"consulted","attempted":1,"agy_version":"1.3.0","binary_path":"/home/noah/.local/bin/agy","model_id":"gemini-3.1-pro-high","model_family":"google/gemini (requested id; unverifiable from the receipt)","exit_code":0,"duration_seconds":150.038594951,"agy_status":"SUCCESS","usage":{"input_tokens":99846,"output_tokens":16475,"thinking_tokens":14861,"cache_read_tokens":627903,"total_tokens":116321},"output_check":{"structured_output_present":true,"reviewed":true,"schema_valid":true},"reverified_by_primary":false,"divergence":{"agreed":0,"agy_only":0,"primary_only":2,"contradicted":0},"findings":[]}},"findings_ref":{"path":"findings.sarif","sha256":"e381bd5adf21991cff3c88ab5cb8f3245693048adf18f423d0f79d2018ddfa1d"},"cost":{"input_tokens":99846,"output_tokens":16475,"wall_seconds":1500},"diff_patch_id":"c3fb6c97c18ef8eb23d9e20e76fd739588e52906","diff_patch_id_algo":"git-patch-id-verbatim/pinned-diff-v1","notes":["diff_patch_id was relayed by the parent session (subagent-lock.sh refuses git patch-id in a review lane, by design); a control on the previous head 6bac6be648 reproduced 30be26cb97a09421c8df64ea78e5fa9bd2505a7d. The delta since that head renames the old log name to coverage-gate.log in scripts/dogfood.sh and two case labels to coverage_gate_* in scripts/check_dogfood_reads_ci.sh; guard-tree#m5 (the S4 script) now exits 0. The two prior primary findings (dead elif at dogfood.sh 1857, narrower CI test read) were re-verified unchanged at this head; the two surviving extra mutants also survive unchanged. One lane refusal: subagent-lock.sh refused an rm of a scratch dir outside the lane own dir; not routed around, see SARIF rule lane_hook_refusals."]}} diff --git a/evidence/pr-review/4886/deb4f19d5ea9d4b77086a7fcd630ca7229aaa6ed/findings.sarif b/evidence/pr-review/4886/deb4f19d5ea9d4b77086a7fcd630ca7229aaa6ed/findings.sarif new file mode 100644 index 0000000000..af0ed4e772 --- /dev/null +++ b/evidence/pr-review/4886/deb4f19d5ea9d4b77086a7fcd630ca7229aaa6ed/findings.sarif @@ -0,0 +1,182 @@ +{ + "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "pmat" + } + }, + "invocations": [ + { + "executionSuccessful": true, + "toolExecutionNotifications": [] + } + ], + "results": [ + { + "ruleId": "duplication_scan_no_hits", + "level": "note", + "message": { + "text": "The lexical duplication scan over head, all 1539 unmerged sibling branches and the merge-base-to-main range (0 files) found 0 hits for the 24 symbols the diff adds. The diff changes no Rust file, so the pmat semantic index (Rust-only) was queried but cannot reach it." + }, + "properties": { + "grounding": "measured", + "command": [ + "bash", + "scripts/pr_review_duplication_scan.sh", + "--base", + "e95ae8280fbf24433a853d0b73a84e1516c2dedd", + "--head", + "deb4f19d5ea9d4b77086a7fcd630ca7229aaa6ed", + "--json", + "" + ], + "exit_code": 0, + "stdout_sha256": "6a88674b1b53b138795e06fe78c18ce1765ebcc7650f8bd4b94d74911e5d440e", + "failure_scenario": "A re-implementation under a different name is invisible to a name match; that residual is not covered.", + "precision_class": "advisory" + } + }, + { + "ruleId": "ci_read_narrower_than_measured_test", + "level": "note", + "message": { + "text": "In pre-publish the test row now reads `workspace-test`, which the runner comment itself says is nextest --lib over the workspace, while the replaced row ran `cargo test $FEATS` (doctests, integration targets, bin tests, root facade). The runner records the narrowing in a comment but the receipt row says only `read, not re-run`." + }, + "properties": { + "grounding": "asserted", + "rationale": "Taken from the diff comment at scripts/dogfood.sh section 2c and CLAUDE.md Testing, which says only a subset of integration targets is wired into CI. Not measured by running anything.", + "failure_scenario": "A doctest or integration-only failure that CI does not run passes the pre-publish test row, because the row now means workspace-test green rather than cargo test green.", + "precision_class": "advisory" + } + } + ] + }, + { + "tool": { + "driver": { + "name": "crux" + } + }, + "invocations": [ + { + "executionSuccessful": true, + "toolExecutionNotifications": [] + } + ], + "results": [] + }, + { + "tool": { + "driver": { + "name": "cargo-mutants" + } + }, + "invocations": [ + { + "executionSuccessful": true, + "toolExecutionNotifications": [] + } + ], + "results": [ + { + "ruleId": "committed_plants_killed", + "level": "note", + "message": { + "text": "The committed planted-defect sets of check_dogfood_reads_ci.sh (9 plants) and check_dogfood_row_order.sh (2 plants) are all killed: both --self-test runs exit 0." + }, + "properties": { + "grounding": "measured", + "command": [ + "bash", + "scripts/check_dogfood_reads_ci.sh", + "--self-test" + ], + "exit_code": 0, + "stdout_sha256": "542142ef51e2f92a7d6370d1e99d028e0e81b1e4b2ef29ee09f04a2e63adb258", + "failure_scenario": "If a plant survived, a runner defect the guard claims to catch would pass unnoticed.", + "precision_class": "advisory" + } + }, + { + "ruleId": "guard_blind_to_cov_mark_move", + "level": "warning", + "message": { + "text": "Extra mutant outside the committed set: a copy of scripts/dogfood.sh with the pre-publish `cov_mark` call (a long row) moved from line 1818 to just after `ci_mark fmt` (line 706) still passes check_dogfood_row_order.sh --file, which reports O1-O3 PASS with the long rows starting at line 1818 and counting only 140 rows. row_calls requires an argument after the wrapper name, so the zero-argument `cov_mark` is not a row call and O1 never sees it." + }, + "properties": { + "grounding": "measured", + "command": [ + "bash", + "scripts/check_dogfood_row_order.sh", + "--file", + "" + ], + "exit_code": 0, + "stdout_sha256": "3948fe1b0dd67c437e2a0042b66e62773bc36193a13443e645cb75d24b1ee4d1", + "failure_scenario": "cov_mark (the coverage row, a DOGFOOD_LONG_ROWS member) can be moved ahead of the cheap rows in the pre-publish branch and the order guard stays green, so the hours-long coverage read-through would again delay a red cheap row; today cov_mark only reads a receipt, so the cost is small but the guard states a rule it does not test.", + "precision_class": "advisory" + } + } + ] + }, + { + "tool": { + "driver": { + "name": "antigravity" + } + }, + "invocations": [ + { + "executionSuccessful": true, + "toolExecutionNotifications": [] + } + ], + "results": [ + { + "ruleId": "check_dogfood_row_order-blind-to-cov-mark", + "level": "warning", + "message": { + "text": "The row_calls function in scripts/check_dogfood_row_order.sh silently ignores the zero-argument cov_mark row wrapper." + }, + "properties": { + "grounding": "measured", + "command": [ + "bash", + "-c", + "source scripts/check_dogfood_row_order.sh; row_calls scripts/dogfood.sh | grep cov_mark" + ], + "exit_code": 0, + "stdout_sha256": "de809a82013492312c2ad4df20ac310a0a45a6bce10449a04d63a627e535cecb", + "failure_scenario": "Because the regular expression `[[:space:]]+[^[:space:];&|)]+` strictly demands at least one argument, any zero-argument wrapper like `cov_mark` fails to match and becomes entirely invisible to the static checker. If `cov_mark` were accidentally moved before a cheap row, the order guard `O1` would fail to detect the violation and still erroneously report a PASS.", + "precision_class": "advisory" + } + }, + { + "ruleId": "dogfood-unreachable-coverage-check", + "level": "warning", + "message": { + "text": "The coverage-check elif branch for the pre-publish phase is unreachable dead code." + }, + "properties": { + "grounding": "measured", + "command": [ + "grep", + "-n", + "-C", + "5", + "elif [ \"$DOGFOOD_PHASE\" = pre-publish ]; then", + "scripts/dogfood.sh" + ], + "exit_code": 0, + "stdout_sha256": "de809a82013492312c2ad4df20ac310a0a45a6bce10449a04d63a627e535cecb", + "failure_scenario": "The entire `gate test` / `make coverage-check` block was moved into the `else` branch of `if [ \"$DOGFOOD_PHASE\" = pre-publish ]`. As a result, the `elif [ \"$DOGFOOD_PHASE\" = pre-publish ]` branch at line 1857 is logically unreachable. Any custom failure messaging or specific logic intended for the pre-publish phase in this block will never be executed, creating maintenance confusion.", + "precision_class": "advisory" + } + } + ] + } + ] +} diff --git a/evidence/pr-review/4886/deb4f19d5ea9d4b77086a7fcd630ca7229aaa6ed/receipt.intoto.jsonl b/evidence/pr-review/4886/deb4f19d5ea9d4b77086a7fcd630ca7229aaa6ed/receipt.intoto.jsonl new file mode 100644 index 0000000000..3ffa88b889 --- /dev/null +++ b/evidence/pr-review/4886/deb4f19d5ea9d4b77086a7fcd630ca7229aaa6ed/receipt.intoto.jsonl @@ -0,0 +1 @@ +{"_type":"https://in-toto.io/Statement/v1","subject":[{"name":"git+https://github.com/paiml/aprender","digest":{"sha1":"deb4f19d5ea9d4b77086a7fcd630ca7229aaa6ed"}}],"predicateType":"https://paiml.dev/attestations/pr-review/v2","predicate":{"skill_version":"2.1.0","attestation_level":"L1-self","pr":4886,"base_sha":"e95ae8280fbf24433a853d0b73a84e1516c2dedd","head_sha":"deb4f19d5ea9d4b77086a7fcd630ca7229aaa6ed","author_actor":{"kind":"agent","id":"agent:claude-opus-5-5/build-kaizen-4672-2c"},"reviewer_actor":{"kind":"agent","id":"agent:claude-sonnet-5-5/pr-review-4886-lane"},"affected_crates":[],"verdict":"FINDINGS","consultations":{"pmat":{"status":"consulted","transport":"cli","transport_unavailable":["mcp: not attempted this run (cli answered)"],"index_commit":"deb4f19d5ea9d4b77086a7fcd630ca7229aaa6ed","index_is_ancestor":true,"index_worktree_dirty":false,"complexity_delta":[],"tdg_delta":[],"satd_introduced":[],"cache_hits":0,"duplication_hits":[],"duplication_coverage":{"rust":"lexical","shell":"lexical","python":"lexical","config":"lexical","docs":"lexical","other":"lexical","sibling_branches":"lexical","merge_base_to_main":"lexical"},"duplication_horizon":["head=deb4f19d5ea9d4b77086a7fcd630ca7229aaa6ed","siblings=refs/remotes/origin/* unmerged into origin/main","merge_base_to_main=e95ae8280fbf24433a853d0b73a84e1516c2dedd..refs/remotes/origin/main"],"horizon_branches_total":1539,"horizon_branches_scanned":1539,"merge_base_to_main_files":0,"symbols_searched":24,"queries":[{"q":"pre-publish reads CI check results for a commit sha","command":["pmat","query","pre-publish reads CI check results for a commit sha","--limit","10"],"cwd":"the review worktree at head","results":10,"note":"semantic index is Rust-only and the diff changes no Rust; results are unrelated clap InputFile fields. SATD: the only two added TODO-like matches are mktemp XXXXXX templates, not markers.","stdout_sha256":"2dc4bf637f33a4028070b209d51f740b922fac1bf04f84309c4e583eb9d7d543"}]},"cuda":{"status":"not-triggered","trigger_reason":"no changed path or commit message matches a section 3.B pattern (guard --match-path and --match-message both exit 1) and the diff makes no device-behaviour claim: a shell runner, two guards and a contract"},"crux":{"status":"consulted","trigger_reason":"the guard line-level S3.C recompute fires on two added lines of scripts/check_dogfood_row_order.sh, `local src=\"$1\" long=\"$2\" ...` (a shell local named long, not a clap attribute): a false positive named here. The diff changes no subcommand, flag, route, MCP tool, config key or output format.","surfaces":[{"surface":"long=\"$2\" (shell local variable, not a declaration)","file":"scripts/check_dogfood_row_order.sh","kind":"false-positive: a bash local named long, matched by the long= clap pattern","assessment":"no user-facing surface added or changed"}],"contracts":[],"comparative_claims":[],"crux_coverage":"none","gap_effect":"none"},"mutation":{"status":"consulted","scope":"guard","attempted":11,"killed":11,"survivors":[]},"antigravity":{"status":"consulted","attempted":1,"agy_version":"agy 1.3.0","binary_path":"/home/noah/.local/bin/agy","model_id":"gemini-3.1-pro-high","model_family":"google/gemini (requested id; unverifiable from the receipt)","exit_code":0,"duration_seconds":423.979265746,"agy_status":"ERROR","agy_error":"API error (attempt 1): UNAVAILABLE (code 503): The service is currently unavailable.","usage":{"input_tokens":260224,"output_tokens":26790,"thinking_tokens":18563,"cache_read_tokens":3915215,"total_tokens":287014},"output_check":{"structured_output_present":true,"reviewed":true,"schema_valid":true},"reverified_by_primary":true,"divergence":{"agreed":0,"agy_only":2,"primary_only":1,"contradicted":0},"findings":[{"command":["bash","-c","source scripts/check_dogfood_row_order.sh; row_calls scripts/dogfood.sh | grep cov_mark"],"failure_scenario":"Because the regular expression `[[:space:]]+[^[:space:];&|)]+` strictly demands at least one argument, any zero-argument wrapper like `cov_mark` fails to match and becomes entirely invisible to the static checker. If `cov_mark` were accidentally moved before a cheap row, the order guard `O1` would fail to detect the violation and still erroneously report a PASS.","file":"scripts/check_dogfood_row_order.sh","grounding":"measured","id":"check_dogfood_row_order-blind-to-cov-mark","line":398,"source":"measured","summary":"The row_calls function in scripts/check_dogfood_row_order.sh silently ignores the zero-argument cov_mark row wrapper.","precision_class":"advisory"},{"command":["grep","-n","-C","5","elif [ \"$DOGFOOD_PHASE\" = pre-publish ]; then","scripts/dogfood.sh"],"failure_scenario":"The entire `gate test` / `make coverage-check` block was moved into the `else` branch of `if [ \"$DOGFOOD_PHASE\" = pre-publish ]`. As a result, the `elif [ \"$DOGFOOD_PHASE\" = pre-publish ]` branch at line 1857 is logically unreachable. Any custom failure messaging or specific logic intended for the pre-publish phase in this block will never be executed, creating maintenance confusion.","file":"scripts/dogfood.sh","grounding":"measured","id":"dogfood-unreachable-coverage-check","line":1857,"source":"measured","summary":"The coverage-check elif branch for the pre-publish phase is unreachable dead code.","precision_class":"advisory"}]}},"findings_ref":{"path":"findings.sarif","sha256":"63c595df926d5c1d2d82428346e4c76e34adfcc84cce073c2f07caaaf316b04b"},"cost":{"input_tokens":260224,"output_tokens":26790,"wall_seconds":1400},"diff_patch_id":"6ff6a0799033f0825677c55ea34f466758d06bfc","diff_patch_id_algo":"git-patch-id-verbatim/pinned-diff-v1"}} diff --git a/scripts/check_dogfood_reads_ci.sh b/scripts/check_dogfood_reads_ci.sh new file mode 100644 index 0000000000..60b0d5c825 --- /dev/null +++ b/scripts/check_dogfood_reads_ci.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env bash +# check_dogfood_reads_ci.sh -- in --phase pre-publish, dogfood READS the commit's CI for fmt and +# test and its coverage receipt, and no green receipt for that exact sha is RED (#4672, C316 2c). +# +# bash scripts/check_dogfood_reads_ci.sh # R1-R3 over scripts/dogfood.sh +# bash scripts/check_dogfood_reads_ci.sh --self-test # planted runner defects must go RED +# +# R1 sha_checks.sh and tag_coverage_gate.sh --self-test are green (their planted rows stay red); +# R2 STRUCTURE: fmt and test are `ci_mark` calls and coverage is `cov_mark` (tag_coverage_gate.sh +# --resolve, the receipt cut_tag requires) inside the pre-publish branch, and their +# measuring commands (`gate fmt|test`, `coverage-check`) sit only in its else; clippy is +# measured in every phase and never read from CI (its CI lint is narrower); pre-publish +# never PASSes coverage it did not read; +# R3 BEHAVIOUR: the runner's own CI-read block and ci_mark(), lifted and driven against +# planted check rows for a real commit, give PASS only for a green check on THAT sha, +# and FAIL for a red check, a missing check, a green check on another sha, a failed +# read, a missing reader and a dirty tree. +# EXIT 0 all hold · 1 a finding · 2 the guard cannot judge (not a pass). +set -uo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" || exit 2 +SRC="$ROOT/scripts/dogfood.sh" +SHA_CHECKS="$ROOT/scripts/release/sha_checks.sh" +TCG="$ROOT/scripts/release/tag_coverage_gate.sh" + +# r2 -> 0 when the row sites are wired as stated +r2() { + awk ' + /^if \[ "\$DOGFOOD_PHASE" = pre-publish \]; then$/ { inpp = 1; inelse = 0; next } + inpp && /^else$/ { inelse = 1; next } + inpp && /^fi( |$)/ { inpp = 0; inelse = 0; next } + /^[[:space:]]*ci_mark fmt +"\$CI_SPEC_GATE"$/ { if (inpp && !inelse) f++ } + /^[[:space:]]*ci_mark test +"\$CI_SPEC_TEST"$/ { if (inpp && !inelse) t++ } + /^[[:space:]]*cov_mark$/ { if (inpp && !inelse) v++ } + /^[[:space:]]*ci_mark clippy/ { printf "FAIL R2 line %d: clippy reads CI, whose lint is narrower than the row: %s\n", NR, $0; bad = 1 } + /^gate clippy / { if (!inpp) c++ } + /^[[:space:]]*(ci_)?mark coverage / { if (inpp && !inelse) { printf "FAIL R2 line %d: pre-publish records coverage without reading the receipt: %s\n", NR, $0; bad = 1 } } + /^[[:space:]]*gate (fmt|test) / || /make .*coverage-check/ { + if (!inelse) { printf "FAIL R2 line %d measures outside the pre-publish else: %s\n", NR, $0; bad = 1 } } + END { + if (f != 1 || t != 1 || v != 1 || c != 1) { + printf "FAIL R2 want fmt, test and coverage read in pre-publish once each, clippy measured once in every phase: fmt=%d test=%d coverage=%d clippy=%d\n", f, t, v, c; bad = 1 } + exit bad }' "$1" +} + +# r3 -> 0 when the lifted read block decides every planted case right +r3() { + local src=$1 d blk sha other fail=0 + d=$(mktemp -d) || return 2 + blk="$d/block.sh" + awk '/^# ── C316 item 2c/ { on = 1 } on { print } on && /^}$/ && ++k == 2 { exit }' "$src" > "$blk" + { grep -q '^ci_mark()' "$blk" && grep -q '^cov_mark()' "$blk"; } \ + || { echo "ENV R3 no C316 read block with ci_mark() and cov_mark() in $src"; rm -rf "${d:?}"; return 2; } + git -C "$d" init -q repo && git -C "$d/repo" -c user.name=t -c user.email=t@t commit -q --allow-empty -m one > /dev/null 2>&1 \ + || { echo "ENV R3 cannot make a scratch commit"; rm -rf "${d:?}"; return 2; } + printf 'x\n' > "$d/repo/f"; git -C "$d/repo" add f + git -C "$d/repo" -c user.name=t -c user.email=t@t commit -q -m two > /dev/null 2>&1 + sha=$(git -C "$d/repo" rev-parse HEAD); other=$(git -C "$d/repo" rev-parse HEAD~1) + # The real sha_checks.sh, and a coverage reader that answers rc $TCG_RC for --resolve $TCG_SHA + # only (the real tag_coverage_gate.sh's own reds are R1's). + mkdir -p "$d/skill/release" && cp "$SHA_CHECKS" "$d/skill/release/sha_checks.sh" + printf '%s\n' '[ "$1" = --resolve ] && [ "$2" = "$TCG_SHA" ] || { echo "no receipt for $2"; exit 1; }' \ + 'echo "receipt rc $TCG_RC"; exit "$TCG_RC"' > "$d/skill/release/tag_coverage_gate.sh" + # case + case_() { + local name=$1 want=$2 wcov=$3 dirty=$4 gh=$5 crc=$6 csha=$7 got; shift 7 + printf '%s\n' "$@" | awk -F'|' 'NF { print $1 "\t" $2 "\t" $3 "\t" $4 "\t" $5 "\t2026-10-06T10:00:00Z" }' > "$d/rows.tsv" + if [ "$dirty" = 1 ]; then printf 'y\n' > "$d/repo/f"; else git -C "$d/repo" checkout -q -- f; fi + local tsv=""; [ "$gh" = gh ] && tsv="$d/rows.tsv" + got=$(cd "$d/repo" && GH="$gh" SHA_CHECKS_TSV="$tsv" DOGFOOD_PHASE=pre-publish REPO_ROOT="$d/repo" \ + TCG_RC="$crc" TCG_SHA="$csha" SKILL_DIR="$([ "$gh" = noreader ] && echo "$d" || echo "$d/skill")" WORKLOG="$d" \ + bash -c 'mark() { printf "%s=%s\n" "$1" "$2"; }; . "$1"; ci_mark fmt "$CI_SPEC_GATE"; ci_mark test "$CI_SPEC_TEST"; cov_mark' _ "$blk" 2>&1 | tr '\n' ' ') + local exp="fmt=$want test=$want coverage=$wcov " + if [ "$got" = "$exp" ]; then printf 'ok R3 %-30s %s\n' "$name" "$got" + else printf 'FAIL R3 %-30s got [%s] want [%s]\n' "$name" "$got" "$exp"; fail=1; fi + } + local G="CI|ci / gate|COMPLETED" T="CI|workspace-test|COMPLETED" GG GT + GG="$sha|$G|SUCCESS"; GT="$sha|$T|SUCCESS" + case_ green_control PASS PASS 0 gh 0 "$sha" "$GG" "$GT" + case_ red_check_for_the_sha FAIL PASS 0 gh 0 "$sha" "$sha|$G|FAILURE" "$sha|$T|FAILURE" + case_ missing_check FAIL PASS 0 gh 0 "$sha" "$sha|CI|gpu-touched|COMPLETED|SUCCESS" + case_ green_for_a_different_sha FAIL PASS 0 gh 0 "$sha" "$other|$G|SUCCESS" "$other|$T|SUCCESS" + case_ coverage_gate_refused PASS FAIL 0 gh 1 "$sha" "$GG" "$GT" + case_ coverage_gate_other_sha PASS FAIL 0 gh 0 "$other" "$GG" "$GT" + case_ dirty_tree FAIL FAIL 1 gh 0 "$sha" "$GG" "$GT" + case_ github_read_failed FAIL PASS 0 false 0 "$sha" + case_ the_readers_are_missing FAIL FAIL 0 noreader 0 "$sha" + rm -rf "${d:?}" + return "$fail" +} + +judge() { # judge -> 0 green, 1 finding, 2 env + local src=$1 rc=0 r + [ -f "$src" ] || { echo "ENV no runner at $src"; return 2; } + if bash "$SHA_CHECKS" --self-test > /dev/null 2>&1; then echo "ok R1 sha_checks.sh --self-test green" + else echo "FAIL R1 sha_checks.sh --self-test is red"; rc=1; fi + if bash "$TCG" --self-test > /dev/null 2>&1; then echo "ok R1 tag_coverage_gate.sh --self-test green (no receipt, other sha, below floor, gh failing: red)" + else echo "FAIL R1 tag_coverage_gate.sh --self-test is red"; rc=1; fi + if r2 "$src"; then echo "ok R2 fmt/test are ci_mark rows and coverage a cov_mark row in pre-publish, measured only in its else; clippy measured in every phase" + else rc=1; fi + r3 "$src"; r=$? + [ "$r" -eq 2 ] && return 2 + [ "$r" -ne 0 ] && rc=1 + return "$rc" +} + +self_test() { + local d fail=0 + d=$(mktemp -d) || return 2 + judge "$SRC" > "$d/out" 2>&1 || { echo "FAIL pristine runner is not green:"; cat "$d/out"; rm -rf "${d:?}"; return 1; } + echo "ok pristine runner green" + planted() { # planted + sed -e "$3" "$SRC" > "$d/$1.sh" + if cmp -s "$SRC" "$d/$1.sh"; then echo "FAIL plant $1 changed nothing"; fail=1; return; fi + if judge "$d/$1.sh" > "$d/$1.out" 2>&1; then echo "FAIL plant $1 stayed green: $2"; fail=1 + else echo "ok plant $1 RED: $2"; fi + } + planted rerun "pre-publish re-runs fmt instead of reading CI" 's/^ ci_mark fmt "\$CI_SPEC_GATE"$/ gate fmt true/' + planted nodirty "a dirty tree still reads HEAD's CI" 's/--untracked-files=no 2>\/dev\/null)" \]; then$/--untracked-files=no 2>\/dev\/null)" ] \&\& false; then/' + planted skipread "a failed read becomes a pass" 's/\*) mark "\$1" FAIL "no receipt/*) mark "$1" PASS "no receipt/' + planted wrongspec "test reads ci / gate instead of workspace-test" 's/^ ci_mark test "\$CI_SPEC_TEST"$/ ci_mark test "$CI_SPEC_GATE"/' + planted clippyread "clippy reads ci / gate, a narrower lint" 's/^gate clippy .*/ci_mark clippy "$CI_SPEC_GATE"/' + planted covpass "pre-publish passes coverage it never read" 's/^ cov_mark$/ mark coverage PASS later/' + planted covmissing "pre-publish drops the coverage row" '/^ cov_mark$/d' + planted covskip "a refused coverage receipt becomes a pass" 's/^ else mark coverage FAIL "no coverage receipt/ else mark coverage PASS "no coverage receipt/' + planted covwrongsha "coverage resolves a receipt for another sha" 's/--resolve "\$CI_SHA"/--resolve "${CI_SHA}~1"/' + rm -rf "${d:?}" + [ "$fail" -eq 0 ] && { echo "check_dogfood_reads_ci self-test: PASS"; return 0; } + echo "check_dogfood_reads_ci self-test: FAIL"; return 1 +} + +case "${1:-}" in + --self-test) self_test; exit $? ;; + "") judge "$SRC"; rc=$?; [ "$rc" -eq 0 ] && echo PASS; exit "$rc" ;; + *) sed -n '2,6p' "$0" >&2; exit 2 ;; +esac diff --git a/scripts/dogfood.sh b/scripts/dogfood.sh index f53c1bade9..d66ce8b97e 100755 --- a/scripts/dogfood.sh +++ b/scripts/dogfood.sh @@ -659,9 +659,56 @@ if [ -n "$CHANGELOG_PATH" ] && grep -qF "$VERSION" "$CHANGELOG_PATH"; then mark elif [ -n "$CHANGELOG_PATH" ]; then mark changelog WARN "$CHANGELOG_PATH has no entry for $VERSION" else mark changelog WARN "no CHANGELOG.md (looked in $PWD and $REPO_ROOT)"; fi +# ── C316 item 2c (#4672): pre-publish READS what the commit already has ───── +# fmt and test re-ran, on the release commit, work CI had already done for that same commit. In +# --phase pre-publish they now read it instead, for exactly HEAD's sha: fmt reads `ci / gate` +# (same `cargo fmt --all -- --check`), test reads `workspace-test` (nextest --lib over the whole +# workspace; the root facade's doctests and bin tests are not in it). No green receipt for that +# sha is RED, never a skip: a red, pending or missing check, a green check on another commit, a +# failed GitHub read, and a tree with uncommitted tracked changes. Coverage reads the receipt +# cut_tag already requires: `tag_coverage_gate.sh --resolve SHA` (the coverage-nightly receipt, +# #4734), PASS only on its rc 0. clippy stays measured; see where it sits (C314 design round, #4886). +# One GraphQL call (GH-1); scripts/release/sha_checks.sh --self-test plants the reds. +CI_READ="" CI_READ_ERR="" CI_SHA="" +CI_SPEC_GATE="CI:ci / gate" CI_SPEC_TEST="CI:workspace-test" +if [ "$DOGFOOD_PHASE" = pre-publish ]; then + CI_SHA=$(git -C "$REPO_ROOT" rev-parse HEAD 2>/dev/null) + if [ -z "$CI_SHA" ]; then CI_READ_ERR="there is no git HEAD to read CI for" + elif [ -n "$(git -C "$REPO_ROOT" status --porcelain --untracked-files=no 2>/dev/null)" ]; then + CI_READ_ERR="the tree has uncommitted tracked changes, so no CI result for ${CI_SHA:0:10} describes it" + else + CI_READ=$(bash "$SKILL_DIR/release/sha_checks.sh" "$CI_SHA" "$CI_SPEC_GATE" "$CI_SPEC_TEST" 2>&1) + printf '%s\n' "$CI_READ" > "${WORKLOG:-${TMPDIR:-/tmp}}/ci-read.log" 2>/dev/null || : + fi +fi +ci_mark() { # ci_mark -- PASS only on sha_checks' "ok" line for + local line + if [ -n "$CI_READ_ERR" ]; then mark "$1" FAIL "pre-publish reads CI for HEAD, and $CI_READ_ERR"; return; fi + line=$(printf '%s\n' "$CI_READ" | grep -F -- " $2 -- " | head -1) + case "$line" in + "ok "*) mark "$1" PASS "read, not re-run: ${line#ok "$2" -- }" ;; + "bad "*) mark "$1" FAIL "no green receipt: ${line#bad "$2" -- }" ;; + *) mark "$1" FAIL "no receipt for '$2' on ${CI_SHA:0:10}: ${CI_READ:0:100}" ;; + esac +} +cov_mark() { # cov_mark -- PASS only when tag_coverage_gate.sh --resolve exits 0 for HEAD's sha + local out rc + if [ -n "$CI_READ_ERR" ]; then mark coverage FAIL "pre-publish reads the coverage receipt for HEAD, and $CI_READ_ERR"; return; fi + out=$(GIT_DIR=$(git -C "$REPO_ROOT" rev-parse --absolute-git-dir 2>/dev/null) bash "$SKILL_DIR/release/tag_coverage_gate.sh" --resolve "$CI_SHA" 2>&1); rc=$? + printf '%s\n' "$out" > "${WORKLOG:-${TMPDIR:-/tmp}}/coverage-gate.log" 2>/dev/null || : + if [ "$rc" -eq 0 ]; then mark coverage PASS "read, not re-run: coverage-nightly receipt for ${CI_SHA:0:10} holds COV_FLOOR" + else mark coverage FAIL "no coverage receipt at or above COV_FLOOR for ${CI_SHA:0:10} (tag_coverage_gate.sh --resolve rc $rc): $(printf '%s' "$out" | tail -n 1 | cut -c1-160)"; fi +} + # ── 4-8. quality gates ────────────────────────────────────────────────────── mark feature-scope INFO "clippy/test run with: ${FEAT_NOTE}" -gate fmt cargo fmt --all -- --check +if [ "$DOGFOOD_PHASE" = pre-publish ]; then + ci_mark fmt "$CI_SPEC_GATE" +else + gate fmt cargo fmt --all -- --check +fi +# clippy stays MEASURED in every phase (C314 design round on #4886): `ci / gate` lints default +# features only, allows unused-variables and falls back to lib-only, which is narrower than this row. # shellcheck disable=SC2086 gate clippy cargo clippy --all-targets $FEATS -- -D warnings if command -v cargo-deny >/dev/null 2>&1; then gate security cargo deny check advisories @@ -1766,6 +1813,10 @@ fi # test and coverage ($DOGFOOD_LONG_ROWS) take hours; every row above takes minutes. They # run here so a red cheap row is known before the long wait, not after it. Moved # from section 4-8 unchanged but for one note's wording; their verdicts count exactly as before. +if [ "$DOGFOOD_PHASE" = pre-publish ]; then + ci_mark test "$CI_SPEC_TEST" + cov_mark +else # shellcheck disable=SC2086 gate test cargo test $FEATS MAKEFILE_PATH=$(find_up Makefile) @@ -1811,6 +1862,7 @@ if [ -n "$MAKEFILE_PATH" ] && grep -qE '^coverage-check:' "$MAKEFILE_PATH" 2>/de mark coverage FAIL "${cov_why:-coverage-check failed (rc $cov_rc)}" fi else mark coverage FAIL "no coverage-check make target in ${MAKEFILE_PATH:-$PWD/Makefile} — the >=95% floor is UNVERIFIED, which is not the same as met (was a WARN, contradicting the rule of this skill that a missing capability is a NO-GO)"; fi +fi # end: pre-publish reads CI (C316 2c), every other phase measures # ── clean-room reminder (heavy, runs on the CI box; not automated here) ───── mark clean-room MANUAL "run \`make -C ../infra/machines/clean-room clean-room-$CRATE\` (MANDATORY release gate)" diff --git a/scripts/release/sha_checks.sh b/scripts/release/sha_checks.sh new file mode 100644 index 0000000000..7e4e66dab1 --- /dev/null +++ b/scripts/release/sha_checks.sh @@ -0,0 +1,139 @@ +#!/usr/bin/env bash +# sha_checks.sh -- are the named CI checks green for exactly this commit? (#4672, C316 2c) +# +# bash scripts/release/sha_checks.sh SHA SPEC [SPEC...] # one verdict line per SPEC +# bash scripts/release/sha_checks.sh --self-test # planted rows must stay red +# +# WHY. `dogfood --phase pre-publish` re-ran fmt and the test suite on the release commit, work CI +# had already done for that same commit: the release commit reaches main through the merge queue, +# so `ci / gate` and `workspace-test` have already run on it. This script reads those results +# instead of re-measuring them. It reads; it never re-runs and never waits. Alternatives (below) +# serve any caller that accepts one of several checks. +# +# SPEC ":", e.g. "CI:ci / gate". Alternatives joined by "|" are +# satisfied by any one of them: "CI:ci / coverage|Coverage Nightly:coverage". +# +# THE RULE. A SPEC is green only when its newest check run (by start time) ON THIS SHA, +# in a run of the named workflow, completed with conclusion SUCCESS. Everything else is red, +# never a skip: a red or cancelled newest run, a run still in progress, no run at all, a +# green run on a DIFFERENT commit, and a GitHub read that failed (not measured is red). +# +# GH-1: one GraphQL call per invocation, however many SPECs. +# ENV GH (default gh) · SHA_CHECKS_REPO (paiml/aprender) · SHA_CHECKS_TSV (a file of rows to +# judge instead of asking GitHub; the self-test plants rows through it). +# OUT per SPEC: "ok " or "bad ". +# EXIT 0 every SPEC green · 1 any SPEC red, or the read failed · 2 usage. +set -uo pipefail +GH=${GH:-gh} +REPO=${SHA_CHECKS_REPO:-paiml/aprender} + +# fetch SHA -> TSV rows "\t\t\t\t\t". +fetch() { + local q='query($o:String!,$n:String!,$s:GitObjectID!){repository(owner:$o,name:$n){object(oid:$s){... on Commit{oid checkSuites(first:100){nodes{workflowRun{workflow{name}} checkRuns(first:100){nodes{name status conclusion startedAt}}}}}}}}' + "$GH" api graphql -f query="$q" -f o="${REPO%%/*}" -f n="${REPO#*/}" -f s="$1" \ + --jq '.data.repository.object as $c | $c.checkSuites.nodes[] | select(.workflowRun) + | .workflowRun.workflow.name as $w | .checkRuns.nodes[] + | [$c.oid, $w, .name, .status, (.conclusion // ""), (.startedAt // "")] | @tsv' +} + +# decide SHA ALT < TSV -> "ok " or "bad " for ONE alternative ":". +# The newest start time decides. A run with no start time yet (queued) counts as newest, and +# runs that disagree at that same newest time are red: a tie is not a green. +decide() { + local sha=$1 wf=${2%%:*} name=${2#*:} row + row=$(awk -F'\t' -v s="$sha" -v w="$wf" -v n="$name" ' + $1 == s && $2 == w && $3 == n { + ts = ($6 == "") ? "~" : $6; v = $4 "\t" $5 + if (!seen || ts "" > m "") { m = ts; best = v; tie = 0; seen = 1 } + else if (ts "" == m "" && v != best) tie = 1 } + END { if (seen) print (tie ? "TIE\tdisagreeing runs at one start time" : best) }') + [ -n "$row" ] || { echo "bad no '$name' run of workflow '$wf' on ${sha:0:10}"; return; } + local st cc; st=$(cut -f1 <<<"$row"); cc=$(cut -f2 <<<"$row") + if [ "$st" = COMPLETED ] && [ "$cc" = SUCCESS ]; then echo "ok $wf / $name SUCCESS on ${sha:0:10}" + else echo "bad newest '$name' ($wf) on ${sha:0:10} is ${st}${cc:+ $cc}"; fi +} + +# judge SHA SPEC < TSV -> "ok|bad "; any alternative green makes the SPEC green. +judge() { + local sha=$1 spec=$2 rows alt v why="" + rows=$(cat) + IFS='|' read -r -a alts <<<"$spec" + for alt in "${alts[@]}"; do + v=$(decide "$sha" "$alt" <<<"$rows") + case "$v" in ok\ *) echo "ok $spec -- ${v#ok }"; return ;; esac + why="${why:+$why; }${v#bad }" + done + echo "bad $spec -- $why" +} + +main() { + local sha=$1 rows spec v rc=0; shift + [[ "$sha" =~ ^[0-9a-f]{40}$ ]] || { echo "sha_checks: need a full 40-hex SHA, got '$sha'" >&2; return 2; } + [ $# -ge 1 ] || { echo "sha_checks: need at least one SPEC" >&2; return 2; } + if [ -n "${SHA_CHECKS_TSV:-}" ]; then rows=$(cat "$SHA_CHECKS_TSV") || rows="" + elif ! rows=$(fetch "$sha" 2>&1); then + for spec in "$@"; do echo "bad $spec -- the GitHub read failed, so not measured: ${rows:0:120}"; done + return 1 + fi + for spec in "$@"; do + v=$(judge "$sha" "$spec" <<<"$rows"); echo "$v" + case "$v" in ok\ *) ;; *) rc=1 ;; esac + done + return "$rc" +} + +self_test() { + local d A B fail=0 n=0 got want + d=$(mktemp -d) || return 2 + A=$(printf 'a%.0s' {1..40}); B=$(printf 'b%.0s' {1..40}) + t() { # t + local name=$1 w=$2 spec=$3; shift 3 + printf '%s\n' "$@" | sed 's/ | /\t/g' > "$d/rows.tsv" + SHA_CHECKS_TSV="$d/rows.tsv" main "$A" "$spec" > "$d/out" 2>&1; got=$? + n=$((n + 1)) + if [ "$got" = "$w" ]; then printf 'ok %-34s rc=%s %s\n' "$name" "$got" "$(head -c 90 "$d/out")" + else printf 'FAIL %-34s rc=%s want %s: %s\n' "$name" "$got" "$w" "$(cat "$d/out")"; fail=1; fi + } + local G="CI:ci / gate" + t green_control 0 "$G" "$A | CI | ci / gate | COMPLETED | SUCCESS | 2026-10-06T10:00:00Z" + t red_check_for_this_sha 1 "$G" "$A | CI | ci / gate | COMPLETED | FAILURE | 2026-10-06T10:00:00Z" + t missing_check 1 "$G" "$A | CI | workspace-test | COMPLETED | SUCCESS | 2026-10-06T10:00:00Z" + t green_for_a_different_sha 1 "$G" "$B | CI | ci / gate | COMPLETED | SUCCESS | 2026-10-06T10:00:00Z" + t no_rows_at_all 1 "$G" + t in_progress 1 "$G" "$A | CI | ci / gate | IN_PROGRESS | | 2026-10-06T10:00:00Z" + t cancelled 1 "$G" "$A | CI | ci / gate | COMPLETED | CANCELLED | 2026-10-06T10:00:00Z" + t skipped_is_not_green 1 "$G" "$A | CI | ci / gate | COMPLETED | SKIPPED | 2026-10-06T10:00:00Z" + t same_name_other_workflow 1 "$G" "$A | Other | ci / gate | COMPLETED | SUCCESS | 2026-10-06T10:00:00Z" + t newer_red_beats_older_green 1 "$G" "$A | CI | ci / gate | COMPLETED | SUCCESS | 2026-10-06T10:00:00Z" \ + "$A | CI | ci / gate | COMPLETED | FAILURE | 2026-10-06T11:00:00Z" + t newer_green_rerun_wins 0 "$G" "$A | CI | ci / gate | COMPLETED | FAILURE | 2026-10-06T10:00:00Z" \ + "$A | CI | ci / gate | COMPLETED | SUCCESS | 2026-10-06T11:00:00Z" + t same_second_tie_is_red 1 "$G" "$A | CI | ci / gate | COMPLETED | FAILURE | 2026-10-06T10:00:00Z" \ + "$A | CI | ci / gate | COMPLETED | SUCCESS | 2026-10-06T10:00:00Z" + t queued_rerun_after_green 1 "$G" "$A | CI | ci / gate | COMPLETED | SUCCESS | 2026-10-06T10:00:00Z" \ + "$A | CI | ci / gate | QUEUED | | " + local C="CI:ci / coverage|Coverage Nightly:coverage" + t coverage_nightly_green 0 "$C" "$A | Coverage Nightly | coverage | COMPLETED | SUCCESS | 2026-10-06T10:00:00Z" + t coverage_tag_green 0 "$C" "$A | CI | ci / coverage | COMPLETED | SUCCESS | 2026-10-06T10:00:00Z" + t coverage_red 1 "$C" "$A | Coverage Nightly | coverage | COMPLETED | FAILURE | 2026-10-06T10:00:00Z" + t coverage_other_sha_green 1 "$C" "$B | Coverage Nightly | coverage | COMPLETED | SUCCESS | 2026-10-06T10:00:00Z" + t coverage_missing 1 "$C" "$A | CI | ci / gate | COMPLETED | SUCCESS | 2026-10-06T10:00:00Z" + # Two SPECs: one red makes the whole call red. + printf '%s\t%s\t%s\t%s\t%s\t%s\n' "$A" CI "ci / gate" COMPLETED SUCCESS 2026-10-06T10:00:00Z > "$d/two.tsv" + SHA_CHECKS_TSV="$d/two.tsv" main "$A" "$G" "CI:workspace-test" > "$d/out" 2>&1; got=$?; n=$((n + 1)) + if [ "$got" = 1 ] && grep -q '^bad CI:workspace-test' "$d/out"; then echo "ok one_of_two_red rc=1" + else echo "FAIL one_of_two_red rc=$got: $(cat "$d/out")"; fail=1; fi + # A failed GitHub read is red for every SPEC, never a skip. + GH=false main "$A" "$G" > "$d/out" 2>&1; got=$?; n=$((n + 1)) + if [ "$got" = 1 ] && grep -q 'not measured' "$d/out"; then echo "ok github_read_failed rc=1" + else echo "FAIL github_read_failed rc=$got: $(cat "$d/out")"; fail=1; fi + main "abc" "$G" > /dev/null 2>&1; got=$?; n=$((n + 1)) + if [ "$got" = 2 ]; then echo "ok short_sha_is_usage rc=2"; else echo "FAIL short_sha_is_usage rc=$got"; fail=1; fi + rm -rf "${d:?}" + if [ "$fail" -eq 0 ]; then echo "sha_checks self-test: $n/$n"; return 0; fi + echo "sha_checks self-test: FAILED"; return 1 +} + +if [ "${1:-}" = --self-test ]; then self_test; exit $?; fi +[ $# -ge 2 ] || { sed -n '2,5p' "$0" >&2; exit 2; } +main "$@"