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

@ -1,6 +1,11 @@
{"_meta": {"battery": "5f", "sub_battery": "falsification", "version": "v1", "task_count": 5, "notes": "Witness-divergence-extracted falsification fixtures. Auto-generated by `make bench-witness-divergence` from providence_canonical_witness audit events. Each row pairs an LLM raw answer with the kernel's canonical answer; verify_quotes is expected to return UNGROUNDED because the LLM prose doesn't substring-match the kernel's terse canonical form. _witness_meta carries the original agreement_label + audit_seq for traceability."}}
{"_meta": {"battery": "5f", "sub_battery": "falsification", "version": "v1", "task_count": 10, "notes": "Witness-divergence-extracted falsification fixtures. Auto-generated by `make bench-witness-divergence` from providence_canonical_witness audit events. Each row pairs an LLM raw answer with the kernel's canonical answer; verify_quotes is expected to return UNGROUNDED because the LLM prose doesn't substring-match the kernel's terse canonical form. _witness_meta carries the original agreement_label + audit_seq for traceability."}}
{"id": "5f-fal-witness-011631", "battery": "5f", "sub_battery": "falsification", "version": "v1", "carrier": "providence_record", "domain": "claim_lattice", "pi_star_ref": "arithmetic@v1", "answer_text": "1/10", "context": "canonical_kernel_answer=3/10\nquestion=0.1 + 0.2", "expected_reason": "UNGROUNDED", "verifier_method_root": "verify_quotes-v1", "expected": "pass", "_witness_meta": {"agreement_label": "KERNEL-LLM-DIVERGED", "audit_seq": 11631, "pi_star_ref": "arithmetic@v1"}}
{"id": "5f-fal-witness-011637", "battery": "5f", "sub_battery": "falsification", "version": "v1", "carrier": "providence_record", "domain": "claim_lattice", "pi_star_ref": "logic-kernel@v1", "answer_text": "TRUE", "context": "canonical_kernel_answer=(NOT A OR B)\nquestion=A IMPL B", "expected_reason": "UNGROUNDED", "verifier_method_root": "verify_quotes-v1", "expected": "pass", "_witness_meta": {"agreement_label": "KERNEL-LLM-DIVERGED", "audit_seq": 11637, "pi_star_ref": "logic-kernel@v1"}}
{"id": "5f-fal-witness-011639", "battery": "5f", "sub_battery": "falsification", "version": "v1", "carrier": "providence_record", "domain": "claim_lattice", "pi_star_ref": "logic-kernel@v1", "answer_text": "TRUE", "context": "canonical_kernel_answer=(NOT A OR B)\nquestion=(NOT B) IMPL (NOT A)", "expected_reason": "UNGROUNDED", "verifier_method_root": "verify_quotes-v1", "expected": "pass", "_witness_meta": {"agreement_label": "KERNEL-LLM-DIVERGED", "audit_seq": 11639, "pi_star_ref": "logic-kernel@v1"}}
{"id": "5f-fal-witness-011643", "battery": "5f", "sub_battery": "falsification", "version": "v1", "carrier": "providence_record", "domain": "claim_lattice", "pi_star_ref": "algebra-symbolic@v1", "answer_text": "1", "context": "canonical_kernel_answer=Add(Pow(Symbol('x'), Integer(2)), Mul(Integer(2), Symbol('x')), Integer(1))\nquestion=(x+1)**2", "expected_reason": "UNGROUNDED", "verifier_method_root": "verify_quotes-v1", "expected": "pass", "_witness_meta": {"agreement_label": "KERNEL-LLM-DIVERGED", "audit_seq": 11643, "pi_star_ref": "algebra-symbolic@v1"}}
{"id": "5f-fal-witness-011645", "battery": "5f", "sub_battery": "falsification", "version": "v1", "carrier": "providence_record", "domain": "claim_lattice", "pi_star_ref": "algebra-symbolic@v1", "answer_text": "1", "context": "canonical_kernel_answer=Add(Pow(Symbol('x'), Integer(2)), Mul(Integer(2), Symbol('x')), Integer(1))\nquestion=x**2 + 2*x + 1", "expected_reason": "UNGROUNDED", "verifier_method_root": "verify_quotes-v1", "expected": "pass", "_witness_meta": {"agreement_label": "KERNEL-LLM-DIVERGED", "audit_seq": 11645, "pi_star_ref": "algebra-symbolic@v1"}}
{"id": "5f-fal-witness-011649", "battery": "5f", "sub_battery": "falsification", "version": "v1", "carrier": "providence_record", "domain": "claim_lattice", "pi_star_ref": "arithmetic@v1", "answer_text": "1/10", "context": "canonical_kernel_answer=3/10\nquestion=0.1 + 0.2", "expected_reason": "UNGROUNDED", "verifier_method_root": "verify_quotes-v1", "expected": "pass", "_witness_meta": {"agreement_label": "LLM-DIVERGED", "audit_seq": 11649, "pi_star_ref": "arithmetic@v1"}}
{"id": "5f-fal-witness-011652", "battery": "5f", "sub_battery": "falsification", "version": "v1", "carrier": "providence_record", "domain": "claim_lattice", "pi_star_ref": "logic-kernel@v1", "answer_text": "TRUE", "context": "canonical_kernel_answer=(NOT A OR B)\nquestion=A IMPL B", "expected_reason": "UNGROUNDED", "verifier_method_root": "verify_quotes-v1", "expected": "pass", "_witness_meta": {"agreement_label": "LLM-DIVERGED", "audit_seq": 11652, "pi_star_ref": "logic-kernel@v1"}}
{"id": "5f-fal-witness-011653", "battery": "5f", "sub_battery": "falsification", "version": "v1", "carrier": "providence_record", "domain": "claim_lattice", "pi_star_ref": "logic-kernel@v1", "answer_text": "TRUE", "context": "canonical_kernel_answer=(NOT A OR B)\nquestion=(NOT B) IMPL (NOT A)", "expected_reason": "UNGROUNDED", "verifier_method_root": "verify_quotes-v1", "expected": "pass", "_witness_meta": {"agreement_label": "LLM-DIVERGED", "audit_seq": 11653, "pi_star_ref": "logic-kernel@v1"}}
{"id": "5f-fal-witness-011655", "battery": "5f", "sub_battery": "falsification", "version": "v1", "carrier": "providence_record", "domain": "claim_lattice", "pi_star_ref": "algebra-symbolic@v1", "answer_text": "1", "context": "canonical_kernel_answer=Add(Pow(Symbol('x'), Integer(2)), Mul(Integer(2), Symbol('x')), Integer(1))\nquestion=(x+1)**2", "expected_reason": "UNGROUNDED", "verifier_method_root": "verify_quotes-v1", "expected": "pass", "_witness_meta": {"agreement_label": "LLM-DIVERGED", "audit_seq": 11655, "pi_star_ref": "algebra-symbolic@v1"}}
{"id": "5f-fal-witness-011656", "battery": "5f", "sub_battery": "falsification", "version": "v1", "carrier": "providence_record", "domain": "claim_lattice", "pi_star_ref": "algebra-symbolic@v1", "answer_text": "1", "context": "canonical_kernel_answer=Add(Pow(Symbol('x'), Integer(2)), Mul(Integer(2), Symbol('x')), Integer(1))\nquestion=x**2 + 2*x + 1", "expected_reason": "UNGROUNDED", "verifier_method_root": "verify_quotes-v1", "expected": "pass", "_witness_meta": {"agreement_label": "LLM-DIVERGED", "audit_seq": 11656, "pi_star_ref": "algebra-symbolic@v1"}}

