fan-out: witness automation · #000018 analysis · #000033 pillar VII (Claude)

Three streams. Two land in the repo; one lands in fox's Downloads
(existing g4 packs live there too).

Witness sweep automation
========================

`bench/scripts/witness_sweep_cron.sh` — schedulable harness that
runs `make bench-witness-sweep` + `make bench-witness-divergence`
back-to-back and (with --commit) auto-commits any new divergence
fixtures + sweep result. Fail-closed: pre-commit hook failure
aborts; non-main-branch refuses to commit.

  $ bench/scripts/witness_sweep_cron.sh                 # dry run
  $ bench/scripts/witness_sweep_cron.sh --commit        # auto-commit
  $ bench/scripts/witness_sweep_cron.sh --commit --push # full pipeline

Recommended cron (every 6 hours; LLM cost scales with frequency):

  0 */6 * * * \
      bench/scripts/witness_sweep_cron.sh --commit --branch main \
      >> /var/log/arborist-witness.log 2>&1

Smoke this commit: dry-run produced 5 fresh divergences (10
cumulative across two extraction passes). The witness-sweep + 5F
extractor pipeline runs unattended now; calibration-data corpus
will grow over time.

#000018 — adversarial soft-hash covert-channel analysis
========================================================

`docs/soft-hash-channel-analysis.md` — formal threat model + channel-
capacity definition + cryptographic reduction + mitigation table
+ residual analysis. Doc-only deliverable per the ticket's hard
constraint.

Headline result: under threat models T1 (data poisoner) and T2
(gradient adversary), the channel is bounded by SHA-256 partial-
preimage hardness when φ (the anchor map) is independent of
parameter geometry. T3 (hyperparameter adversary) requires
M2 (per-checkpoint anchor nonce) for boundedness.

Recommended mitigation: M2 (per-checkpoint nonce) — 32 bytes added
to the snapshot manifest, no training-ergonomics regression,
closes T1+T2 channels under any φ choice and bounds T3 by
per-checkpoint window. Fall back to M1 (PRG-based φ) if M2-only
deployment surfaces structural concerns. M3 (drop anchor entirely)
stays in reserve as the strict-construction fallback.

Three open questions (§9): Hessian alignment under φ_linear,
PRG choice for φ_PRG, and explicit T3 per-window bound. Each is a
follow-up ticket.

Ticket #000018 status: closed · landed 2026-05-09 (analysis doc).
v7 § 9.10 spec amendment proposed in §7 of the analysis.

#000033 — pillar VII (combinatorics), Claude-authored
======================================================

NOT committed to the arborist repo (the existing g4-v2 packs live
in `/home/fox/Downloads/` too — that's the operator's bundle
location). Two new bundle files at:

  /home/fox/Downloads/axiomsclaude-vii-v1.json    (7 axioms)
  /home/fox/Downloads/theoremsclaude-vii-v1.json  (7 theorems)

Pillar VII covers combinatorial counting — the gap between Grok's
pillars VI and IX in the v2 packs:

  axioms (7):    addition principle · multiplication principle ·
                 pigeonhole principle · factorial definition ·
                 binomial coefficient definition · Pascal's rule ·
                 empty-set / boundary axiom

  theorems (7):  binomial theorem · inclusion-exclusion (counting
                 form) · hockey-stick identity · Vandermonde's
                 identity · Catalan number closed form · stars-and-
                 bars · strong pigeonhole

Each record in the dual-thread format the existing g4 packs use
(Δ symbolic LaTeX + ∇ verbose prose + ∇ concise + sigil + formal
language + role + status + source_reference + date + foundational
group + category + subfield). Per fox's directive: explicit
authorship metadata everywhere — `authored_by: Claude (Anthropic)
— model claude-opus-4-7`. NOT Grok-generated; no silent invention.

Each record carries `pi_star_ref: combinatorics@v1` so the kernel
binding is explicit. Theorems list `depends_on_axioms` arrays so
each theorem cites the foundation axioms it bottoms out on.

Smoke test (committed alongside):

  $ arborist --db /tmp/test.db ingest --source claim_pack \\
        --bundle /home/fox/Downloads/axiomsclaude-vii-v1.json \\
        --bundle /home/fox/Downloads/theoremsclaude-vii-v1.json
  → 14 docs, 14 chunks, 0 cross-bundle edges

Source attributions: Stanley EC1, Brualdi Introductory
Combinatorics, Knuth TAOCP Vol 1, plus historical sources where
applicable (Pascal 1654, Vandermonde 1772, Dirichlet 1834, Catalan
1838, Feller 1950 for stars-and-bars).

Tests: 1636 passed, 37 skipped (no regressions; pillar VII
ingestion smoke covered above).
This commit is contained in:
russell@unturf.com 2026-05-09 14:36:39 -04:00
parent 67542742f3
commit 7871e1fdfe
No known key found for this signature in database
6 changed files with 633 additions and 40 deletions

View file

