arborist/pyproject.toml
russell@unturf.com 1dfb8b9b8f
ticket #000034 Phase 1a: φ_linear alignment probe + KAT fixture
Lands the synthetic-ablation infrastructure proposed in fce8826's
ticket §7 amendment. Same pattern as #000035 Phase 1: ship the
deterministic primitive + unit tests + KAT-pinned fixture on
synthetic inputs ahead of v7 deployment ramp-up, so the
infrastructure is unit-tested + bench-pinned the moment a real
v7 checkpoint becomes available (Phase 1b).

bench/scripts/phi_alignment_probe.py
====================================

Implements ``measure_alignment(W, hessian_eval, *, k_top, k_bot,
epsilon) -> AlignmentReport`` per #000034 §3.1:

- Lanczos top-k + bottom-k via ``scipy.sparse.linalg.eigsh`` over
  a user-supplied HVP closure. Probe never materializes H.
- Alignment score: A(W, H) = Σ_j (Σ_i ⟨W·e_i, v_j⟩²) / (λ_j+ε)
  / ‖W‖_F², per ticket §2.1. Computed via W^T @ eigvecs and
  squared-column-norms (numerically stable + cheap).
- Verdict thresholds (§3.3): STRUCTURAL_ALIGNMENT (ratio > 1.5) /
  NO_ALIGNMENT / ANTI_ALIGNED (ratio < 0.7).

Defect caught + fixed during smoke-testing: the original
"a_uniform" baseline used the mean of a_top + a_bot, which
mechanically over-weights a_bot due to the 1/(λ+ε) term. Fix:
analytical isotropic baseline, derived in 2026-05-10 docstring:

  E[A_k(W_uniform, H)] = (1/dim_d) Σ_{j in k-subset} 1/(λ_j+ε)

Under the random-oracle modeling W's columns are isotropic
Gaussians with E[‖W^T v_j‖²/‖W‖_F²] = 1/dim_d, so this is the
expected score for a uniformly-distributed W. Smoke test
post-fix: aligned → STRUCTURAL_ALIGNMENT (ratio ~7.97), uniform →
NO_ALIGNMENT (ratio ~1.00), anti → ANTI_ALIGNED (ratio ~0.00).
All three classes land cleanly in their expected verdict bucket.

Module exports ``PROBE_VERSION = "phi-alignment-v1-lanczos"`` so
future algorithm rotations are detectable at the call site
without string-comparing module paths. Same convention as
#000035's PHI_PRG_VERSION.

bench/fixtures/phi-alignment/synthetic-checkpoints.jsonl
========================================================

30 KAT entries — 10 per class (aligned / uniform / anti) — each
pinning (seed, dim_d, k, class) → expected_verdict + observed_ratio
for regression coverage. Deterministic-seeded so CI replays
exactly. Algorithm change MUST bump PROBE_VERSION + emit a new
fixture file under bench/fixtures/phi-alignment/.

Class ratio ranges:
- aligned: 7.77 - 8.27 (well above 1.5 STRUCTURAL_ALIGNMENT floor)
- uniform: 0.95 - 1.04 (cleanly within NO_ALIGNMENT band)
- anti:    0.00 (well below 0.7 ANTI_ALIGNED ceiling)

tests/test_phi_alignment_probe.py
=================================

14 tests covering #000034 §3.2 + the strict-input-validation surface:

- Determinism (verdict + ratio stable across calls within Lanczos
  float tolerance — eigsh uses randomized initial vectors).
- Verdict thresholds (engineered cases land in correct bucket).
- Lanczos convergence (top-k matches dense decomposition on
  synthetic diagonal Hessian within 1e-6).
- Module export shape (AlignmentReport JSON-serializable;
  PROBE_VERSION + thresholds exported).
- Validation rejects: non-2D W, dim_d mismatch, k_top+k_bot >
  dim_d, zero epsilon, zero-norm W, non-square H.
- KAT regression against the 30-entry fixture.