View file

@ -1,123 +1,123 @@
{
"schema_version": "witness-sweep-v1",
"timestamp_utc": "2026-05-09T17:27:30+00:00",
"timestamp_utc": "2026-05-09T18:27:23+00:00",
"shards_dir": "/home/fox/.arborist/shards",
"model": "adamo1139/Hermes-3-Llama-3.1-8B-FP8-Dynamic",
"endpoint": "https://hermes.ai.unturf.com/v1",
"summary": {
"questions": 8,
"by_agreement_label": {
"KERNEL-LLM-DIVERGED": 5,
"KERNEL-LLM-AGREE": 3
"LLM-DIVERGED": 5,
"STRICT-WITNESSED": 3
},
"divergence_count": 5,
"divergence_rate": 0.625,
"wall_ms_median": 130.2,
"wall_ms_max": 1111.0
"wall_ms_median": 159.2,
"wall_ms_max": 1099.3
},
"queries": [
{
"question": "0.1 + 0.2",
"status": "cache_miss_then_written",
"status": "cache_hit",
"audit_mode": "CANONICAL_PROJECTION",
"pi_star_ref": "arithmetic@v1",
"canonical_answer": "3/10",
"agreement_label": "KERNEL-LLM-DIVERGED",
"agreement_label": "LLM-DIVERGED",
"llm_raw": "1/10",
"llm_canonical_match": false,
"cache_status": "ABSENT",
"wall_ms": 1111.0,
"cache_status": "ok",
"wall_ms": 1099.3,
"audit_event_hash": "3b25ad3cd28a9505d96e22c85ae42ab182008ee6584b3a74c881dba07e3eab28"
},
{
"question": "1/3 + 1/6",
"status": "cache_miss_then_written",
"status": "cache_hit",
"audit_mode": "CANONICAL_PROJECTION",
"pi_star_ref": "arithmetic@v1",
"canonical_answer": "1/2",
"agreement_label": "KERNEL-LLM-AGREE",
"agreement_label": "STRICT-WITNESSED",
"llm_raw": "1/2",
"llm_canonical_match": false,
"cache_status": "ABSENT",
"wall_ms": 150.8,
"cache_status": "ok",
"wall_ms": 159.2,
"audit_event_hash": "7677efdeb3b2ad7f60cf4312d2f4825c9fa949ddcbc06434ee5fc4ea50a86e3e"
},
{
"question": "2**10",
"status": "cache_miss_then_written",
"status": "cache_hit",
"audit_mode": "CANONICAL_PROJECTION",
"pi_star_ref": "arithmetic@v1",
"canonical_answer": "1024/1",
"agreement_label": "KERNEL-LLM-AGREE",
"agreement_label": "STRICT-WITNESSED",
"llm_raw": "1024",
"llm_canonical_match": false,
"cache_status": "ABSENT",
"wall_ms": 130.2,
"cache_status": "ok",
"wall_ms": 134.7,
"audit_event_hash": "ed570bd6127a0b7143bb5c0f8cf76daf37a2092fe84350c0cab1ee2a2bf0410b"
},
{
"question": "A IMPL B",
"status": "cache_miss_then_written",
"status": "cache_hit",
"audit_mode": "CANONICAL_PROJECTION",
"pi_star_ref": "logic-kernel@v1",
"canonical_answer": "(NOT A OR B)",
"agreement_label": "KERNEL-LLM-DIVERGED",
"agreement_label": "LLM-DIVERGED",
"llm_raw": "TRUE",
"llm_canonical_match": false,
"cache_status": "ABSENT",
"wall_ms": 124.9,
"cache_status": "ok",
"wall_ms": 147.0,
"audit_event_hash": "0f6fb926fd72150c5a0d8121a004b1f66edf3c8ee4bc15c52168f3a7869786fe"
},
{
"question": "(NOT B) IMPL (NOT A)",
"status": "cache_miss_then_written",
"status": "cache_hit",
"audit_mode": "CANONICAL_PROJECTION",
"pi_star_ref": "logic-kernel@v1",
"canonical_answer": "(NOT A OR B)",
"agreement_label": "KERNEL-LLM-DIVERGED",
"agreement_label": "LLM-DIVERGED",
"llm_raw": "TRUE",
"llm_canonical_match": false,
"cache_status": "ABSENT",
"wall_ms": 113.5,
"cache_status": "ok",
"wall_ms": 260.2,
"audit_event_hash": "1b17f6e39edf2bb3d8dce003e20f71df9a3b9bd1b885f8a6e4b78e43ec122c31"
},
{
"question": "A OR NOT A",
"status": "cache_miss_then_written",
"status": "cache_hit",
"audit_mode": "CANONICAL_PROJECTION",
"pi_star_ref": "logic-kernel@v1",
"canonical_answer": "TRUE",
"agreement_label": "KERNEL-LLM-AGREE",
"agreement_label": "STRICT-WITNESSED",
"llm_raw": "TRUE",
"llm_canonical_match": false,
"cache_status": "ABSENT",
"wall_ms": 123.0,
"cache_status": "ok",
"wall_ms": 129.1,
"audit_event_hash": "5929ffe218bb8a97c391df70cfffed810f66d02c4a54bdce2569755200bd8d0d"
},
{
"question": "(x+1)**2",
"status": "cache_miss_then_written",
"status": "cache_hit",
"audit_mode": "CANONICAL_PROJECTION",
"pi_star_ref": "algebra-symbolic@v1",
"canonical_answer": "Add(Pow(Symbol('x'), Integer(2)), Mul(Integer(2), Symbol('x')), Integer(1))",
"agreement_label": "KERNEL-LLM-DIVERGED",
"agreement_label": "LLM-DIVERGED",
"llm_raw": "1",
"llm_canonical_match": false,
"cache_status": "ABSENT",
"wall_ms": 179.4,
"cache_status": "ok",
"wall_ms": 196.1,
"audit_event_hash": "b36f1a830aae8fec514f95f3104ba4473bc6febb98137016c5d0816f859ba440"
},
{
"question": "x**2 + 2*x + 1",
"status": "cache_miss_then_written",
"status": "cache_hit",
"audit_mode": "CANONICAL_PROJECTION",
"pi_star_ref": "algebra-symbolic@v1",
"canonical_answer": "Add(Pow(Symbol('x'), Integer(2)), Mul(Integer(2), Symbol('x')), Integer(1))",
"agreement_label": "KERNEL-LLM-DIVERGED",
"agreement_label": "LLM-DIVERGED",
"llm_raw": "1",
"llm_canonical_match": false,
"cache_status": "ABSENT",
"wall_ms": 120.1,
"cache_status": "ok",
"wall_ms": 147.3,
"audit_event_hash": "d307d6990527ddc6af73ea3cb894d4986ea3003106723fe74e22282f16eb62c6"
}
]

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"

View file

@ -76,7 +76,7 @@ Newest first. Update on every open/close.
| #000021 | 5S/5T/5R benchmark fixtures + harness | closed · Phase 1a + 2 landed 2026-05-08 | 2026-05-07 | — |
| #000020 | Capital-cost ledger (8-capital queues) | closed · landed 2026-05-07 | 2026-05-07 | — |
| #000019 | Specification methodology for π* and V | closed · landed 2026-05-07 | 2026-05-07 | — |
| #000018 | Adversarial soft-hash covert-channel analysis | open · awaiting go/no-go | 2026-05-07 | — |
| #000018 | Adversarial soft-hash covert-channel analysis | closed · landed 2026-05-09 (analysis doc) | 2026-05-07 | — |
| #000017 | Memory-root: lifelong learning audit chain | closed · landed 2026-05-07 | 2026-05-07 | — |
| #000016 | ZK Phase-2 frontier proof (concretize) | open · awaiting go/no-go | 2026-05-07 | — |
| #000015 | π* domain library + cross-domain composition | closed · landed 2026-05-07 | 2026-05-07 | — |

View file

@ -0,0 +1,432 @@
# Soft-hash covert channel analysis
**Ticket:** #000018
**Authored:** 2026-05-09
**Audience:** fox + future blackops shifts + downstream Merkle-AGI v7+ authors
**Stance:** defensive only — detection / flagging / bound-derivation, never
generation or concealment.
---
## 0. Executive summary
We analyze whether an adversary controlling some fraction of training
data, gradient computation, or hyperparameter scheduling can drive a
v7-§9 plastic-trained model so that its **next snapshot's hard hash
`C(M_{t+1})`** lands on a prearranged target value or value-class,
exploiting the soft-hash anchor map `φ` as a side-channel.
Result, under the assumptions stated in §5:
> **Under threat models T1 (data poisoner) and T2 (gradient adversary),
> the channel is bounded by a SHA-256 partial-preimage hardness
> reduction (§4). Under T3 (hyperparameter adversary), the channel is
> bounded by the per-checkpoint mitigation budget M2 (re-randomized
> anchors); residual channel without M2 is at most O(log N · entropy
> of training-data choices) bits per checkpoint window.**
Recommended mitigation: **M2 (per-checkpoint anchor nonce)**, costing
one additional commit field per snapshot. Falls back to **M1 (PRG-based
φ)** if a deployment surfaces residual structure. M3 (drop the anchor)
is the strict-construction fallback if both fail; loses some training
ergonomics.
This document is doc-only per the ticket's hard constraint: it
recommends, does not implement. A follow-up ticket lands the chosen
mitigation.
---
## 1. Threat model
Three adversary capabilities, increasing in strength.
### 1.1 T1 — Data poisoner
Adversary controls a fraction `f ∈ (0, 1)` of training-data examples.
Training loop is honest; aggregator is honest; hyperparameters are
honest; `φ` is the published deterministic embedding. Poisoned
examples are valid in distribution (otherwise an outlier filter
catches them).
**Goal:** poisoned examples drive `Q(Θ_{t+1})` to a region whose soft
hash `h_v(t+1)` projects to a SHA-256 bucket the adversary can predict.
Concretely: adversary tries to land `C(M_{t+1})` in a target class
`T ⊂ {0,1}^{256}` with `|T|/2^{256} = ε` (so the 'class' could be
"first byte 0xAA" → ε = 2^-8, or "specific 256-bit value" → ε = 2^-256).
### 1.2 T2 — Gradient adversary
T1 + adversary controls a fraction `g` of gradient computations
(e.g., compromised data-parallel worker that returns dishonest local
gradients to the central aggregator). Aggregator is still honest.
Adversary can bias the gradient signal in arbitrary directions —
not bounded to legitimate-data-distribution reach. Tighter than T1.
### 1.3 T3 — Hyperparameter adversary
T2 + adversary controls some learning-rate / scheduler / batch-order
decisions. Adversary can synchronize gradient updates with anchor
geometry to maximize alignment. Strictly stronger than T2.
### 1.4 What's NOT in scope
- Direct attack on `C(M_t)` itself (preimage-attack on SHA-256). Out
of scope by A3 in v7 §3 (collision-resistant hash assumption).
- Side-channel on training infrastructure (Spectre, RowHammer,
compromised CPU). Different threat model.
- Adversary controlling the published `φ` seed retroactively. Once
φ's seed is public, it's frozen; this ticket assumes seed is
honestly drawn at v7 boot.
- Compromised aggregator that lies about the snapshot bytes.
Different threat model — that's a checkpoint integrity attack,
not a covert channel.
---
## 2. v7 § 9 plastic training, recap
The relevant slice of the v7 spec:
```
Θ — model parameters (continuous, ~10^9 floats)
Q(Θ) — public quantization of Θ (SQD §3, integer kernel)
C(M) — SHA-256(canonical-encoding of Q(Θ) ∥ metadata)
↑ THE HARD HASH — committed bytes
h_v(Θ) — soft hash, dim_h-vector function of Θ
↑ THE SOFT HASH — used during training only
φ(C(M)) — anchor map: SHA-256 digest → dim_h vector
↑ FIXED DETERMINISTIC, published seed
```
Plastic training loss at step t:
```
L_total(Θ_t) = L_task(Θ_t) + α · ‖h_v(Θ_t) - φ(C(M_{t-1}))‖²
↑ L2 anchor pull
```
The anchor term pulls the model's soft hash toward the embedding of
the *previous* checkpoint's hard hash. At each checkpoint boundary t →
t+1, we compute Q(Θ_{t+1}) → C(M_{t+1}) and that becomes the next
anchor.
The dual-hash separation theorem (T6, v7 §3): C(M) is determined
solely by Q(Θ) and metadata; soft-hash bytes never enter the
SHA-256 preimage. **First-order conclusion:** training cannot
directly affect committed bytes.
The covert-channel concern: training does affect Q(Θ) (that's what
training does). The question is whether the L2 anchor term lets the
adversary *steer* Q(Θ) toward a target SHA-256 bucket.
---
## 3. Channel capacity definition
Define the **per-checkpoint covert channel** as the mutual information
```
I_t = I(adversary inputs at training step ≤ t ; C(M_{t+1}))
conditional on the public training history H_{≤t}
```
The conditioning on `H_{≤t}` (public training history: published
losses, public hyperparameters, public seeds) removes the
"adversary trivially knows what they did" channel. We measure the
bits the adversary can steer ABOVE the public information's
predictive power.
A non-adversarial bound: under random training, `C(M_{t+1})` is
near-uniform on `{0,1}^{256}` conditional on `H_{≤t}` if `Q(Θ_{t+1})`
is sufficiently varied. Adversarial bound is the question.
### 3.1 Capacity bound under random `φ`
If `φ` is modeled as a random oracle independent of the parameter
geometry, then `h_v - φ(C(M_{t-1}))` is a uniform random direction at
each checkpoint, and the L2 pull provides no parameter-aligned
gradient signal. Under this idealization, the covert channel
reduces to:
```
I_t ≤ I(adversary inputs ; Q(Θ_{t+1}))
conditional on H_{≤t}
```
…which is the un-amplified channel — adversary is no better off
through the soft-hash side-channel than they would be attacking
Q(Θ) directly.
### 3.2 Capacity bound under structured `φ`
If `φ` has algebraic structure relative to parameter geometry (the
v7 reference `embed_hard_to_vec` is a fixed-seed linear projection
of the SHA-256 digest), the bound depends on whether gradient
updates that minimize the L2 anchor term are *parameter-aligned* to
shifts in `Q(Θ)` that move SHA-256 buckets predictably.
The reduction in §4 shows this dependency reduces to a SHA-256
partial-preimage problem.
---
## 4. Reduction to SHA-256 partial-preimage
### 4.1 Reduction sketch
Suppose adversary `A` exists that, given black-box training oracle
access under T1/T2, can drive `C(M_{t+1})` into a target class `T` of
density ε with non-negligible probability `p`.
Construct algorithm `B` that solves SHA-256 partial-preimage:
```
B(target T):
1. Initialize a fresh v7 plastic-training run with random seed.
2. Run A as a sub-routine, supplying T as the target class.
3. After A signals success on checkpoint t+1, output Q(Θ_{t+1}).
4. Q(Θ_{t+1}) is then a partial preimage of T under SHA-256.
```
`B`'s success probability is `p` minus the probability that `A`
succeeds via legitimate-Q-randomization (i.e., `B` would have
solved the problem by random Q-search anyway). Under the standard
random-oracle model for SHA-256, the random-Q baseline is `ε`. So:
```
P[B solves partial-preimage] ≥ p - ε
```
If `p > ε + δ` for any non-negligible `δ`, then `B` is a non-trivial
SHA-256 partial-preimage attacker — contradicting A3 (collision-
resistance / partial-preimage hardness).
**Conclusion:** under the SHA-256 random-oracle assumption (A3),
no T1/T2 adversary can succeed with probability non-negligibly
above ε. The channel exists but is bounded at the random baseline.
### 4.2 Where the reduction is tight, where it's loose
**Tight:** when `φ` is independent of parameter geometry (M1 or M2
applied), the reduction is essentially exact. T1/T2 are bounded to
the random baseline.
**Loose:** when `φ` has structure relative to parameter geometry
(reference v7 `embed_hard_to_vec` with fixed-seed linear projection),
the gradient feedback through the anchor MAY favor parameter
directions correlated with target SHA-256 buckets. We don't know
whether this correlation is large enough to break the reduction
without explicit structural analysis of `embed_hard_to_vec`.
This is the residual gap §6 addresses.
### 4.3 T3 caveat
T3 (hyperparameter adversary) is NOT bounded by the §4.1 reduction
directly. The reduction assumes A's queries to the training oracle
follow the published schedule. T3 violates that. Under T3:
- Adversary can synchronize gradient bursts with anchor geometry
via learning-rate schedule manipulation.
- Per-checkpoint channel capacity grows with the adversary's
schedule-control budget.
T3 needs M2 (re-randomized per-checkpoint anchor) or M3 (drop
anchor). M1 alone may not suffice.
---
## 5. Assumptions on `φ`
Three concrete `φ` choices, with channel-residual under each:
### 5.1 `φ_linear` — v7 reference (linear projection, fixed seed)
```
φ(digest) = W · digest_as_uint32_vector (W frozen at boot)
```
- **Pros:** fast, deterministic, simple.
- **Channel residual:** unclear without explicit structural analysis
of W relative to the parameter Hessian. If W has any direction
aligned with a low-eigenvalue direction of the loss Hessian, the
L2 pull provides cheap parameter movement that aligns with
SHA-256 buckets — exploitable under T2 with empirical effort.
- **Verdict:** the reduction in §4 is loose under `φ_linear`.
### 5.2 `φ_PRG` — non-linear PRG-based map (mitigation M1)
```
φ(digest) = PRG(seed=published, output_len=dim_h * 4 bytes)
then bytes → floats in [-1, 1]
```
PRG output is computationally indistinguishable from random under
the PRG security assumption. Gradient feedback through the anchor
is uncorrelated with parameter-space updates that would shift hash
bytes predictably.
- **Channel residual:** zero modulo PRG security (one-way function
+ no algebraic structure for the parameter Hessian to exploit).
- **Verdict:** §4 reduction is tight under `φ_PRG`.
### 5.3 `φ_nonce` — re-randomized anchor (mitigation M2)
```
At each checkpoint t, sample fresh random nonce n_t (committed
in the snapshot manifest). Compute anchor as
φ(C(M_{t-1}) ∥ n_t)
where φ is φ_linear or φ_PRG. Adversary can't precompute against
the next anchor because n_t is unknown until commitment.
```
- **Channel residual:** even under `φ_linear` base, T1/T2 adversaries
can't pre-plan attacks because the gradient direction they want
to steer toward is randomized between checkpoints.
- **T3 residual:** still bounded — T3 adversary controls timing,
not the nonce. Per-checkpoint window is `O(steps) × per-step
channel`; the nonce reset zeroes the cumulative steerage.
- **Verdict:** lightweight; only adds 32 bytes to the manifest per
checkpoint. Closes the residual channel for T1/T2 entirely;
bounds T3 by a per-window budget.
### 5.4 `φ` dropped — anchor term removed (mitigation M3)
`L_total(Θ) = L_task(Θ) + (no anchor term)`.
- **Channel residual:** zero by construction (no soft-hash gradient
signal at all).
- **Loss:** plastic training loses some ergonomics (stable
representation between checkpoints relied on the anchor pull).
Quantified loss: depends on deployment; estimated in v7 §9.7
as 5-15% slower convergence on representation-stability metrics.
- **Verdict:** strict-construction fallback. Recommend only if M1
+ M2 prove insufficient empirically.
---
## 6. Mitigations with residual analysis
| Mitigation | Cost | T1 residual | T2 residual | T3 residual | Closes the channel? |
|------------|------|-------------|-------------|-------------|---------------------|
| **None** (v7 reference) | 0 | bounded by §4 reduction (loose under φ_linear) | bounded by §4 reduction (loose under φ_linear) | unbounded structurally | No |
| **M1 — φ_PRG** | fast PRG eval per checkpoint | tight bound at random baseline ε | tight bound at random baseline ε | unbounded (T3 controls timing) | T1+T2 yes; T3 no |
| **M2 — per-checkpoint nonce** | 32 B in manifest per checkpoint | ε | ε | bounded by per-window budget | T1+T2 yes; T3 bounded |
| **M1 + M2** (combined) | both costs | ε | ε | bounded by per-window budget | T1+T2 yes; T3 bounded |
| **M3 — drop anchor** | 5-15% training-ergonomics regression | 0 | 0 | 0 | Yes, by construction |
| **M4 — gradient-budget cap** | per-step gradient-norm clip | bounds adversary's per-step budget | bounds adversary's per-step budget | bounds T3 per-step | Soft bound; doesn't close |
---
## 7. Recommendation
**Land M2 first** (re-randomized per-checkpoint anchor):
- 32 bytes additional manifest field, committed in the snapshot.
- Closes the T1 + T2 channel under any `φ` choice.
- Bounds the T3 channel by per-checkpoint budget (the only
attack window is between nonce-publish and next-checkpoint).
- No training-ergonomics regression — the nonce is purely
per-checkpoint randomization, anchor pull still lands.
**Add M1 (φ_PRG) as Phase 2** if M2-only deployment surfaces
structural concerns (e.g., empirical evidence that T3 attacks
within a window achieve > ε success rate).
**M3 (drop anchor)** stays in reserve as the strict-construction
fallback. v7 §9 spec amendment proposed:
```
v7 §9.10 (proposed): The anchor map φ takes both the prior
checkpoint's hard hash AND a per-checkpoint nonce committed in
the manifest. The nonce is fresh entropy at each checkpoint,
sealed before training resumes. This closes the soft-hash covert
channel under threat models T1 and T2, and bounds T3 by the
per-checkpoint window.
```
---
## 8. Empirical validation (out of scope; follow-up)
A small experiment to sanity-check the analysis:
1. Run v7 §9 plastic training with a deliberately-poisoned dataset
targeting "first byte of `C(M)` equals 0xAA" — that's `ε = 2^-8`.
2. With M2 disabled (`φ_linear`, no nonce): measure success rate
over N checkpoints. Hypothesis: indistinguishable from `ε` if
§4 reduction holds under `φ_linear`; structurally elevated if
`φ_linear` has Hessian-aligned structure.
3. With M2 enabled (`φ_linear`, per-checkpoint nonce): measure
again. Hypothesis: indistinguishable from `ε` regardless of
`φ_linear`'s structure.
4. Same experiment under `φ_PRG`: should match `ε` baseline with
or without M2.
If empirical results diverge from analysis predictions, the
analysis is wrong somewhere — likely in §5 about `φ_linear`'s
structural alignment with the parameter Hessian.
This experiment is a follow-up ticket; not in scope here.
---
## 9. Open questions
The reduction in §4 leaves three loose threads:
1. **Hessian alignment under `φ_linear`.** Is the v7 reference
`embed_hard_to_vec` matrix W aligned with low-eigenvalue
directions of the typical training-loss Hessian? If yes, T2
adversaries with full gradient control can amplify steerage
beyond the §4 random-oracle baseline. **Test:** compute the
spectrum of `W^T W` and compare to typical Hessian eigenvalue
distributions on representative checkpoints.
2. **PRG modeling for `φ_PRG`.** The §4 reduction treats `φ_PRG`
as a random oracle. In practice it's a deterministic PRG with
public seed. The reduction holds modulo PRG security; we
should pick a PRG with cryptographic strength matching SHA-256
(e.g., AES-256-CTR with public IV; or HMAC-SHA-512 expansion).
**Decision:** use HMAC-SHA-512(seed, digest ∥ counter) for
dim_h floats. Keeps the dependency surface (already on SHA-256)
tight.
3. **T3 per-window budget formal bound.** §6 lists "bounded by
per-window budget" without giving the bound. The bound depends
on (a) the per-step adversary control bandwidth, (b) the
between-nonce window length, (c) the gradient-magnitude budget.
**Open:** explicit bound calculation, deferred to either a
v7 §9.10 spec amendment or a follow-up ticket.
---
## 10. References
- v7 § 3 (T6 dual-hash separation theorem)
- v7 § 9 (plastic training; the source of the L2-anchor term)
- v7 § 9.9 (the "backdoor via soft hash" first-order dismissal we're
superseding)
- SQD § 3 (hard-hash construction for Q(Θ))
- SQD § 5 (integer-kernel discipline; bigint accumulator)
- ticket #000018 (this document is the closure deliverable)
---
## 11. Status
**Open questions:** §9.1 (Hessian alignment under `φ_linear`),
§9.2 (PRG cryptographic strength for `φ_PRG`), §9.3 (T3 per-window
explicit bound).
**Closed:** §4 reduction shows T1/T2 are bounded by SHA-256 partial-
preimage hardness under any `φ` independent of parameter geometry.
M2 (per-checkpoint nonce) closes residual channels at minimal cost.
**Recommendation:** v7 spec amendment §9.10 lands the M2 nonce.
Implementation ticket follows.
**Doc closure criterion** (per #000018 §7): reduction stated, mitigation
recommended, residual-bound table present (§6). Done.

View file

@ -1,6 +1,6 @@
# Ticket #000018 — Adversarial soft-hash covert channel analysis
**Status:** open · awaiting go/no-go
**Status:** closed · landed 2026-05-09 (analysis doc at `docs/soft-hash-channel-analysis.md`)
**Opened:** 2026-05-07
**Scope:** Formal threat model + falsifier set for whether training
gradients can route information from training data through soft hashes