#!/usr/bin/env bash
set -uo pipefail
umask 077
readonly E="/home/cube/projects/richard/traning coach/.omo/evidence/task26/task26-gates18-20-clarification-normalized-4e9962be49b72951c3b9ed7e1a4fe36d0ca03e757872ae03364c1ab7a790f32b-st_01a0080c"
readonly C="/home/cube/projects/richard/traning coach/.omo/evidence/task26/task26-clarification-normalized-successor-4e9962be49b72951c3b9ed7e1a4fe36d0ca03e757872ae03364c1ab7a790f32b"
readonly R="/home/cube/projects/richard/hermes-agent"
readonly PY="$R/.venv/bin/python"
readonly W="$C/artifacts/hermes_agent-0.17.0-py3-none-any.whl"
readonly D="4e9962be49b72951c3b9ed7e1a4fe36d0ca03e757872ae03364c1ab7a790f32b"
readonly BASE="$C/source-delta/authenticated-fix-evidence/baseline"
mkdir -p "$E/artifacts" "$E/receipts"; chmod 700 "$E" "$E/artifacts" "$E/receipts"
record(){ local n="$1";shift;local d="$E/artifacts/$n";mkdir -p "$d";chmod 700 "$d";printf '%q ' "$@">"$d/command.txt";printf '\n'>>"$d/command.txt";date -u +%Y-%m-%dT%H:%M:%S.%NZ>"$d/started-at-utc.txt";local s e rc pid;s=$(date +%s%N);"$@">"$d/stdout.txt" 2>"$d/stderr.txt"&pid=$!;wait "$pid";rc=$?;e=$(date +%s%N);date -u +%Y-%m-%dT%H:%M:%S.%NZ>"$d/ended-at-utc.txt";printf '%s\n' "$rc">"$d/exit-code.txt";printf '%s\n' "$(((e-s)/1000000))">"$d/duration-ms.txt";(cd "$d"&&sha256sum command.txt started-at-utc.txt ended-at-utc.txt exit-code.txt duration-ms.txt stdout.txt stderr.txt>files.sha256);chmod 600 "$d"/*;return 0;}
cd "$R"
git status --porcelain=v1 -z >"$E/artifacts/git-status-before.nul"
sha256sum "$C/candidate-manifest.json" "$C/hash-inventory.json" "$C/bindings/source-delta.json" "$W" >"$E/artifacts/candidate-pins-before.sha256"
systemctl --user show hermes-gateway-dualcoachtest.service -p ActiveState -p SubState -p MainPID >"$E/artifacts/service-before.txt" 2>&1 || true
find "/home/cube/projects/richard/traning coach/.omo/evidence/task26" -type f \( -path '*/receipts/*.json' -o -name '*receipt*.json' \) ! -path "$E/*" -print0|sort -z|xargs -0 sha256sum >"$E/artifacts/prior-receipts-before.sha256"
record candidate-preverify "$PY" "$C/verify_candidate.py" "$C"
record source-wheel-parity "$PY" -c '
import hashlib,json,sys,zipfile
from pathlib import Path
repo=Path(sys.argv[1]); wheel=Path(sys.argv[2]); paths=["gateway/platforms/nutrition_onboarding_reconciliation.py","gateway/platforms/telegram_nutrition_onboarding_copy.py","gateway/platforms/telegram_nutrition_onboarding_runtime.py","gateway/platforms/telegram_nutrition_onboarding_runtime_publication.py"];rows=[]
with zipfile.ZipFile(wheel) as z:
 for p in paths:
  a=(repo/p).read_bytes();b=z.read(p);rows.append({"path":p,"source_sha256":hashlib.sha256(a).hexdigest(),"wheel_sha256":hashlib.sha256(b).hexdigest(),"byte_identical":a==b})
r={"candidate_digest":sys.argv[3],"modules":rows,"status":"PASS" if all(x["byte_identical"] for x in rows) else "FAIL"};print(json.dumps(r,sort_keys=True,separators=(",",":")));raise SystemExit(r["status"]!="PASS")
' "$R" "$W" "$D"
readonly SANDBOX=(bwrap --die-with-parent --unshare-net --ro-bind / / --bind "$E" "$E" --tmpfs /tmp --tmpfs "$R/.pytest-cache" --dev /dev --proc /proc --setenv HOME /tmp --setenv TMPDIR /tmp --setenv PYTHONDONTWRITEBYTECODE 1 --chdir "$R")
record gate18-golden "${SANDBOX[@]}" "$PY" -B -W error -m pytest -q -p no:cacheprovider --junitxml="$E/artifacts/gate18-golden.junit.xml" tests/gateway/test_nutrition_onboarding_reconciliation.py::test_authoritative_summary_renders_canonical_customer_values tests/gateway/test_nutrition_onboarding_reconciliation.py::test_resolved_clarification_discards_stale_advisory_sections tests/gateway/test_telegram_nutrition_onboarding_copy.py::test_parse_answer_normalizes_exact_activity_clarification_prefix tests/gateway/test_telegram_nutrition_onboarding.py::test_schedule_rewind_recovers_exact_legacy_activity_shape tests/gateway/test_telegram_nutrition_onboarding.py::test_recovered_answers_resubmit_to_valid_baseline_and_summary
readonly FOCUSED=(tests/gateway/test_telegram_nutrition_onboarding.py tests/gateway/test_telegram_nutrition_onboarding_copy.py tests/gateway/test_nutrition_onboarding_reconciliation.py)
record gate19-predecessor bwrap --die-with-parent --unshare-net --ro-bind / / --bind "$E" "$E" --ro-bind "$BASE/gateway/platforms/telegram_nutrition_onboarding_copy.py" "$R/gateway/platforms/telegram_nutrition_onboarding_copy.py" --ro-bind "$BASE/gateway/platforms/telegram_nutrition_onboarding_runtime.py" "$R/gateway/platforms/telegram_nutrition_onboarding_runtime.py" --ro-bind "$BASE/tests/gateway/test_telegram_nutrition_onboarding.py" "$R/tests/gateway/test_telegram_nutrition_onboarding.py" --ro-bind "$BASE/tests/gateway/test_telegram_nutrition_onboarding_copy.py" "$R/tests/gateway/test_telegram_nutrition_onboarding_copy.py" --tmpfs /tmp --tmpfs "$R/.pytest-cache" --dev /dev --proc /proc --setenv HOME /tmp --setenv TMPDIR /tmp --setenv PYTHONDONTWRITEBYTECODE 1 --chdir "$R" "$PY" -B -W error -m pytest -q -p no:cacheprovider --junitxml="$E/artifacts/gate19-predecessor.junit.xml" "${FOCUSED[@]}"
readonly RELATED=(tests/gateway/test_telegram_nutrition_onboarding.py tests/gateway/test_telegram_nutrition_onboarding_copy.py tests/gateway/test_nutrition_onboarding_reconciliation.py tests/gateway/test_telegram_nutrition_onboarding_callback_observability.py tests/gateway/test_telegram_nutrition_onboarding_direct_entry.py tests/gateway/test_telegram_nutrition_onboarding_preview.py tests/gateway/test_telegram_nutrition_onboarding_preview_runtime.py)
record gate19-successor "${SANDBOX[@]}" "$PY" -B -W error -m pytest -q -p no:cacheprovider --junitxml="$E/artifacts/gate19-successor.junit.xml" "${RELATED[@]}"
record ruff "$R/.venv/bin/ruff" check --no-cache gateway/platforms/telegram_nutrition_onboarding_copy.py gateway/platforms/telegram_nutrition_onboarding_runtime.py tests/gateway/test_telegram_nutrition_onboarding.py tests/gateway/test_telegram_nutrition_onboarding_copy.py
record compile "$PY" -B -c 'import sys;from pathlib import Path;[compile(Path(p).read_bytes(),p,"exec",dont_inherit=True) for p in sys.argv[1:]]' gateway/platforms/telegram_nutrition_onboarding_copy.py gateway/platforms/telegram_nutrition_onboarding_runtime.py tests/gateway/test_telegram_nutrition_onboarding.py tests/gateway/test_telegram_nutrition_onboarding_copy.py
readonly BUILD="$E/artifacts/reproducible-build-output";mkdir -p "$BUILD"
record reproducible-build bwrap --die-with-parent --unshare-net --ro-bind / / --tmpfs /tmp --bind /home/cube/.cache/uv /home/cube/.cache/uv --bind "$BUILD" /tmp/wheel-out --dev /dev --proc /proc --setenv HOME /tmp --setenv TMPDIR /tmp --setenv UV_CACHE_DIR /home/cube/.cache/uv --chdir "$R" /bin/bash -c 'umask 0002;exec scripts/reproducible-wheel-build "$PWD" /tmp/wheel-out'
sha256sum "$BUILD"/*.whl >"$E/artifacts/reproducible-build.sha256" 2>&1 || true
readonly INSTALL="$E/artifacts/installed-wheel-root";mkdir -p "$INSTALL";record wheel-install "$PY" -m pip install --no-deps --no-compile --target "$INSTALL" "$W"
mkdir -p "$E/artifacts/wheel-tests";cp "${RELATED[@]}" tests/gateway/test_dualcoach_activation_cutover.py tests/gateway/test_dualcoach_admin_provider_auth.py tests/gateway/test_telegram_customer_bootstrap.py "$E/artifacts/wheel-tests/"
record installed-wheel-tests bwrap --die-with-parent --unshare-net --ro-bind / / --bind "$E" "$E" --tmpfs /tmp --dev /dev --proc /proc --setenv HOME /tmp --setenv TMPDIR /tmp --setenv PYTHONDONTWRITEBYTECODE 1 --setenv PYTHONPATH "$INSTALL" --chdir /tmp "$PY" -B -m pytest -q -p no:cacheprovider --junitxml="$E/artifacts/installed-wheel-tests.junit.xml" "$E/artifacts/wheel-tests/test_telegram_nutrition_onboarding.py" "$E/artifacts/wheel-tests/test_telegram_nutrition_onboarding_copy.py" "$E/artifacts/wheel-tests/test_nutrition_onboarding_reconciliation.py" "$E/artifacts/wheel-tests/test_telegram_nutrition_onboarding_callback_observability.py" "$E/artifacts/wheel-tests/test_telegram_nutrition_onboarding_direct_entry.py" "$E/artifacts/wheel-tests/test_telegram_nutrition_onboarding_preview.py" "$E/artifacts/wheel-tests/test_telegram_nutrition_onboarding_preview_runtime.py" "$E/artifacts/wheel-tests/test_dualcoach_activation_cutover.py" "$E/artifacts/wheel-tests/test_dualcoach_admin_provider_auth.py" "$E/artifacts/wheel-tests/test_telegram_customer_bootstrap.py::test_customer_activation_commits_only_the_exact_bound_session"
record installed-wheel-imports bwrap --die-with-parent --unshare-net --ro-bind / / --tmpfs /tmp --dev /dev --proc /proc --setenv HOME /tmp --setenv TMPDIR /tmp --setenv PYTHONDONTWRITEBYTECODE 1 --setenv PYTHONPATH "$INSTALL" --chdir /tmp "$PY" -B -c '
import importlib,json,sys
from pathlib import Path
root=Path(sys.argv[1]).resolve();names=["gateway.platforms.nutrition_onboarding_reconciliation","gateway.platforms.telegram_nutrition_onboarding_copy","gateway.platforms.telegram_nutrition_onboarding_runtime","gateway.platforms.telegram_nutrition_onboarding_runtime_publication","gateway.platforms.dualcoach_activation_cutover","gateway.platforms.dualcoach_admin","gateway.platforms.telegram_customer_bootstrap"];rows=[]
for n in names:
 m=importlib.import_module(n);p=Path(m.__file__).resolve();rows.append({"module":n,"origin":str(p),"inside_wheel":p.is_relative_to(root)})
leaks=[{"module":n,"origin":str(Path(m.__file__).resolve())} for n,m in sorted(sys.modules.items()) if (n=="gateway" or n.startswith("gateway.")) and getattr(m,"__file__",None) and not Path(m.__file__).resolve().is_relative_to(root)];r={"candidate_digest":sys.argv[2],"imports":rows,"source_fallbacks":leaks,"status":"PASS" if all(x["inside_wheel"] for x in rows) and not leaks else "FAIL"};print(json.dumps(r,sort_keys=True,separators=(",",":")));raise SystemExit(r["status"]!="PASS")
' "$INSTALL" "$D"
record installed-wheel-cli bwrap --die-with-parent --unshare-net --ro-bind / / --tmpfs /tmp --dev /dev --proc /proc --setenv HOME /tmp --setenv TMPDIR /tmp --setenv PYTHONDONTWRITEBYTECODE 1 --setenv PYTHONPATH "$INSTALL" --chdir /tmp "$PY" -B -m gateway.platforms.dualcoach_admin customer activate --help
"$PY" - <<'PY' "$E" "$R" "$BASE" "$INSTALL"
import json,sys
from pathlib import Path
e,r,b,i=map(Path,sys.argv[1:]);common={"pythonVersion":"3.12","pythonPlatform":"Linux","typeCheckingMode":"strict","reportMissingTypeStubs":"none"};files=["gateway/platforms/telegram_nutrition_onboarding_copy.py","gateway/platforms/telegram_nutrition_onboarding_runtime.py","tests/gateway/test_telegram_nutrition_onboarding_copy.py","tests/gateway/test_telegram_nutrition_onboarding.py"]
for name,root,extra in [("current",r,[r,i]),("baseline",b,[b,i,r])]:
 x=dict(common);x["include"]=[str(root/p) for p in files];x["extraPaths"]=[str(p) for p in extra];(e/"artifacts"/f"type-{name}-config.json").write_text(json.dumps(x,indent=2)+"\n")
PY
record basedpyright-current /home/cube/.local/bin/basedpyright --project "$E/artifacts/type-current-config.json" --pythonpath "$R/.venv/bin/python" --outputjson
record basedpyright-baseline /home/cube/.local/bin/basedpyright --project "$E/artifacts/type-baseline-config.json" --pythonpath "$R/.venv/bin/python" --outputjson
record type-classification "$PY" -c '
import json,sys
from collections import Counter
from pathlib import Path
root=Path(sys.argv[1]);a=json.loads((root/"basedpyright-current/stdout.txt").read_text());b=json.loads((root/"basedpyright-baseline/stdout.txt").read_text())
def rows(d):return [{"file":Path(x["file"]).name,"severity":x["severity"],"rule":x.get("rule"),"message":x["message"]} for x in d["generalDiagnostics"]]
def key(x):return (x["file"],x["severity"],x["rule"],x["message"])
ca,cb=Counter(map(key,rows(a))),Counter(map(key,rows(b)));new=list((ca-cb).elements());removed=list((cb-ca).elements());r={"candidate_digest":sys.argv[2],"current_summary":a["summary"],"baseline_summary":b["summary"],"inherited_count":sum((ca&cb).values()),"new_diagnostics":[{"file":x[0],"severity":x[1],"rule":x[2],"message":x[3]} for x in new],"removed_diagnostics":[{"file":x[0],"severity":x[1],"rule":x[2],"message":x[3]} for x in removed],"status":"PASS" if not new and a["summary"]["errorCount"]==b["summary"]["errorCount"] else "FAIL"};print(json.dumps(r,ensure_ascii=False,sort_keys=True,separators=(",",":")));raise SystemExit(r["status"]!="PASS")
' "$E/artifacts" "$D"
record gate20-full-gateway "${SANDBOX[@]}" "$PY" -B -m pytest -q -p no:cacheprovider --junitxml="$E/artifacts/gate20-full-gateway.junit.xml" tests/gateway
record candidate-postverify "$PY" "$C/verify_candidate.py" "$C"
git status --porcelain=v1 -z >"$E/artifacts/git-status-after.nul";sha256sum "$C/candidate-manifest.json" "$C/hash-inventory.json" "$C/bindings/source-delta.json" "$W" >"$E/artifacts/candidate-pins-after.sha256";systemctl --user show hermes-gateway-dualcoachtest.service -p ActiveState -p SubState -p MainPID >"$E/artifacts/service-after.txt" 2>&1 || true
find "/home/cube/projects/richard/traning coach/.omo/evidence/task26" -type f \( -path '*/receipts/*.json' -o -name '*receipt*.json' \) ! -path "$E/*" -print0|sort -z|xargs -0 sha256sum >"$E/artifacts/prior-receipts-after.sha256"