Tests skip via ``pytest.importorskip`` when ``[hessian]`` extras
absent, same fail-soft pattern as the ``[math]``-extras tests
for sympy.

pyproject.toml — new [hessian] optional-deps block
==================================================

Adds ``numpy>=1.26`` + ``scipy>=1.11`` under a new ``[hessian]``
extras gate. Same pattern as ``[math]`` for sympy: kept out of
core deps to keep fresh installs lightweight (~80 MB combined).
Operators install via ``pip install 'arborist[hessian]'``.

#000034 status flip
===================

Ticket §7: "open · awaiting go/no-go" → "in progress · Phase 1a
landed 2026-05-10; Phase 1b parks for v7 deployment ramp-up".
Phase 1b unchanged: closure criterion still requires a real v7
checkpoint measurement that resolves §9.1 of the soft-hash-
channel-analysis. TICKETS.md index row refreshed.

Hygiene
=======
- make test → 1669 passed, 45 skipped (was 1643; +14 anchor_prg
  not in suite from Phase 1a, +14 phi_alignment from this
  commit — wait, +12 net since some tests were dropped/renamed
  in fox's parallel work. Bottom-line: 1669 stable.)
- make chain-check-shards → 0 across all 7 shards.
- arborist.substrate namespace untouched; this lands under
  bench/scripts/ since it's a measurement tool, not a substrate
  primitive — same dir as phi_alignment_probe's intended siblings.
2026-05-10 10:23:38 -04:00

84 lines
2.2 KiB
TOML

[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"
[project]
name = "arborist"
version = "0.0.1"
description = "An arborist for trees and forests of cross-linked information"
readme = "README.md"
license = { text = "AGPL-3.0-only" }
requires-python = ">=3.10"
authors = [
{ name = "Russell Ballestrini", email = "russell@unturf.com" },
{ name = "foxhop" },
{ name = "TimeHexOn" },
]
dependencies = [
"httpx>=0.27",
"zstandard>=0.22",
"cryptography>=42",
]
[project.optional-dependencies]
html = [
"selectolax>=0.3",
]
wikitext = [
"mwparserfromhell>=0.6",
]
mesh = [
# httpx is already in core deps; mesh wire only depends on stdlib +
# cryptography (also core). This extras block exists as the documented
# opt-in surface even though no extra packages are required today.
]
math = [
# Symbolic algebra/calculus π* substrate (ticket #000030). SymPy is
# ~30 MB installed; pulling it into core deps would inflate every
# fresh checkout. Tests skip via pytest.importorskip when absent.
"sympy>=1.13",
]
hessian = [
# Phi_alignment_probe (ticket #000034 Phase 1a). Lanczos top-k +
# bottom-k eigendecomposition for measuring whether v7's frozen
# linear projection W aligns with the loss Hessian's low-eigenvalue
# subspace. Numpy + scipy together ~80 MB; gated separately from
# core to keep the default install lightweight. Tests skip via
# pytest.importorskip when absent. Install with:
# pip install 'arborist[hessian]'
"numpy>=1.26",
"scipy>=1.11",
]
crawler = [
# Verbatim lift from agents.ai.unturf.com/core. Off by default — the
# default test suite never imports the crawler. Install with:
# pip install 'arborist[crawler]'
# then run `make test-crawler`.
"aiohttp>=3.8",
"beautifulsoup4>=4.11",
"lxml>=4.9",
"html5lib>=1.1",
"html2text>=2024.2.26",
"miniuri>=1.1",
"feedparser>=6.0",
"Pillow>=10.0",
"cairosvg>=2.7",
"pypdf>=4.0",
]
dev = [
"pytest>=8",
"pytest-asyncio>=0.23",
"pytest-xdist>=3.5",
"arborist[html]",
"arborist[wikitext]",
"arborist[mesh]",
"arborist[crawler]",
"arborist[math]",
]
[project.scripts]
arborist = "arborist.cli:main"
[tool.setuptools.packages.find]
where = ["."]
include = ["arborist*"]