From 30e47836ba929d00449d13c2a1f755974b96531a Mon Sep 17 00:00:00 2001 From: codex-bot-andresmgsl <4+codex-bot-andresmgsl@users.noreply.github.com> Date: Tue, 18 Aug 2026 06:56:56 +0000 Subject: [PATCH] feat: emit drill record drafts --- CHANGELOG.md | 1 + drill/drill.sh | 64 ++++++++++++++++++++++++++++++++++++++-- drill/record.sh | 77 ++++++++++++++++++++++++++++++++++++++++++++++++ drills/README.md | 21 +++++++++++++ test/cli.sh | 13 +++++++- 5 files changed, 173 insertions(+), 3 deletions(-) create mode 100644 drill/record.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index f755c22..665c28b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ which records not just what changed but what each drill run proved. ### Added +- The hardware drill can emit an uncoloured release-record draft with a shared run ID (#152) - `kimi-box` template — the Moonshot Kimi CLI agent seed (#158; rig#109's tenant) ## 0.9.0 — 2026-07-21 diff --git a/drill/drill.sh b/drill/drill.sh index cee0210..3651db2 100755 --- a/drill/drill.sh +++ b/drill/drill.sh @@ -10,6 +10,8 @@ # bash drill/drill.sh --yes # no prompt (CI, or you've read it) # bash drill/drill.sh --ref main # drill a different branch of the repo # bash drill/drill.sh --keep-boxes # leave the boxes up to poke at +# --emit-record write an editable Markdown record draft +# --run-id share one ID across the family drills # # Four phases: # A. Incus semantics — the assumptions box is built on, probed directly. @@ -36,6 +38,17 @@ REPO="${BOX_REPO:-heavy-duty/box}" REF="${BOX_REF:-main}" YES=0; KEEP=0 SELF="$(readlink -f "$0")" +EMIT_RECORD="${DRILL_EMIT_RECORD:-}" +RUN_ID="${DRILL_RUN_ID:-}" +DRILL_STARTED_EPOCH="${DRILL_STARTED_EPOCH:-$(date +%s)}" +DRILL_DATE="${DRILL_DATE:-$(date -u +%F)}" +if [ -z "${DRILL_INVOCATION:-}" ]; then + printf -v DRILL_INVOCATION 'bash %q' "$0" + printf -v _drill_args ' %q' "$@" + DRILL_INVOCATION+="$_drill_args" +fi +# shellcheck source=drill/record.sh +. "$(dirname "$SELF")/record.sh" while [ $# -gt 0 ]; do case "$1" in @@ -43,11 +56,19 @@ while [ $# -gt 0 ]; do --keep-boxes) KEEP=1; shift ;; --repo) REPO="$2"; shift 2 ;; --ref) REF="$2"; shift 2 ;; + --emit-record) + [ "$#" -ge 2 ] || { echo "drill: --emit-record needs a value" >&2; exit 2; } + EMIT_RECORD="$2"; shift 2 ;; + --run-id) + [ "$#" -ge 2 ] || { echo "drill: --run-id needs a value" >&2; exit 2; } + RUN_ID="$2"; shift 2 ;; --in-group) shift; break ;; # internal: see below - -h|--help) sed -n '2,18p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; + -h|--help) sed -n '2,20p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; *) echo "drill: unknown option: $1" >&2; exit 2 ;; esac done +export DRILL_EMIT_RECORD="$EMIT_RECORD" DRILL_RUN_ID="$RUN_ID" +export DRILL_STARTED_EPOCH DRILL_DATE DRILL_INVOCATION pass=0; fail=0; findings=(); audit=() ok() { printf ' \033[32mPASS\033[0m %s\n' "$*"; pass=$((pass + 1)); } @@ -280,11 +301,25 @@ EOF # credentials are untouched, so we still have to enter the group ourselves — # once, for the remainder of the drill. inf "re-entering inside the incus-admin group…" - exec sg incus-admin -c "IN_GROUP=1 DRILL_OWNS_SETUP='$OWNS' BOX_REPO='$REPO' BOX_REF='$REF' KEEP=$KEEP bash '$SELF' --in-group" + printf -v reexec '%q ' env IN_GROUP=1 "DRILL_OWNS_SETUP=$OWNS" \ + "BOX_REPO=$REPO" "BOX_REF=$REF" "KEEP=$KEEP" \ + "DRILL_EMIT_RECORD=$EMIT_RECORD" "DRILL_RUN_ID=$RUN_ID" \ + "DRILL_STARTED_EPOCH=$DRILL_STARTED_EPOCH" "DRILL_DATE=$DRILL_DATE" \ + "DRILL_INVOCATION=$DRILL_INVOCATION" bash "$SELF" --in-group + exec sg incus-admin -c "$reexec" fi export PATH="$HOME/.local/bin:$PATH" KEEP="${KEEP:-0}" +record_version=''; record_box_sha='' +record_rig_repo=''; record_rig_ref=''; record_rig_sha='' +if [ -n "$EMIT_RECORD" ]; then + record_version="$(cat "$HOME/.local/share/box/current/VERSION" 2>/dev/null || echo unknown)" + [ -n "$RUN_ID" ] || RUN_ID="$(drill_default_run_id "$record_version" "$DRILL_DATE")" + if ! record_box_sha="$(drill_resolve_ref_sha "$REPO" "$REF")"; then + no "could not resolve exact box SHA for $REPO@$REF — the record cannot pin what ran" + fi +fi # PROVE THE INSTALLER'S CONTRACT (#64) — first, before the clean or anything # else on this host mutates the stack, and before the drill runs setup-host @@ -590,6 +625,15 @@ printf '\n minting a claude-box box (cold, ~10 min)…\n' t0=$SECONDS if mint_box /tmp/mint-drill.log --name drill --template claude-box; then ok "box new --name drill --template claude-box ($((SECONDS - t0))s)" + if [ -n "$EMIT_RECORD" ]; then + record_rig_repo="$(incus config get drill user.box.rig.repo 2>/dev/null)" + record_rig_ref="$(incus config get drill user.box.rig.ref 2>/dev/null)" + if [ -z "$record_rig_repo" ] || [ -z "$record_rig_ref" ]; then + no "minted box did not record the rig repo/ref — the record cannot pin what converged it" + elif ! record_rig_sha="$(drill_resolve_ref_sha "$record_rig_repo" "$record_rig_ref")"; then + no "could not resolve exact rig SHA for $record_rig_repo@$record_rig_ref" + fi + fi else no "box new FAILED — tail: $(tail -3 /tmp/mint-drill.log | tr '\n' ' ')" timeout -k 5 60 incus delete -f drill >/dev/null 2>&1 @@ -978,6 +1022,22 @@ else || no "a drill box survived teardown: $(printf '%s' "$leftover" | awk '{print $1}' | tr '\n' ' ')" fi +if [ -n "$EMIT_RECORD" ]; then + # Standard host metadata, optional by design. + # shellcheck disable=SC1091 + record_os="$(. /etc/os-release 2>/dev/null; printf '%s' "${PRETTY_NAME:-unknown OS}")" + record_host="$(hostname) / $record_os, $(uname -srmo), Incus $(incus --version 2>/dev/null || echo unknown)" + record_elapsed=$(($(date +%s) - DRILL_STARTED_EPOCH)) + if drill_write_record "$EMIT_RECORD" "$record_version" "$RUN_ID" "$record_host" \ + "$DRILL_DATE" "$REPO" "$REF" "$record_box_sha" \ + "$record_rig_repo" "$record_rig_ref" "$record_rig_sha" \ + "$DRILL_INVOCATION" "$pass" "$fail" "$record_elapsed" findings; then + inf "wrote editable release-record draft: $EMIT_RECORD" + else + no "could not emit the release-record draft at $EMIT_RECORD" + fi +fi + phase "Summary" printf ' %s passed, %s failed\n' "$pass" "$fail" if [ "${#findings[@]}" -gt 0 ]; then diff --git a/drill/record.sh b/drill/record.sh new file mode 100644 index 0000000..71bb2ae --- /dev/null +++ b/drill/record.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# Pure helpers for drill/drill.sh's generated release-record draft (#152). + +drill_default_run_id() { + local version="$1" run_date="$2" + printf 'drill-%s-%s-01\n' "$version" "${run_date//-/}" +} + +drill_resolve_ref_sha() { + local repo="$1" ref="$2" remote refs sha + case "$ref" in + [0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]) + printf '%s\n' "$ref" + return + ;; + esac + case "$repo" in + /*|./*|../*|http://*|https://*|git@*) remote="$repo" ;; + *) remote="https://github.com/$repo.git" ;; + esac + refs="$(git ls-remote "$remote" \ + "refs/heads/$ref" "refs/tags/$ref" "refs/tags/$ref^{}" 2>/dev/null)" || return 1 + sha="$(printf '%s\n' "$refs" | awk -v ref="$ref" ' + $2 == "refs/tags/" ref "^{}" { peeled=$1 } + $2 == "refs/heads/" ref { head=$1 } + $2 == "refs/tags/" ref { tag=$1 } + END { if (peeled) print peeled; else if (head) print head; else if (tag) print tag } + ')" + [ -n "$sha" ] || return 1 + printf '%s\n' "$sha" +} + +drill_write_record() { + local path="$1" version="$2" run_id="$3" host="$4" run_date="$5" + local box_repo="$6" box_ref="$7" box_sha="$8" rig_repo="$9" + shift 9 + local rig_ref="$1" rig_sha="$2" invocation="$3" passed="$4" failed="$5" + local elapsed="$6" findings_name="$7" tmp finding plain total minutes + local -n record_findings="$findings_name" + + if [ -e "$path" ]; then + echo "drill: record path already exists; refusing to overwrite evidence: $path" >&2 + return 1 + fi + [ -d "$(dirname "$path")" ] || { + echo "drill: record directory does not exist: $(dirname "$path")" >&2 + return 1 + } + + total=$((passed + failed)) + minutes=$((elapsed / 60)) + tmp="$(mktemp "$path.tmp.XXXXXX")" || return 1 + { + printf '# Release drill — %s\n\n' "$version" + printf '> Generated draft: verify the facts and add operator judgement before commit.\n\n' + printf -- "- **Run ID:** \`%s\`\n" "$run_id" + printf -- '- **Host:** %s\n' "$host" + printf -- '- **Date:** %s\n' "$run_date" + printf -- '- **Candidate refs:**\n' + printf " - box \`%s\` @ \`%s\` (\`%s\`)\n" "$box_ref" "$box_sha" "$box_repo" + printf " - rig \`%s\` @ \`%s\` (\`%s\`)\n" "$rig_ref" "$rig_sha" "$rig_repo" + printf '\n## What ran\n\n' + printf "\`%s\` — phases A, B, C, E, D, M.\n" "$invocation" + printf '\n## Result\n\n' + printf '**%s/%s passed, %s failed.** %s minutes wall clock.\n\n' \ + "$passed" "$total" "$failed" "$minutes" + if [ "${#record_findings[@]}" -eq 0 ]; then + printf -- '- No failures or notes recorded by the harness.\n' + else + for finding in "${record_findings[@]}"; do + plain="$(printf '%s' "$finding" | sed $'s/\033\\[[0-9;]*m//g')" + printf -- '- %s\n' "$plain" + done + fi + } > "$tmp" || { rm -f "$tmp"; return 1; } + mv "$tmp" "$path" +} diff --git a/drills/README.md b/drills/README.md index 8e18fa5..117d8df 100644 --- a/drills/README.md +++ b/drills/README.md @@ -47,6 +47,27 @@ is a good record. So is a maintainer's written waiver explaining why this release shipped without a full drill. What the gate refuses is silence — #95, #114 and #148 all shipped unproven because a skip left no trace. +## Generate the factual draft + +The harness can write the facts it already knows directly into a new record: + +```sh +bash drill/drill.sh --ref release/0.9.1 \ + --run-id drill-0.9.1-20260818-01 \ + --emit-record drills/0.9.1.md +``` + +`--run-id` wins over `DRILL_RUN_ID`; if neither is set, the harness generates +`drill---01`. Supply the same ID explicitly to each family +drill so their records reconcile. The emitter refuses to overwrite an existing +file, and its Markdown contains no terminal colour escapes. + +The generated file is a **draft, not finished release evidence**. It records +the host, invocation, elapsed time, findings, and the exact box and rig refs and +SHAs the run selected. Before committing it, verify those facts and add the +operator judgement that a script cannot make: hardware detail, the meaning of +any failures or skips, and whether they block release. + ## Worked example The version below is a **placeholder that can never be a real release**. diff --git a/test/cli.sh b/test/cli.sh index 66e6a53..8f1a2f9 100644 --- a/test/cli.sh +++ b/test/cli.sh @@ -3119,22 +3119,33 @@ drill_record_fixture() { check "drill record: renderer writes a Markdown draft" 0 "" drill_record_fixture check "drill record: names the release version" 0 "# Release drill — 0.9.1" cat "$DRILL_RECORD" +# Backticks are literal Markdown delimiters. +# shellcheck disable=SC2016 check "drill record: carries the shared run ID" 0 '**Run ID:** `drill-0.9.1-20260818-01`' cat "$DRILL_RECORD" +# shellcheck disable=SC2016 check "drill record: pins the box ref and full SHA" 0 'box `release/0.9.1` @ `0123456789abcdef0123456789abcdef01234567`' cat "$DRILL_RECORD" +# shellcheck disable=SC2016 check "drill record: pins the rig ref and full SHA" 0 'rig `release/0.4.0` @ `89abcdef0123456789abcdef0123456789abcdef`' cat "$DRILL_RECORD" +# shellcheck disable=SC2016 check "drill record: records the invocation" 0 '`bash drill/drill.sh --ref release/0.9.1 --run-id drill-0.9.1-20260818-01`' cat "$DRILL_RECORD" check "drill record: renders pass/fail counts and wall clock" 0 '**84/85 passed, 1 failed.** 41 minutes wall clock.' cat "$DRILL_RECORD" check "drill record: carries plain findings" 0 '- FAIL: sibling isolation regressed' cat "$DRILL_RECORD" -check "drill record: strips terminal colour" 1 $'\033' grep -q $'\033' "$DRILL_RECORD" +check "drill record: strips terminal colour" 1 "" grep -q $'\033' "$DRILL_RECORD" printf 'operator evidence\n' > "$DRILL_RECORD_DIR/existing.md" +# Expansion belongs to the bash -c fixture. +# shellcheck disable=SC2016 check "drill record: refuses to overwrite evidence" 1 "already exists" \ bash -c '. "$1/drill/record.sh"; findings=(); drill_write_record "$2" v id host date repo ref sha rig rref rsha invocation 0 0 0 findings' \ _ "$ROOT" "$DRILL_RECORD_DIR/existing.md" check "drill record: an overwrite refusal preserves the file" 0 "operator evidence" cat "$DRILL_RECORD_DIR/existing.md" +# shellcheck disable=SC2016 check "drill record: default run ID joins version and UTC date" 0 "drill-0.9.1-20260818-01" \ bash -c '. "$1/drill/record.sh"; drill_default_run_id 0.9.1 2026-08-18' _ "$ROOT" +# shellcheck disable=SC2016 +check "drill record: an already exact ref stays exact" 0 "0123456789abcdef0123456789abcdef01234567" \ + bash -c '. "$1/drill/record.sh"; drill_resolve_ref_sha repo 0123456789abcdef0123456789abcdef01234567' _ "$ROOT" check "drill: help names --emit-record" 0 "--emit-record " bash "$ROOT/drill/drill.sh" --help check "drill: help names --run-id" 0 "--run-id " bash "$ROOT/drill/drill.sh" --help check "drill: --emit-record needs a value before any mutation" 2 "--emit-record needs a value" \