#!/usr/bin/env bash # Render /workspace/artifacts/review-evidence.md (spec ยง18) from the recorded # gate statuses and PR metadata. Every check appears with an explicit status: # PASS / FAIL / NOT_APPLICABLE / NOT_RUN / BLOCKED. Phase-2/3 checks the Phase-1 # runner cannot execute are stated NOT_RUN with the reason โ€” never omitted, # never converted into a pass. # # Reads: REVIEW_TYPE, TICKET, REVIEW_NOTES, RUN_ID/GITHUB_RUN_ID, artifacts from # earlier steps ($ARTIFACTS_DIR/{frontend,backend}-pr.json, checkout.json, # gate-status.tsv) SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=lib.sh source "$SCRIPT_DIR/lib.sh" require_env REVIEW_TYPE EVIDENCE_FILE="$ARTIFACTS_DIR/review-evidence.md" run_id="${GITHUB_RUN_ID:-local}" # The evidence report is only as trustworthy as the gate table it renders. assert_gate_table_intact # Untrusted strings (PR titles, branch names, dispatcher-supplied ticket and # notes) must not be able to forge lines inside the evidence report โ€” the agent # is told the evidence report is the only source of truth for what executed. # Control characters and newlines are stripped and the length is capped, so a # crafted value stays on the single line it was rendered into. sanitize() { printf '%s' "$1" | tr -d '\000-\037' | cut -c1-200 } pr_field() { # pr_field [fallback] local f="$ARTIFACTS_DIR/$1-pr.json" if [ -f "$f" ]; then sanitize "$(jq -r "$2" "$f")"; else echo "${3:-not in scope}"; fi } g() { gate_status "$1"; } # A side that has no PR under review has all its gates NOT_APPLICABLE. side_in_scope() { # side_in_scope case "$REVIEW_TYPE" in paired) return 0 ;; "$1") return 0 ;; *) return 1 ;; esac } fe_gate() { if side_in_scope frontend; then g "$1"; else echo "NOT_APPLICABLE (backend-only review)"; fi; } be_gate() { if side_in_scope backend; then g "$1"; else echo "NOT_APPLICABLE (frontend-only review)"; fi; } companion_note="" if [ "$REVIEW_TYPE" != "paired" ] && [ -f "$ARTIFACTS_DIR/checkout.json" ]; then cb="$(jq -r '.companion_branch' "$ARTIFACTS_DIR/checkout.json")" companion_note=" (companion checked out at \`$cb\` head for contract context, not under review)" fi cat >"$EVIDENCE_FILE" </dev/null)" ]; then for f in "$LOG_DIR"/*; do printf -- '- logs/%s\n' "$(basename "$f")" done else printf -- '- none\n' fi) ## Gate Detail $(if [ -f "$GATE_STATUS_FILE" ]; then while IFS=$'\t' read -r key status det; do # shellcheck disable=SC2016 # backticks are literal markdown printf -- '- `%s`: %s%s\n' "$key" "$status" "${det:+ โ€” $det}" done <"$GATE_STATUS_FILE" else printf -- '- no gates recorded\n' fi) EOF log "evidence written to $EVIDENCE_FILE"