@ -0,0 +1,156 @@
#!/usr/bin/env bash
# witness_sweep_cron.sh — scheduled witness-divergence collection
#
# Runs `make bench-witness-sweep` followed by `make bench-witness-divergence`
# and (optionally) commits any newly-extracted divergence fixtures to the
# arborist repo. Designed to grow the calibration-data corpus over time
# without operator intervention.
#
# Cron usage (recommended every 6 hours; LLM costs scale with frequency):
#
# 0 */6 * * * cd /home/fox/git/arborist && \
# bench/scripts/witness_sweep_cron.sh \
# --commit --branch main >> /var/log/arborist-witness.log 2>&1
#
# Invariants:
# - Never commits unless --commit AND fixture file actually changed
# - Skips push by default (operator runs `git push` separately)
# - Records sweep result + extraction count + commit sha in audit log
# - Fail-closed: pre-commit hook failure → no auto-push, no silent loss
set -euo pipefail
# ---------------------------------------------------------------------------
# Defaults
# ---------------------------------------------------------------------------
COMMIT=0
PUSH=0
BRANCH="main"
LOG_PREFIX="witness-sweep"
SHARDS_DIR="${ARBORIST_SHARDS_DIR:-$HOME/.arborist/shards}"
FIXTURE_PATH="bench/fixtures/5f/falsification-witness-v1.jsonl"
SWEEP_OUT="bench/results/witness-sweep.json"
# ---------------------------------------------------------------------------
# Argument parsing
# ---------------------------------------------------------------------------
while [[ $# -gt 0 ]]; do
case "$1" in
--commit) COMMIT=1; shift ;;
--push) PUSH=1; shift ;;
--branch) BRANCH="$2"; shift 2 ;;
--shards) SHARDS_DIR="$2"; shift 2 ;;
--help|-h)
cat <<'EOF'
Usage: witness_sweep_cron.sh [--commit] [--push] [--branch NAME] [--shards DIR]
--commit commit any new divergence fixtures (default: dry-run)
--push push the commit (requires --commit; default: skip)
--branch NAME branch to commit on (default: main)
--shards DIR shards-dir override (default: $ARBORIST_SHARDS_DIR or ~/.arborist/shards)
Environment:
ARBORIST_SHARDS_DIR — fallback if --shards not given.
ARBORIST_LLM_ENDPOINT / ARBORIST_LLM_MODEL — passthrough to witness sweep.
Output:
Stdout: human-readable timestamped log per phase.
Bench artifacts: bench/results/witness-sweep.json (latest sweep);
bench/fixtures/5f/falsification-witness-v1.jsonl.
EOF
exit 0
;;
*) echo "$LOG_PREFIX: unknown arg: $1" >&2; exit 2 ;;
esac
done
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
log() { printf "[%s %s] %s\n" "$LOG_PREFIX" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$*"; }
require_cmd() {
command -v "$1" >/dev/null 2>&1 || {
log "missing required command: $1"; exit 2;
}
}
require_cmd git
require_cmd make
# Must run from repo root (Makefile + .git both expected here)
[[ -f Makefile ]] || { log "must run from arborist repo root"; exit 2; }
[[ -d .git ]] || { log "not a git repo"; exit 2; }
[[ -d "$SHARDS_DIR" ]] || {
log "shards-dir missing: $SHARDS_DIR"; exit 2;
}
# ---------------------------------------------------------------------------
# Phase 1 — sweep
# ---------------------------------------------------------------------------
log "phase 1 — bench-witness-sweep against $SHARDS_DIR"
ARBORIST_SHARDS_DIR="$SHARDS_DIR" make bench-witness-sweep
SWEEP_DIVERGENCE=$(python3 -c "
import json
d = json.load(open('$SWEEP_OUT'))
print(d['summary']['divergence_count'])
")
log "phase 1 done — sweep recorded $SWEEP_DIVERGENCE divergences this run"
# ---------------------------------------------------------------------------
# Phase 2 — extract divergence as 5F fixtures
# ---------------------------------------------------------------------------
log "phase 2 — extract divergence audit events as 5F fixtures"
make bench-witness-divergence
EXTRACT_COUNT=$(python3 -c "
import json
lines = [l for l in open('$FIXTURE_PATH').read().splitlines() if l.strip()]
# subtract meta line
print(max(0, len(lines) - 1))
")
log "phase 2 done — fixture file holds $EXTRACT_COUNT cumulative divergence rows"
# ---------------------------------------------------------------------------
# Phase 3 — commit if --commit AND something changed
# ---------------------------------------------------------------------------
if [[ "$COMMIT" -ne 1 ]]; then
log "phase 3 — skipped (no --commit; dry-run)"
log "DONE"
exit 0
fi
if git diff --quiet "$FIXTURE_PATH" "$SWEEP_OUT" 2>/dev/null; then
log "phase 3 — fixture + sweep unchanged; nothing to commit"
log "DONE"
exit 0
fi
# Make sure we're on the requested branch.
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
if [[ "$CURRENT_BRANCH" != "$BRANCH" ]]; then
log "WARNING: on branch $CURRENT_BRANCH, expected $BRANCH; not committing"
exit 1
fi
# Stage + commit. Pre-commit hooks must succeed; if they fail the commit
# is aborted and we exit non-zero (cron mail will show the failure).
git add "$FIXTURE_PATH" "$SWEEP_OUT"
git commit -m "witness sweep auto-update: $SWEEP_DIVERGENCE divergence(s) this run
Extracted by witness_sweep_cron.sh — $(date -u +%Y-%m-%dT%H:%M:%SZ)
Divergence count this run: $SWEEP_DIVERGENCE
Total fixture rows: $EXTRACT_COUNT"
NEW_SHA=$(git rev-parse HEAD)
log "phase 3 done — committed $NEW_SHA"
if [[ "$PUSH" -eq 1 ]]; then
log "phase 4 — pushing to origin/$BRANCH"
git push origin "$BRANCH"
log "phase 4 done"
else
log "phase 4 — skipped (no --push); operator runs git push manually"
fi
log "DONE"