Commit graph

411 commits

Author SHA1 Message Date
fc5ba507dc
tests/doc_counts: regression test for numeric claims in docs/ (4x drift fix)
The doc-drift pattern recurred four times today on 2026-05-10
(commits 6cbbf95, 14bcb99, 5c21e83, 30a9488). Each fix was the
same shape: walk a doc, find a count that drifted from live truth
during the hours after the doc was written, refresh it. Cost: ~5
min per drift × 4 = 20 min of manual catching, with no guarantee
the next drift gets caught before someone external reads it.

Per fox's selection: regression test that makes drift loud at
test time instead of relying on visual catching.

== Mechanism ==

`tests/test_doc_counts.py` scans `docs/**/*.md` for AUTOCOUNT
tags of the form:

  <!--AUTOCOUNT:metric:path-->N<!--/AUTOCOUNT-->

Two metrics supported:

- `tests` — pytest collected count for path. Batches every
  tagged path into one `pytest --collect-only` subprocess
  (~0.5s total).
- `fixture-rows` — non-blank-non-comment line count in a JSONL
  fixture.

GitHub and most markdown renderers strip HTML comments, so
readers see only `N`. The tags are invisible in rendered output
but make the claim machine-checkable. Three tests in the file:

1. `test_doc_autocount_claims_match_live` — the core invariant
2. `test_autocount_tags_are_well_formed` — open/close balance
3. `test_autocount_metric_names_are_documented` — fail-closed on
   undocumented metrics (catches typos)

Failure message names the doc file, line number, and the
claimed-vs-live diff. Example:
`docs/foo.md:42 AUTOCOUNT(tests:tests/test_x.py) claims 23, live is 27`

== 29 tags installed across 5 docs ==

While installing tags I had to read the surrounding prose, which
surfaced six stale counts that had drifted same-day:

`docs/soft-hash-channel-analysis.md`:
- L392 14 → 23 tests for phi_alignment_probe
- L417 20 → 27 tests for anchor_prg
- L463 14 → 23 tests for phi_alignment_probe (status section)

`docs/seven-point-program.md`:
- L77 68 → 58 tests for metacognition (drift -10; the file
  shed tests during a refactor and the doc didn't catch up)
- L78 9 tests for `test_dag.py::test_preflight_*` — removed
  count entirely; pytest selector subsets aren't currently
  supported by the AUTOCOUNT metric set (would need a
  `tests-matching` metric; not worth the surface for one claim).
- L110 24 → 33 tests for test_dag.py

`docs/calculator-test-patterns.md`:
- L35 33 → 23 tests for warrant_resolver
- L35 10 → 9 tests for warrant_chain
- L16, L265 51 → 53 tests for t3_bound_calculator (kept
  initial-shipment provenance in prose)

== Coverage installed ==

  calculator-test-patterns.md           3 tagged claims
  soft-hash-channel-analysis.md         5 tagged claims
  warrant-substrate-cookbook.md        14 tagged claims
  seven-point-program.md                3 tagged claims
  tickets/ticket-000006-bench-...      4 tagged claims
                                      ---
                                       29 tagged claims

Every count that drifted today is now tagged. Future drift
fires the regression test at the next pytest run instead of
waiting for human catching.

== Discipline pattern ==

Walk this pattern for any new doc that names a count:

1. Surround the number with the tag pair:
   `<!--AUTOCOUNT:tests:tests/test_foo.py-->N<!--/AUTOCOUNT-->`
2. Run `pytest tests/test_doc_counts.py` (~3.5s)
3. If it passes, the claim is now machine-verified

Aim to tag counts on first authorship. Retrofitting is cheap
but only catches drift after the fact.

== Out of scope ==

Test counts inside source code (docstrings, CLI --help) are not
scanned — would expand the test surface significantly and the
drift pattern hasn't manifested there. Add `**/*.py` scope when
that pattern surfaces.

Alias-row counts and claim-pack-record counts could be tagged
with new `db-rows:<table>` and `db-where:<sql>` metrics; deferred
until the next drift on those numbers (none caught today after
30a9488's cookbook refresh).

== Verification ==

  $ .venv/bin/pytest tests/test_doc_counts.py -v
  3 passed in 3.89s

  $ .venv/bin/pytest -q
  2276 passed, 54 skipped in 153.21s

No new dependencies. No schema changes. No source-code changes.
2026-05-10 16:15:52 -04:00
fd643fe1a5
#000012 Phase 1b: Merkle-AGI v8 consensus paper landed
`docs/_source/merkle-agi-v8-consensus.rst` (834 lines, RST sister
to the v7-W substrate paper at the same path). Closes Phase 1b of
ticket #000012 — the loop-closing consensus protocol that turns
single-validator Proof-of-Upgrade into Darwinian selection across
an open validator set.

11 parts:

  Part 1   Introduction & motivation — gap table from v7 § 13.4,
           concrete backdoor-attack scenario, paper IS/IS-NOT
           scope.
  Part 2   Substrate definition — SQD A1/A2/A3 inheritance,
           consensus_events row schema, consensus_policy_hash
           sibling (never enters cache_key).
  Part 3   Validator state machine — bonding/active/challenged/
           slashed/unbonding with full transition graph + invariants.
  Part 4   Acceptance protocol — proposer submission, layered
           fitness floor (canonical + lab-declared ceiling),
           audit-replay procedure, 2/3-stake quorum + GRANDPA-
           style finalization, liveness floor.
  Part 5   Challenge protocol — counter-evidence shape,
           adjudication, challenger reward, frivolous-challenge
           bond.
  Part 6   Stake mechanics — bond/unbond/challenge window
           recommendations, offense-class slashing schedule,
           reward distribution, optional stake cap + sqrt-weighting.
  Part 7   Fork choice rule — GRANDPA-style finality, pre-finality
           constraints, liveness recovery.
  Part 8   Mesh wire format extension — three new message kinds,
           BLS-or-concat aggregate signatures, bandwidth profile.
  Part 9   BFT analysis — safety, liveness, Sybil resistance,
           bootstrap honesty, re-staking attacks.
  Part 10  Worked example — 7-validator deployment, one upgrade
           cycle with successful challenge against one fraudulent
           validator.
  Part 11  Out of scope — implementation, calibration, cross-chain
           anchoring, fixture selection, bootstrap-set membership,
           cross-instance slashing accumulator, branch-set
           persistence.

Closure §: open questions tracked separately (initial validator
set composition, threshold-key ceremony, ZK-replay, policy-hash
transition mechanics).

Ticket #000012 status updated; Phase 1c (branch-set persistence)
remains proposed-not-opened. Implementation follow-up tickets that
cite this paper land later — one per validator-state-machine,
mesh-wire-format extension, audit-replay harness, slashing
accountant.
2026-05-10 16:12:00 -04:00
883289d00e
#000025 Phase 1e: 5F falsification motif coverage (§10.12 closed)
Pre-Phase-1e: falsification-v1.jsonl covered 10 motif tags across 50
fixtures (the high-traffic warrant/title/anchor/format set). Phase
1e adds 12 fixtures (5f-fal-051..062) for the previously-uncovered
motifs from the verifier+soft-demote registries:

  CITATION_MISMATCH            DEFLECTION_DETECTED
  MANUAL_QUOTE_VIOLATION       SCHEMA_INVALID
  SOURCE_ROLE_BLOCKED          SUBJECT_TOKENS_ABSENT
  TOO_MANY_EVIDENCE_IDS        UNKNOWN_EVIDENCE_ID
  BROAD_QUANTIFIER_RUNAWAY     BROAD_QUANTIFIER_CAP_APPLIED
  BROAD_QUANTIFIER_SCOPE_UNBOUND  BROAD_QUANTIFIER_REJECTED

Coverage now: 22 unique motif tags across 62 fixtures.

Harness changes:
- test_bench_batteries.py: bump pass_count assertion 50 → 62 in both
  falsification tests; add test_5f_falsification_covers_every_documented_motif
  that pins the motif set against the verifier+soft-demote registries
  so adding a new violation upstream surfaces here as a missing
  fixture (loud signal, no silent drift).
- test_session_integration.py: bump full-suite total 662 → 674.

Closes #000025 §10.12 (every documented failure-motif tag).
Still open in Phase 1b: §10.11 (real shard finetuning chains),
§10.13 (Feedback Loop latency/efficiency against real workload),
§10.14 (threshold handoff to #000012).
2026-05-10 16:04:34 -04:00
30a9488578
docs/cookbook: non-test-count drift sweep — 3 staleness fixes
Sweep after closing the #000006 amend refresh: three areas in
warrant-substrate-cookbook.md drifted apart from TICKETS.md
authoritative status while the day-long substrate/alias sprint
was running.

Findings:

1. **Line 422 `#000041` count stale**: cookbook listed "54 live
   rows"; TICKETS.md row authoritative since 2026-05-10:
   "74 rows live as of 2026-05-10 (count grew 40 → 54 → 74)".
   Live `arborist alias citation list | wc` = 74. Refresh.

2. **Line 416 cascade-completion-state line ambiguous**: the
   `# → 92 / 92 (100%) under the 18-substrate + 54-alias state`
   comment is in the `make textbook-*` re-run code block. Read
   as "current state of a re-run today" it's stale (74 not 54);
   read as "historical state at 100% achievement" it's accurate.
   Refreshed to current state with explicit `(counts as of
   2026-05-10)` so a future reader knows what era it pins to.
   Split out citation vs term aliases since both feed cascade.

3. **Title-from-author backfill section over-states the
   workaround**: cookbook framed the SQL UPDATE pattern as
   "Workaround until source-side fix lands". The source-side
   fix already shipped — commit `551c969` 2026-05-10 (#000031
   follow-up B-2: `--author` flag in HTML + textbook_tex +
   crawler ingest paths; every `make textbook-*` Makefile
   target already wires it). The SQL pattern is now legacy
   fix-up for already-ingested shards that pre-date B-2;
   refresh the section header + body to reflect that.

Other claims sanity-checked + accurate:

- Line 122 `4 term-aliases` for Pillar VI Newton vocab — live
  domain breakdown is 5/4/4 (arithmetic / classical-physics /
  geometry); 4 classical-physics matches.
- Line 350 `(74 rows live as of 2026-05-10)` — accurate.
- Pillar I-IX record counts (13/10/13/18/5/5/14/14 = 92) —
  matches live `SELECT COUNT(*) FROM documents WHERE
  source_type='claim_pack'` in shard 000.db (92).
- Phase-status references on lines 261/373/424/458/494/499/512
  — all internally consistent with TICKETS.md authoritative
  statuses (#000031 closed, #000034/35/36 Phase 1 in progress,
  #000038 Phase 4 still-blocked).

Hygiene: docs-only commit, no schema, no tests. Pre-existing
order-dependent flake on test_full_suite_total_fixture_count
unrelated; test passes in isolation.

2326 tests collected; 1799 + 53 skipped pass when run with -x.
2026-05-10 16:02:28 -04:00
8916bf3728
soft-hash T3 bound: pre-review polish pass for external cryptographer
Four targeted edits before forwarding to dav1d:

1. Add §0 cover note — names the three things the reviewer should
   confirm (decomposition, per-surface derivations, conservative-
   constant choice) and what's explicitly out of scope (empirical
   validation against a real adversarial-training run).

2. Tighten §2 decomposition. The previous text invoked DPI to
   produce an additive split I(A;C) ≤ I(A;Θ) + I(Θ;C), which DPI
   alone doesn't justify. Replace with a clean Markov-chain DPI
   statement (A → Θ → C(M) is a Markov chain conditional on
   (H_{≤t}, n_t); DPI gives I(A;C) ≤ I(A;Θ)) and frame the T1+T2
   baseline as threat-model-additive (disjoint adversary surfaces),
   not information-additive in the same MI sense.

3. Rename §3 'Apply Fano's inequality' → 'discrete-distinguishability
   counting'. The derivation log₂(SNR+1) is the discrete channel-
   capacity bound on K distinguishable outputs, not Fano's
   inequality (which bounds error probability from MI). Add an
   explanatory note that LR factors cancel per-step (LR's distinct
   channel contribution is §4, not double-counted here). Update §10
   item 1 cross-reference for the same naming consistency.

4. Resolve §5 conjecture. Move the random-shuffle conjecture out of
   the headline derivation; commit C_B3 = 1 strictly under the
   adversarial-order assumption stated in §5. The random-shuffle
   tightening C_B3 → O(1/√N_b) stays referenced via §10 + #000043
   as the formal tightening path operators can opt into via the
   --c-b3 calculator flag.

No numeric examples changed; no calculator behavior changed; no
reference list changed. Pure pre-review polish to remove three
specific things a careful cryptographer would catch and ask
about, plus a cover note that frames the kind of review wanted.
2026-05-10 15:59:16 -04:00
2585d3c718
tests/pi_star_time_series: 35 KATs for temporal-signal kernel
Backfills partial-only coverage on arborist/pi_star/time_series.py
(172 lines, 2026-05-10 zero-coverage sweep). KATs mirror the
docstring's equivalence classes: timestamp/value jitter within
Δ_t/Δ_v, out-of-order samples sort to canonical, duplicate
timestamps collapse with last-value-wins. Pins banker's rounding
(ties-to-even: 0.5→0, 1.5→2, 2.5→2). Pins int-vs-float dt/dv
equivalence when integer-valued. Negative cones: missing required
field, non-positive dt/dv (zero, negative, wrong type), malformed
sample pairs, samples-not-array, non-object root, non-JSON, non-
bytes. Plus projective contract: re-canonicalizing the text output
raises PiStarError.
2026-05-10 15:54:55 -04:00
593550b1e3
tests/pi_star_code: 32 KATs for Python-AST kernel
Backfills minimal-only coverage on arborist/pi_star/code.py (123
lines, 2026-05-10 zero-coverage sweep). KATs mirror the docstring's
equivalence classes: whitespace/indent/comment/quote-style/numeric-
formatting (1_000 ≡ 1000) invariance vs identifier/operator/arg-
order distinctness. Pins critical isinstance(bool) ordering (bool
subclasses int, must dispatch first to avoid encoding True as 1).
Pins lexical _fields sort (cross-Python-version determinism). Pins
position-field exclusion (lineno/col_offset never appear in
canonical output). Plus projective contract: re-canonicalizing the
S-expression output raises PiStarError (not valid Python).
2026-05-10 15:54:49 -04:00
e7bef5ff68
tests/pi_star_logic: 53 KATs for propositional CNF kernel
Backfills zero dedicated coverage on arborist/pi_star/logic.py
(371 lines, 2026-05-10 zero-coverage sweep). KATs mirror the
docstring's equivalence classes: commutativity, associativity,
IMPL/IFF/XOR rewrites, De Morgan, double negation, distribution,
idempotence, within-clause tautology drop. Pins v1's documented
limitation: A AND NOT A is NOT collapsed (multi-clause
contradiction detection is out of scope; only empty clauses
surface as FALSE). Negative cones: >8 atoms, unrecognized token,
unexpected char, unbalanced paren, unconsumed tokens, dangling
operator, empty, non-bytes. Plus determinism + lexical-sort
canonicalization.
2026-05-10 15:54:43 -04:00
6c9bc047fd
tests/pi_star_arithmetic: 56 KATs for exact-rational arithmetic kernel
Backfills zero dedicated coverage on arborist/pi_star/arithmetic.py
(188 lines, 2026-05-10 zero-coverage sweep). KATs mirror the
docstring's equivalence-class examples: integer-literal collapse,
decimal → rational exactness (0.1 + 0.2 = 3/10), lowest-terms
reduction, integer exponents. Negative cones: identifier, function
call, non-integer exponent, division by zero, boolean literal,
empty, non-bytes, syntax error. Plus round-trip idempotence and
equivalence-class-id matching across equivalent inputs.
2026-05-10 15:54:37 -04:00
0cb943561a
tickets: close #000026 (Phase 3 landed 60b5748)
Real-shard workload baseline + search latency: Phases 1/2/3 all
landed 2026-05-09. Flip status from "in progress" to closed with
Phase 3 commit reference. Authorship warrant ladder followup (CLI
wiring) noted in ticket body as non-load-bearing — not blocking
closure.
2026-05-10 15:54:32 -04:00
5c21e83b33
ticket #000006 amend: refresh stale test/KAT counts in 2c683de adjacent landings section
fox's 2c683de (#000006 2026-05-10 amend folding my Phase 3
warrant-chain dormancy investigation into the rolling research
log) listed two adjacent same-day landings in §"Adjacent landings
(same-day infrastructure)". Both counts went stale during the
hours after fox's commit, same drift pattern caught earlier
today on the cookbook appendix.

fox's 2c683de timestamp: 13:22 EDT.
- phi_alignment_probe test backfill (a4b3056) landed 14:08 EDT
- The corresponding cookbook appendix refresh (6cbbf95)
  followed shortly after.

Stale counts refreshed:

1. **#000034 Phase 1a entry** (line 725):
   - "14 tests" → "23 tests" (+9 from `a4b3056` 2026-05-10 pattern
     backfill: monotonicity / hand-formula / closure /
     parametrized-invalid per docs/calculator-test-patterns.md)
   - "10-vector KAT fixture" → "30-vector KAT fixture (10 aligned
     + 10 uniform + 10 anti-aligned synthetic checkpoints,
     deterministic-seeded)". The 30 vectors were generated by
     `1dfb8b9` itself; fox's amend simply summarized at "10".
     Refreshed to the actual count + class breakdown.

2. **#000035 Phase 1 entry** (line 729):
   - "20 tests" → "27 tests" (+7 from `de997f7` 2026-05-10 pattern
     backfill: prefix-extension closure invariant, hand-computed
     HMAC-SHA-512 first-block formula, parametrized
     invalid-input cones).
   - "10-vector KAT fixture" → confirmed 10 (matches live).

Verification:

  test_anchor_prg.py            27 ✓
  test_phi_alignment_probe.py   23 ✓
  bench/fixtures/phi-prg/        10 ✓
  bench/fixtures/phi-alignment/  30 ✓

#000006 amend is now zero-drift across all 4 numeric claims in
the adjacent-landings section. The recommendation in §"Verdict"
("track fire rate as a corpus-evolution signal") and the
distinct-signal table both remain accurate as fox wrote them.

Hygiene: docs-only commit, no test or code surface change.
2026-05-10 15:17:13 -04:00
14bcb99db1
docs/cookbook: fill missing test count + refresh test/code ratio after 581ad90
Comprehensive cross-check of the appendix's test counts vs live
`pytest --collect-only` output found two more drift points beyond
6cbbf95's phi_alignment_probe + t3_bound_calculator count
refreshes:

1. tests/test_warrant_resolver.py — appendix described its
   coverage qualitatively but didn't give a count. Live: 23
   tests. Added "23 tests covering ..." prefix.

2. test/code ratio table row for t3_bound_calculator.py was
   "446 351 (51 tests) | 1.4". My 581ad90 added 2 KAT-fixture-
   gap-closure tests + ~95 lines of test code (the
   test_b3_exact_formula + test_t3_bound_known_answer_tests
   functions). Refreshed to "249 | 446 (53 tests) | 1.79".

Comprehensive verification result (all 14 appendix entries
cross-checked against `pytest --collect-only`):

  test_aliases.py                              28 ✓
  test_warrant_resolver.py                     23 (was uncounted)
  test_warrant_chain.py                         9 ✓
  test_textbooks_manifest.py                   43 ✓
  test_anchor_prg.py                           27 ✓
  test_phi_alignment_probe.py                  23 ✓ (refreshed in 6cbbf95)
  test_t3_bound_calculator.py                  53 ✓ (refreshed in 6cbbf95;
                                                  ratio table fixed here)
  test_fork_score.py                           18 ✓
  test_substrate_fork_score.py                 27 ✓ (added in 6cbbf95)
  test_weights.py                              16 ✓
  test_pi_star_protocol_and_registry.py        21 ✓
  test_qa_progress.py                          31 ✓
  test_qa_prompts.py                           20 ✓
  test_concepts_extract.py                     20 ✓

Zero remaining drift. The cookbook appendix is now bit-for-bit
consistent with live pytest collection across all 14 entries.

Hygiene: docs-only commit, no code surface change.
2026-05-10 15:11:55 -04:00
0274be9e0c
pyproject: add [hessian] to dev extras for CI test parity
The earlier audit found one observation: pyproject.toml's `dev`
extras includes arborist[math] (sympy for ticket #000030's
SymPy substrate) but NOT arborist[hessian] (numpy + scipy for
#000034's φ_linear alignment probe).

Without this, fresh checkouts running `make bootstrap` (which uses
`pip install -e '.[dev]'`) skip tests/test_phi_alignment_probe.py
via pytest.importorskip("numpy") + pytest.importorskip(
"scipy.sparse.linalg") at module top. Tests show as
collected-but-skipped instead of actively running. Phase 1a
regressions (algorithm drift, KAT fixture corruption,
threshold-band drift) would only surface when an operator
deliberately ran `pip install '.[hessian]'` first.

Following fox's pattern with `[math]` in dev — arborist[math]
pulls sympy (~30 MB) into every fresh dev checkout so CI runs
test_canonical_projection.py + math π* tests by default.
arborist[hessian] adds ~80 MB combined (numpy + scipy) — a real
cost, but numpy/scipy are nearly universal Python deps and
already installed on most modern dev environments.

Verification:

- ``pip install -e '.[dev]' --dry-run`` now resolves numpy>=1.26
  + scipy>=1.11 (previously did not).
- ``make test`` → 1986 passed, 45 skipped (no new failures; no
  test count change since I already had the extras locally
  installed for #000034 Phase 1a development).

Effect:
- New dev checkout: phi_alignment_probe's 23 tests run by
  default (no skip).
- CI catches algorithm drift / KAT corruption / threshold drift
  in #000034 Phase 1a code on every push, same as how the
  [math] inclusion catches drift in canonical_cache /
  canonical_projection tests.

Test/code ratio (per cookbook appendix § "Unit-test density"):
phi_alignment_probe at 419 test LOC / 200 code LOC = 2.10×
puts it firmly in the "contract-defining foundation" bracket
(≥1× threshold fox flagged for substrate-paper-spec'd
primitives). Matches the discipline.
2026-05-10 15:05:51 -04:00
6cbbf9505e
docs: refresh cookbook appendix counts + reciprocal cross-reference
Walking 6aca7d9 (cookbook test-coverage appendix) surfaced two
findings: (1) two stale test counts since fox wrote the appendix at
2026-05-10 13:11 EDT; (2) the appendix and docs/calculator-test-
patterns.md are complementary lenses but had no explicit
cross-reference. Both fixed in this docs-only commit.

Stale counts refreshed
======================

- `tests/test_phi_alignment_probe.py` "14 tests" → "23 tests".
  Drift cause: my `a4b3056` (2026-05-10 14:08 EDT) added 9
  pattern-backfill tests after fox's appendix snapshot at 13:11
  EDT (~57 min lag).
- `tests/test_t3_bound_calculator.py` "51 tests" → "53 tests".
  Drift cause: my `581ad90` (2026-05-10 ~13:50 EDT) added 2
  KAT-fixture-gap closures after fox's appendix snapshot.

Both refreshes preserve the trajectory by noting the
``+9 from a4b3056`` / ``+2 from 581ad90`` provenance inline. Same
durability pattern fox used in `018a2a1` for the alias-count
refresh + my `6f1dbed` ditto.

Per the appendix-author's own ``unit-test density`` heuristic,
the refreshed counts confirm both files keep their ≥1× test/code
ratio. ``test_phi_alignment_probe.py`` jumps from 268/200 ≈ 1.34
to 419/200 ≈ 2.10× (closer to the contract-defining-foundation
ratio fox flagged for warrant_chain.py at 3.6×).

Missing entry added
====================

`tests/test_substrate_fork_score.py` (renamed from
`test_v8_fork_score.py` in `a4058a4` per the 2026-05-10 v-prefix
retirement) wasn't listed in fox's appendix. The file is the
``arborist substrate score`` CLI surface coverage — adapter tests
+ 4 in-process build_parser CLI tests + 1 real subprocess
invocation. Distinct from `test_fork_score.py` (fox's pure-function
unit tests for ScoredFork at 18 tests).

Added under "Substrate-paper-spec'd primitives" section alongside
test_fork_score.py.

Reciprocal cross-reference
==========================

`docs/calculator-test-patterns.md` (the per-pattern CHECKLIST for
new tests) and `docs/warrant-substrate-cookbook.md § Appendix`
(the per-discipline INDEX of existing tests) are complementary,
not duplicative:

  - Checklist answers: "what should my new tests cover?"
  - Index answers: "where are the tests for X?"

Added each-direction cross-reference paragraphs:

- Cookbook appendix § "Cross-reference" subsection naming
  calculator-test-patterns.md as the checklist for new code.
  When adding a new substrate-paper-spec'd primitive: walk the
  checklist to design the test file, then add a row to the
  appendix under the matching discipline.
- calculator-test-patterns.md § "What this doc is NOT" expanded
  with a bullet pointing readers at the cookbook appendix as
  the existing-test inventory.

Closes the gap where future shifts might find one without the
other and miss half the discipline.

Hygiene
=======
- make test → 1986 passed, 45 skipped.
- Both docs are reference-only; no test or code surface change.
2026-05-10 13:57:00 -04:00
e1ac7c2ea2
bench/full-bench-qa: no regression after substrate+Phase 3 sprint (675 cells)
Full QA-quality sweep, 75 questions × 3 modes × n=3 = 675 cells
against Hermes-3 8B at concurrency=4. No mode regressed past
the 5pp signal floor:

  quote                 53.8% STRICT  vs 54% baseline = -0pp (stable)
  claim_lattice_pointer 23.1% STRICT  vs 20% baseline = +3pp (within floor)
  claim_lattice (JSON)  46.7% STRICT  vs 42% baseline = +5pp (at floor — marginal positive)

JSON-mode +5pp is right at the noise threshold per
docs/bench-maxing.md — could be the 2026-05-10 substrate work
(92/92 warrant chains + 18 textbook ingests + cascade tuning +
Phase 3 wiring) translating to retrieval-quality lift, OR
sample variance. Follow-up bench in 1-2 days disambiguates.

Format-collapse 0/225 in every mode. Latency stable
(10.6-11.1s median). Lattice-mode directive coverage 100%.

Phase 3 per-claim warrant-chain tail still dormant on this
fixture (rescue-only by design; no warrant-shape question
retrieves a chain-backed chunk while failing lexical anchor —
parallel shift's same finding). Source-level warrants tail
fires on claim-pack-targeted retrievals as documented in
phase3-live-validation-2026-05-10.md.

Substrate + Phase 3 sprint shipped clean.
2026-05-10 13:42:12 -04:00
a4058a43bc
tests: rename v8 → substrate + close 9-item checklist gaps across 3 files
Three threads bundled, all surfaced by today's calculator-test-
patterns.md audit + fox's directive to remove v-prefix from test
filenames:

THREAD 1 — rename test_v8_fork_score.py → test_substrate_fork_score.py
=====================================================================

Single test file in the tree had a v-prefix in its filename:
``tests/test_v8_fork_score.py``. Renamed via ``git mv`` for
consistency with yesterday's substrate refactor (the package is
``arborist/substrate/fork_score.py``; the CLI subcommand is
``arborist substrate score``; the test file should match).

No internal code changes needed — the file's imports + assertions
were already updated to ``arborist.substrate.*`` paths in
yesterday's bae5caf commit. Pure rename.

THREAD 2 — close v1 substring discipline gap
=============================================

Audit of test_anchor_prg.py + test_phi_alignment_probe.py against
docs/calculator-test-patterns.md §2 (versioned-default discipline)
found one gap: both files asserted the version string's exact
value but neither asserted the ``"v1"`` substring discipline that
fox's test_returns_calculator_version_token established.

Added ``assert "v1" in PHI_PRG_VERSION`` to
test_module_exports_version_string in test_anchor_prg.py.

Added ``assert "v1" in PROBE_VERSION`` to
test_module_exports_thresholds_and_version in
test_phi_alignment_probe.py.

Both follow fox's pattern: when the algorithm changes (v2-blake3-
expansion, v2-arnoldi-iteration, etc.), the version string MUST
change too. The "v1" substring assertion catches a future
contributor who refactors without bumping the version constant.

THREAD 3 — close CLI subprocess gap on test_substrate_fork_score.py
====================================================================

The renamed file had four CLI tests but all in-process via
build_parser() + parse_args() + func(args). That catches argparse-
shape drift but NOT entry-point / module-loading / sys.argv drift.

Added test_cli_substrate_score_subprocess_invocation: real
``subprocess.run(["python", "-m", "arborist.cli", "substrate",
"score", "--parent", ..., "--child", ..., "--out", ...])`` against
synthetic bench results. Asserts exit 0 + the --out artifact is
written + JSON-parses with valid verdict.

Pattern matches fox's test_cli_baseline_runs_clean in
test_t3_bound_calculator.py + the 581ad90 KAT-fixture-gap closure.
Same hazard fox already hit three times during the substrate
rename refactor (85be5eb, 209d670, b320e27): import-only tests
silently miss CLI surface drift.

CHECKLIST AUDIT — POST-FIX
==========================

Three calculator-style test files now all 9-item complete:

                          | t3 | anchor_prg | phi_alignment | substrate_fork |
  KAT fixture             | ✓  |  ✓        |  ✓           | n/a (different)|
  VERSION + "v1"          | ✓  |  ✓ NOW    |  ✓ NOW       |  ✓             |
  Hand-formula            | ✓  |  ✓        |  ✓           |  ✓ (synthetic) |
  Monotonicity            | ✓  |  ✓        |  ✓           |  ✓             |
  Closure / sum-of-parts  | ✓  |  ✓        |  ✓           |  ✓             |
  Parametrized invalid    | ✓  |  ✓        |  ✓           |  ~              |
  CLI subprocess          | ✓  | n/a       | n/a          |  ✓ NOW         |
  Doc parity              | ✓  | KAT       | KAT          |  KAT            |
  Module-export shape     | ✓  |  ✓        |  ✓           |  ✓             |

All four files now consistently track the calculator-test-patterns
checklist. test_substrate_fork_score.py is structurally different
(verifier-adjacent: tests scoring + verdict-band logic, not
closed-form math) so some checklist items map differently — KAT
fixture replaced by synthetic-input verdict tests (closer to
verifier-style), parametrized-invalid is partial (per-verdict-
class assertions rather than per-bad-input cone). Acceptable.

Test counts:
- test_substrate_fork_score.py: 26 → 27 (+1 subprocess test)
- test_anchor_prg.py: 27 → 27 (assertion added inline)
- test_phi_alignment_probe.py: 23 → 23 (assertion added inline)
- t3 file untouched in this commit (581ad90 already at 53)

Full suite: 1985 → 1986 (+1 from this commit's only
new-test-function addition; the inline assertions don't count
as new tests).

Hygiene
=======
- make test → 1986 passed, 45 skipped.
- All four calculator-style test files structurally aligned.
- No v-prefixed test filenames remain in tests/ tree.
2026-05-10 13:35:52 -04:00
581ad908f0
tests/t3_bound_calculator: close the two checklist gaps from §3 audit
Audited fox's exemplar 51-test file against the 9-item checklist
in docs/calculator-test-patterns.md (codified earlier today in
0725eb4). Two gaps found, both additive:

GAP 1: no KAT fixture
=====================

Checklist item 1: "KAT fixture under bench/fixtures/<module>/
(≥ 5 cases)". Fox's tests cover the doc's worked-example numbers
inline (test_baseline_matches_section_11_doc) but no separate
fixture file existed for off-the-baseline regression coverage.

Generated bench/fixtures/t3-bound/known-answer-tests.jsonl with
8 KATs:

  - small-deployment-§7.1, medium-deployment-§7.2,
    hardened-deployment-§7.3 (the doc's three worked examples)
  - extreme-low-g (g=0.001, σ=0.5 — exercises low-SNR regime)
  - tight-window-W=100 (small-W ceiling-rounding edge case)
  - tightened-c-b1 (override-constants path)
  - all-constants-tight (all three c_b1/c_b2/c_b3 overridden)
  - b3-floor-regime (factor < 1, B3 floors to 0)

Each entry pins (calculator_version, inputs, expected_total,
expected_b1, expected_b2, expected_b3, expected_snr_grad).
Algorithm change MUST bump CALCULATOR_VERSION + emit new fixture
file under bench/fixtures/t3-bound/ — old runs replay against
old data per §1 discipline.

GAP 2: no B3 hand-computed formula test
=======================================

Checklist item 3: "Hand-computed formula tests — at least one
per independent contribution / output field". Fox had
test_b1_exact_formula + test_b2_exact_formula + test_snr_grad_formula
covering three of the five output fields. B3 had only
test_b3_floor_at_zero_when_factor_below_one (an edge case),
not a closed-form check on the general formula.

Added test_b3_exact_formula: hand-computes
``C_B3 · ⌈W/E⌉ · log₂(N_b · σ_grad / ‖∇L_max‖) / 2`` per #000036
§5 (Bottou-Bousquet refinement), asserts agreement with the
function's B3_contribution. Pairs cleanly with the B1/B2 hand-
formula tests fox had.

CHECKLIST AUDIT — POST-FIX
==========================

  1. KAT fixture           ✓ NOW (was ; 8 entries)
  2. VERSION + "v1"        ✓ test_returns_calculator_version_token
  3. Hand-formula          ✓ NOW B1/B2/B3/snr_grad all covered
                              (was ⚠️ partial; B3 had floor-only)
  4. Monotonicity          ✓ test_monotone_in_window_length /
                              gradient_fraction
  5. Closure               ✓ test_total_equals_sum_of_three_contributions
  6. Parametrized invalid  ✓ four @pytest.mark.parametrize blocks
  7. CLI subprocess        ✓ test_cli_baseline_runs_clean +
                              test_cli_invalid_input_exits_2
  8. Doc parity            ✓ test_baseline_matches_section_11_doc
                              (caught today's §11 calibration drift)
  9. Module-export shape   ✓ test_returns_calculator_version_token +
                              test_constants_recorded

All nine items now ✓. test_t3_bound_calculator.py is the
exemplar for calculator-style test discipline.

Test count: 51 → 53 (+2 from this commit). Full suite:
1915 → 1985 (+70 from fox's parallel work + this commit's +2;
partial cycle effects).

Hygiene
=======
- make test → 1985 passed, 45 skipped.
- KAT fixture is JSONL with header comment naming
  CALCULATOR_VERSION; future drift caught at the test level.
- Eat-my-own-dogfood: applied my docs/calculator-test-patterns.md
  checklist to fox's exemplar test file. The fact that gaps
  surfaced (even on fox's substantive 51-test surface) validates
  that the checklist has real reviewer value, not just guideline
  signaling.
2026-05-10 13:26:30 -04:00
d720b73d91
remove docs/dav1dprometheus-update-2026-05-09.md
Per fox 2026-05-10 — file not needed. Was a point-in-time update
note; superseded by the rolling research log in #000006 and the
ticket-level status pins (#000028 closed in TICKETS.md, witness-
sweep amend in #000006 etc.).

No incoming references in the repo (grep clean).

Note for the record: the immediately-prior commit (1421d96) made
an internal-consistency fix to this same file. That fix is moot
post-deletion but stays in the audit chain — describing the
witness/carrier vocabulary distinction was useful at the time it
shipped.
2026-05-10 13:24:51 -04:00
284603fe71
README: refresh stale test-count claim (641+ → 2000+)
Today's autonomous-quality run pushed test count from 1655
to 2093 (≈+438 across both shifts). README.md still cited the
older "641+" milestone from earlier in the project. Updated to
the current ~2000+ number with a parallel-execution latency
note.
2026-05-10 13:24:26 -04:00
1421d96659
dav1dprometheus 2026-05-09: line 284 internal-consistency fix
The doc's own meta-comment at line 160 explicitly distinguishes
witnesses (kernel/cache/LLM channels over the same canonical bytes)
from carriers (text/image/audio/world modalities). Line 284 still
used the conflated phrase 'multi-modality witness' that the meta-
comment was teaching against.

Update to 'multi-witness canonical-agreement' — consistent with
the doc's own clarification, with David's 2026-05-10 review of
#000037 (which renamed #000028's mechanism descriptor across the
controller spec for the same precision reason), and with the
2026-05-10 #000006 amend that uses the corrected vocabulary.

Closed-ticket references to #000028 by its actual title (Multi-
modality witness for canonical shapes) are intentionally not
touched — those are accurate citations of the ticket title, not
generic mechanism descriptors.

Doc-only update; no schema, no governance hash, no code change.
2026-05-10 13:24:12 -04:00
2c683de6d8
ticket #000006: 2026-05-10 amend — Phase 3 warrant-chain dormancy
Third qualitatively different experimental shape in the rolling
research log, parallel to the 2026-05-09 witness-sweep widening:

- random-word emergent (honesty under no ground truth)
- witness-sweep (capability under canonical ground truth)
- warrant-chain (rescue-mechanism activation under chain-backed
  ground truth)  ← new

Captures the structurally-grounded dormancy of #000031 Phase 3
verifier — 0/117 fires across an aggressive A/B with 12/13
chain-root retrieval, plus 5 paraphrase fixture iterations
none of which drive Phase 3 to fire empirically.

Root cause pinned at arborist/qa/warrant.py:507: warrant_check
vacuous-passes unless question shape is relation/date/entity-list/
count/why-cause. Definitional questions don't have warrant shape;
claim-pack chunks are terse axioms without prose context that
warrant-shape questions would retrieve. Phase 3 is structurally
rescue-only on the current corpus.

Mechanism correct + non-regressing + unit-tested. Recommendation:
track fire rate as a corpus-evolution signal, not a fixture-
engineering target. Audit-line tail will surface organic fires.

Adjacent same-day landings noted: #000034 Phase 1a (Hessian-
alignment probe) + #000035 Phase 1 (φ_PRG reference) — both
KAT-pinned cryptographic-primitive infrastructure ahead of v7
plastic-training deployment.

Doc-only update; no code change.
2026-05-10 13:22:30 -04:00
7ea0fdf2b1
ticket #000039 §13.5: amend test plan with CLI subprocess coverage
Phase 1 plan §13.5 named four test files (3 unit + 1 integration)
but did NOT name CLI subprocess tests for the three new CLI
surfaces §13.4 introduces:

  - arborist ingest --embed (flag on existing subcommand)
  - arborist query --retrieval={fts5|vec|hybrid} (new flag)
  - arborist vec rebuild (new subcommand)

Per docs/calculator-test-patterns.md §6 (codified earlier today
in commit 0725eb4 from the three-module pattern bench): import-only
tests miss argparse + main() drift. Yesterday's substrate refactor
caught this hazard three times — fork_score.py import (85be5eb),
Makefile bench-fork-score target (209d670), .gitlab-ci.yml job
+ script (b320e27). Each fix was 1-3 lines, but each had been
shipped to main + would have surfaced as a noisy CI failure on
next pipeline run.

§13.5 now adds three CLI subprocess test files:

  - tests/test_cli_vec_rebuild.py
  - tests/test_cli_ingest_embed_flag.py
  - tests/test_cli_query_retrieval_flag.py

Each gated via pytest.importorskip("sqlite_vec") so they skip
cleanly when [vec] extras absent. Pattern matches fox's
test_cli_baseline_runs_clean / test_cli_invalid_input_exits_2
in tests/test_t3_bound_calculator.py (the exemplar for
calculator-style CLI tests).

§13.7 size estimate revised: 4 test files → 7 test files (+3 CLI
subprocess), 250 → 400 test LOC. CLI subprocess tests are
~30-40 LOC each (boilerplate + tmp_path + subprocess.run +
JSON parse). Phase 1 total grows from ~550+250 → ~550+400 LOC.

Doc-only edit; doesn't unblock or block fox's §13.8 four
decisions — the test-plan addition is mechanical discipline,
not a scope change. Phase 1 still gates on the four §13.8
decisions before any code lands.

Cross-ref: docs/calculator-test-patterns.md §6 (CLI subprocess
pattern) + the three substrate-rename defect commits caught by
that pattern in retrospect (85be5eb / 209d670 / b320e27).
2026-05-10 13:19:53 -04:00
10b81e187d
tests/cli_smoke: 68 argparse-construction smoke tests for the full CLI surface
Catches the regression class where a PR breaks argparse setup
(duplicate flag, broken set_defaults reference, renamed leaf
verb) without breaking any existing test. ``--help`` exercises
the parser-construction path without invoking any handler.

Coverage:
  - top-level: arborist --help / --version / no-subcommand error
  - 30 top-level subcommand --help calls (parametrized)
  - 38 nested-subcommand --help calls across 9 verbs that have
    their own subcommand groups (alias / memory / capital /
    selfmodel / mesh / crawler / canon / substrate / snapshot)
  - completeness check: top-level --help mentions every verb in
    _TOP_LEVEL_SUBCOMMANDS (regression guard against silent
    removal)

All 68 pass. ~20s wall via subprocess (~150ms per --help call x 68
calls + Python startup overhead). Fixture is hand-curated so a
new subcommand requires fixture update — that's the discipline
which surfaces the regression as a test failure rather than as a
missed --help test.

Pattern after fox: contract phrases pinned as test invariants
(here, the subcommand verb names) so silent renames fire the
test loud + force the fixture update + force the docstring +
help-text update too.
2026-05-10 13:16:06 -04:00
0725eb418b
docs/calculator-test-patterns.md: codify the 2026-05-10 pattern bench
Captures the testing patterns surfaced from the three-module
pattern bench (anchor_prg / phi_alignment_probe /
t3_bound_calculator) as a docs/ architecture reference. Future
blackops shifts find it via grep instead of having to read commit
messages from de997f7 + a4b3056 + 35aeebb to reconstruct the
discipline.

Eight patterns codified:

  1. KAT (known-answer-test) regression — pin (input, expected)
     fixtures under bench/fixtures/<module>/
  2. Hand-computed formula assertion — compute the spec's math
     in the test file from first principles, assert agreement
  3. Monotonicity per input axis — scaling one knob while
     holding others fixed verifies the function responds in
     the expected direction
  4. Closure / sum-of-parts invariants — A + B + C ≡ total;
     no missing terms, no double-counting
  5. Parametrized invalid-input cones — collapse N
     test_rejects_X functions into one @parametrize per
     validation class
  6. CLI subprocess end-to-end — argparse + main() drift the
     import-only tests miss
  7. Doc parity — pin the spec's worked-example numbers
     against the function's actual output (catches doc drift,
     which surfaced today as fox's calibration-pass note on the
     T3 bound doc §11)
  8. Module-export shape — version constants, asdict round-trip,
     JSON-serializability, "v1" version-string discipline

Includes:

- "When to use" header that explicitly limits applicability to
  calculator-style code (math-heavy, closed-form output, JSON-
  serializing CLI)
- "When NOT to use" disclaimer that verifier / parser /
  state-machine tests have their own appropriate structures
  and shouldn't be retrofitted (saves future shifts the same
  realization I had today walking warrant_resolver tests)
- A 9-item checklist for new calculator-style modules to land
  with consistent test density
- Concrete code excerpts from the three exemplar test files

Architecture-reference convention followed (per docs/TICKETS.md
§ "Distinction from other docs"): docs/<filename>.md, no ticket
number, listed in the architecture-reference block. Joins
concept-relations-design.md, warrant-substrate-cookbook.md, and
the cti-architecture.md / mesh.md / etc. set.

docs/TICKETS.md amended with the new entry under "Distinction
from other docs".
2026-05-10 13:13:19 -04:00
28b57da381
soft-hash analysis §9.1: pin #000034 Phase 1a landing (mirror of §9.2)
#000034 Phase 1a landed 2026-05-10 (synthetic-ablation
infrastructure for the Hessian-alignment probe under φ_linear):
bench/scripts/phi_alignment_probe.py + 14 tests + KAT fixture
at bench/fixtures/phi-alignment/synthetic-checkpoints.jsonl.

Same closure-loop grooming pattern as 0b038f1 (§9.2 update for
#000035 Phase 1): the analysis doc already named the test path
in §9.1 but did not yet point at the artifacts that just shipped.
This commit closes the loop for §9.1 + updates §11 status block.

Phase 1b (the actual v7-checkpoint measurement that resolves the
open question and feeds C_B1 tightening per #000043) still parks
on v7 deployment ramp-up — same exogenous gate as #000035 Phase 2.

Doc-only update; no schema, no governance hash, no code change.
2026-05-10 13:11:39 -04:00
6aca7d91d7
docs/cookbook: appendix — test-coverage cross-reference (2026-05-10)
Adds a per-discipline test-file index to the cookbook so audit
reviewers can click through from a substrate discipline to the
unit-test pinning that prevents silent regression. Eight
sub-sections matching the live discipline groups:

  - citation/term alias mechanism (#000041 + #000042) —
    test_aliases.py 28 tests
  - warrant-resolver chain (#000031 P1+2+3) —
    test_warrant_resolver.py + test_warrant_chain.py
  - textbook ingest license-discipline gate —
    test_textbooks_manifest.py 43 tests
  - cascade tuning (#000040 + parenthetical/OR-fallback) —
    _phrase_from_parenthetical regression guard
  - substrate-paper-spec'd primitives (#000012 + #000018 +
    #000034 + #000036) — 6 test files
  - Q&A / verifier scaffolding — test_qa_progress.py +
    test_qa_prompts.py
  - concept-relations write-side — test_concepts_extract.py

Plus a unit-test-density-vs-code table: small contract-defining
modules (weights, prompts, warrant_chain) sit at 1.4-3.6× test
LOC because they're foundation; larger modules (warrant_resolver,
aliases) settle at 0.5-1.0× because they're more code-with-tests-
per-feature than contract-with-tests-per-rule.

Code-review heuristic surfaced for future shifts: new
substrate-paper-spec'd primitive without ≥1× test/code ratio
is suspect on landing.
2026-05-10 13:11:08 -04:00
35aeebbb24
tests/prometheus_sigma: refresh stale v9 import path → substrate
CLI version-bake sweep surfaced one real defect: the Phase 1 test
scaffolding I shipped in c422216 imported ``from arborist.v9
import prometheus``, baking in the version-prefixed namespace path
that yesterday's substrate refactor (654d923) abolished.

The skip mechanism (try/except ImportError → CONTROLLER_AVAILABLE
= False) was masking the issue: when fox lands Phase 1 of #000037
at ``arborist/substrate/prometheus.py`` (per the topic-named
convention), my tests would CONTINUE to skip with
"controller module arborist/v9/prometheus.py absent" because the
import target itself is wrong. The skip-stub becomes permanent
dormancy instead of activating when the module ships.

Two changes:

- Import line: ``from arborist.v9 import prometheus`` →
  ``from arborist.substrate import prometheus``.
- Skip-reason text + module-docstring: ``arborist/v9/prometheus.py``
  → ``arborist/substrate/prometheus.py``, with a parenthetical
  noting the post-2026-05-10 topic-named convention and that
  §13's original sketch predated the v-dir retirement.

The fix is a real one — when fox's Phase 1 of #000037 lands, my
17 skip-stubs now activate against the correct module path.
Without this fix, they'd silently stay dormant.

Sweep summary
=============

Walked every CLI subcommand --help (arborist top-level + nested
substrate / memory / capital / selfmodel / warrant-resolve / sweep
/ alias / mesh / crawl / providence) plus full-tree grep for
``arborist v[789]`` / ``arborist\\.v[789]`` / ``arborist/v[789]``.

Remaining v-prefix mentions across the tree (all intentional):

- arborist/cli.py:5166-5169 — historical-note comment for the
  v8→substrate rename
- arborist/substrate/__init__.py:8 — same convention-explanation note
- arborist/substrate/anchor_prg.py:59 — bytestring inside SHA-256
  derivation of placeholder seed; can't change without breaking KAT
- bench/fixtures/phi-prg/known-answer-tests.jsonl:1 — fixture header
  naming the v7 paper section §9.10 (paper version, correct)
- docs/v8-fork-score.md:4 — historical-note ("module moved from")
- docs/tickets/ticket-000019, ticket-000013 — "arborist v9.8" schema
  references (schema version, correct)
- docs/_source/merkle-agi-v7w-spatial-temporal.rst — v7 paper +
  v9.8 schema references (both correct)

Tests: 1915 passing, 45 skipped (was 1872; +43 from fox's parallel
test additions during this commit's prep + the 17 prometheus
skips activating against the correct path stub).

CLI version-bake sweep complete. The substrate refactor is now
surface-clean end-to-end.
2026-05-10 13:02:58 -04:00
4fb467bbda
tests/textbooks_manifest: 43 tests for license-discipline gate (was zero coverage)
bench/scripts/textbooks_manifest.py drives every per-textbook
Make target (`make textbook ID=…`, `make crawl-textbooks`,
`make textbooks-tex`). 236 LOC, no direct tests despite being
the license-discipline chokepoint — `_validate()` is the
fail-closed gate that refuses to emit URLs for licenses outside
arborist's AGPLv3-compatible allow-list.

Coverage:

  iter_entries
  - skips _meta block (first line is metadata not an entry)
  - skips blank lines
  - empty stream → empty iterator

  _validate (license-discipline gate)
  - parametrized over every license in _ALLOWED_LICENSES (12
    tokens — PD / CC0 / CC-BY-* / CC-BY-SA-* / GFDL / AGPL /
    Apache / MIT) — all pass with emit URLs
  - missing license / license_url field → ValueError
  - empty license value → ValueError
  - disallowed license + emit URLs → "redistribution allow-list"
    error
  - placeholder rows (no urls + no crawl_url) bypass allow-list
    (kept for citation traceability per docstring)
  - crawl_url triggers allow-list check (not just urls)
  - allow-list explicitly excludes PROPRIETARY / NC / ND tokens

  cmd_urls / cmd_summary / cmd_crawl_targets / cmd_tex_targets /
  cmd_ids / cmd_lookup
  - URL dedup across entries
  - placeholders skipped at emit time
  - tab-separated output formats (crawl_targets 4-field,
    tex_targets 2-field, lookup 7-field-with-author)
  - default crawl_depth=2 / crawl_max=80 when entry omits
  - cmd_ids excludes license-fail + placeholder rows
  - cmd_lookup return codes: 0 (ok) / 2 (no id arg) / 3
    (license-fail placeholder) / 4 (id not found)
  - blank-author entry → 7th tsv field empty (not absent —
    Makefile `cut -f7` semantics)

  main dispatch
  - unknown subcommand → 2 with usage banner
  - empty argv → 2
  - subcommand routing to cmd_urls

  Live manifest invariant
  - bench/fixtures/textbooks/manifest-v1.jsonl validates clean —
    fires if a future PR adds a typo'd license token

Full suite: 1915 passed, 45 skipped.
2026-05-10 13:02:17 -04:00
a4b30562f8
tests/phi_alignment_probe: backfill fox's testing patterns
Same pattern-application as de997f7 did for test_anchor_prg.py.
The phi_alignment_probe tests landed in 1dfb8b9 with KAT
regression + verdict-bucket coverage + Lanczos convergence
check, but lacked the four patterns fox demonstrated in
test_t3_bound_calculator.py (51 cases for the T3 calculator):
monotonicity, hand-computed formula, closure invariants, and
parametrized invalid-input cones.

New tests added:

1. **test_monotone_alignment_strength_in_concentration** —
   tighter W concentration on low-λ subspace must monotonically
   increase the ratio. Tested across 32-row → 16-row → 8-row
   concentrations, normalized to constant ‖W‖_F. Catches sign
   errors + drops in the alignment-score formula.

2. **test_monotone_alignment_in_dim_h** — verdict invariant
   under W column-count scaling. Sanity check that A(W, H)'s
   ‖W‖_F² normalization decouples it from sample count.

3. **test_uniform_baseline_matches_analytical_formula** —
   hand-computes the isotropic baseline
   ``E[A_bot(W_uniform, H)] = (1/dim_d) Σ 1/(λ_j+ε)`` from
   #000034 §2.1 derivation; asserts exact agreement with the
   function's ``a_uniform`` field. Catches algorithm drift the
   KAT regression would miss (KAT could regenerate against a
   buggy implementation).

4. **test_full_spectrum_a_top_plus_a_bot_covers_full_isotropic_baseline**
   — closure invariant: when k_top + k_bot = dim_d, the function's
   a_top + a_bot must equal full-spectrum A computed via dense
   numpy.linalg.eigh decomposition. Catches missing terms /
   double-counting.

5. **test_eigenvalue_ordering_top_dominates_bot** — closure
   invariant: top-k eigenvalues must all be ≥ bot-k eigenvalues.
   Catches a bug where eigsh's 'LA'/'SA' modes returned
   overlapping ranges on near-degenerate spectra.

6. **test_rejects_wrong_dim_w** — parametrized over (1-D, 3-D,
   0-D scalar) shape errors. Same pattern as test_anchor_prg's
   parametrized rejects.

7. **test_rejects_non_positive_epsilon** — parametrized over
   (0, -1e-6, -1.0). Collapsed N separate test_rejects_*
   functions into a single parametrized cone.

Test count: was 14 in test_phi_alignment_probe.py; now 23
(+9 from the new patterns + parametrize expansion).
Full suite: 1727 → 1872 (note: large jump partly from fox's
parallel test additions today, +136 since my last test count
checkpoint; my contribution here is +9 directly attributable
to this commit).

Three calculator/probe-style modules now have consistent
test coverage:

  bench/scripts/t3_bound_calculator.py   — 51 tests (fox)
  bench/scripts/phi_alignment_probe.py   — 23 tests (this commit)
  arborist/substrate/anchor_prg.py        — 27 tests (de997f7)

Same pattern bench applied across all three. Future
calculator-style code should pin: monotonicity in each input
axis + hand-computed formula assertions + closure / sum-of-parts
invariants + parametrized invalid-input cones.

Hygiene
=======
- make test → 1872 passed, 45 skipped
- make chain-check-shards → 0 across all 7 shards
- All new tests use synthetic inputs (no LLM, no shard
  dependency); run in ~35s suite-wide
2026-05-10 12:51:52 -04:00
c3a3210424
tests/qa/prompts: 20 tests pinning load-bearing system prompts (was zero coverage)
arborist/qa/prompts.py — 4 string constants that ARE the contract
with the LLM. Silent edits drop bench STRICT-rate by tens of
points; per CLAUDE.md "bench-maxing" discipline, prompt
regressions need a per-PR guard, not just bench surfacing after
the fact.

This test file pins the load-bearing phrases as regression
guards for both claim_lattice modes:

  CLAIM_LATTICE_SYSTEM_PROMPT (pointer mode)
  - non-empty + substantial
  - both worked examples present (Apple founders + Mars descriptive)
  - two-pointer cap rule (folds into claim_lattice_max_pointers_per_claim)
  - pointer ID shape teaching (E1, E2, E3, [E#] / [E#,E#])
  - one-claim-per-line rule (parser splits on newlines)
  - synthetic-elision-by-construction-impossible: NO instruction
    to wrap claims in double quotes (that's legacy quote-mode)

  CLAIM_LATTICE_GROUNDING_REMINDER (pointer mode user-turn)
  - "REMINDER" prefix; "pointer-line" format restated
  - two-pointer cap restated

  CLAIM_LATTICE_JSON_SYSTEM_PROMPT (JSON mode)
  - schema shape: claims/text/evidence_ids
  - first-char-`{` / last-char-`}` discipline
  - two-evidence-id cap

  CLAIM_LATTICE_JSON_GROUNDING_REMINDER (JSON mode user-turn)
  - schema restated; cap restated

  Cross-prompt parity
  - both modes reference the two-pointer cap
  - both reminders end with "next message" (handoff to question)
  - all 4 constants importable + non-empty strings

Full suite: 1872 passed, 45 skipped.
2026-05-10 12:50:20 -04:00
b64395de0c
tests/concepts/extract: 20 tests for synonym/idf/fts5 extractors (was zero coverage)
arborist/concepts/extract.py — concept-relation write-side
(extractors that derive concept_relations rows from the corpus
state). 288 LOC, no direct tests despite test_concepts.py
exercising the read-side end-to-end.

Coverage:

  _title_tokens (pure private helper)
  - empty string → empty set
  - stopword strip (the/a/an/of/and/...)
  - underscore→space (Wikipedia title style: 'New_York_City')
  - length≥4 floor (3-letter words = noisy anchors)
  - lowercase output regardless of input case
  - hyphenated tokens kept as one (state-of-the-art)
  - dedupe via set return type
  - skip pure-digit tokens (regex requires [a-z] start)

  EXTRACTORS registry contract
  - 3 documented keys present (link_reciprocity / token_idf /
    documents_fts)
  - all values callable
  - dispatch table maps to actual implementations (identity check)

  backfill_documents_fts on synthetic mini-shard
  - indexes titles → returns rows_indexed count
  - idempotent (DELETE+INSERT pattern)
  - skips NULL titles (FTS5 row absent)
  - default + explicit derived_from kwarg paths

  link_reciprocity_synonym
  - empty edges → zero pairs
  - one-way edge → no reciprocal pair
  - reciprocal pair with no token overlap → cross-product synonyms
  - idempotency (concept_relations PK uniqueness)
  - self-overlap token excluded from cross product
2026-05-10 12:47:58 -04:00
192793d187
tests/qa/progress: 31 tests for Progress emitter (was zero coverage)
arborist/qa/progress.py — stage-level state-machine emitter for
arborist query. 85 LOC, no direct tests. Used throughout the QA
runner + ingest pipelines for stderr-only progress lines (stdout
stays clean for JSON / unfirehose journal output).

Coverage:
  - Progress.emit formatting: bare-prefix (no kvs), key=value tail
    (single + multi), elapsed timestamp format, stream redirect
  - enabled=False is true no-op (no string formatting cost)
  - default stream is sys.stderr; default t_start is monotonic-now
  - disabled() returns singleton (suitable as default kwarg)
  - from_env precedence: cli_override > ARBORIST_PROGRESS env >
    TTY auto-detect
  - 7 truthy env spellings (1/true/on/yes + case variants) enable
  - 7 falsy env spellings (0/false/off/no + case variants) disable
  - unknown / empty / whitespace env values fall through to TTY
  - sys.stderr lacking .isatty falls back to disabled (fail-closed)
  - from_env returns fresh instance per call (no shared state)
2026-05-10 12:45:32 -04:00
b17900cb33
tests/pi_star: 21 tests for protocol + registry (foundation, was untested)
arborist/pi_star/protocol.py + arborist/pi_star/registry.py are
the foundation every concrete π* kernel rides on. Both shipped
in #000015 Phase 1 with zero direct tests; concrete kernels
(arithmetic@v1, logic-kernel@v1, algebra-symbolic@v1, ...) have
their own test files but the protocol contract + registry
mutation discipline weren't pinned.

Coverage:

  protocol.py
  - PiStar @runtime_checkable: instances satisfying the duck-type
    pass isinstance check; missing-method instances are rejected
  - registry_key returns "name@version" exactly; distinct versions
    yield distinct keys
  - equivalence_class_id is sha256 over canonicalize() output;
    invariant under pre-canonical form (two raws that canonicalize
    to the same bytes get the same eclass id); distinguishes
    different canonicals
  - assert_round_trip passes on idempotent π*; raises
    AssertionError naming the kernel on non-idempotent;
    propagates PiStarError when canonicalize raises on the test
    input itself

  registry.py
  - register inserts; get retrieves
  - register IS idempotent for the same instance at the same key
    (no error)
  - register REJECTS a different instance at the same key
    (cache_key invariant: name@version content-pinned)
  - same name with different versions coexist
  - get raises KeyError on unknown key
  - list_keys returns sorted keys (deterministic for cache_key
    derivation downstream)
  - domains() groups by domain; per-domain key lists are sorted;
    empty registry → empty dict

isolated_registry fixture monkeypatches REGISTRY to {} for
mutation tests so the global registry stays untouched (matches
the module docstring's no-public-unregister discipline).

Substrate-paper-spec'd primitives (arborist/substrate/* and
arborist/pi_star/protocol.py + registry.py) all directly tested
now.
2026-05-10 12:44:13 -04:00
3ef8975623
tests/weights: 16 tests for WeightSet defaults + from_dict adapter
arborist/substrate/weights.py was zero-coverage. 73 LOC of
dataclass + adapter. Tests pin:

  - documented defaults from the module docstring (each weight
    has a comment block explaining its design intent; tests
    pin the values so a PR that flips alpha=1.0 → 0.5 fires the
    test and forces an explicit docstring update)
  - documented invariants: alpha=beta=gamma (3 batteries equal),
    eta > alpha (regression heavier than improvement),
    reserved-zero defaults (zeta/iota/kappa)
  - as_dict() returns all 11 fields; lambda_ key (not "lambda" —
    keyword)
  - from_dict() greek-letter keys, "lambda" → "lambda_" translation
    (JSON/YAML friendly), missing-keys-default fall-through,
    extra-keys silent drop, str → float coercion, int → float
    coercion
  - frozen-dataclass invariant (mutation raises FrozenInstanceError)
  - dataclass equality

Full suite: 1881 passed, 54 skipped. tests/ count growing
roughly 1655 → 1881 (+226) across today's autonomous quality
session.
2026-05-10 12:41:49 -04:00
3d0f02e1ac
tests/fork_score: 18 tests for v8 ForkScore (#000012 Phase 1a — was zero coverage)
arborist/substrate/fork_score.py landed in #000012 Phase 1a but
shipped with no test file. 298 LOC of pure-function scoring +
verdict logic, exposed via the `arborist v8 score` CLI (now
substrate-rooted per ticket #000035 dir-rename).

Coverage:
  - bench_result_to_metrics adapter (BatteryResult JSON → nested
    {battery: {sub_battery: metrics}})
  - fork_score happy path: pure improvement → ACCEPT (score ≥
    SIGNAL_FLOOR=0.05)
  - marginal band: small improvement → MARGINAL (score in
    [0, SIGNAL_FLOOR))
  - zero parent + zero child → score 0 → MARGINAL
  - hard-reject paths: per-sub-battery HARD_REGRESSION_FLOOR
    (≥5pp drop on any 5S/5T/5F sub triggers REJECT regardless of
    overall positive score) + adaptation_efficiency_neg_infinite_count
    > 0 → NEG_INF_REGRESSION → REJECT
  - negative score → REJECT (separate path from hard-reject)
  - non-bench inputs: capital_delta penalty, audit_completeness
    bonus, security_risk subtracts WHEN iota>0 (default iota=0
    documented)
  - WeightSet customization flows through to output dict
  - ScoredFork.to_dict() JSON-serializable
  - score ≡ Σ breakdown.values() closure (no hidden term)
  - SIGNAL_FLOOR honored exactly (≥, not >) — score == 0.05 → ACCEPT

Fixed-point design discipline: tests use the constants from
arborist.substrate.fork_score directly (SIGNAL_FLOOR,
HARD_REGRESSION_FLOOR) so a bench-maxing PR that flips the floor
forces a tests-fail signal.

Default-iota=0 documented explicitly so future readers see "no,
you didn't break security_risk; it's deliberately opt-in."
2026-05-10 12:38:39 -04:00
de997f7be3
docs/T3 bound + tests/anchor_prg: apply fox's testing patterns
Two related cleanups in one commit, both surfaced by reading fox's
test_t3_bound_calculator.py (51 tests for my T3 calculator):

1. Refresh stale §7 numbers in the T3 bound doc
=================================================

fox's test_baseline_matches_section_11_doc docstring (lines
56-61) flagged that my §7.1 worked example said
622.7 / 290.0 / 32.7 bits but the calculator's actual
closed-form output is 625.87 / 292.48 / 33.39. Same drift in
§7.2 (3358 → 3387.72) and §7.3 (247 → 247.14).

The numbers were rounded estimates from when I drafted the doc
before the calculator existed. Refreshed all three §7 numeric
examples to match the calculator's actual output (verified live
via t3_bound_bits()). §3 inline approximation likewise updated
(290 → 292.48). Added a short note pointing readers at the
calculator + tests as the source of truth.

2. Backfill anchor_prg tests with fox's patterns
=================================================

fox's test_t3_bound_calculator.py demonstrated four patterns I'd
missed in my #000035 phi_prg tests:

- **Output prefix invariant** (closure check): phi_prg(h, n+k)[:n]
  ≡ phi_prg(h, n). Streaming-counter invariant — would catch a
  bug where a per-call seed mutation broke determinism across
  dim_h values.
- **Output length monotonicity**: len(phi_prg(h, n)) == n exactly.
  Parametrized over n ∈ {1, 2, 4, 7, 16, 17, 64, 1024}. Catches
  off-by-one in `_expand` truncation.
- **Hand-computed first block**: assert that the first 64 bytes
  of output equal a direct ``hmac.new(seed, h + b'\\x00\\x00
  \\x00\\x00', sha512).digest()``. Pattern from fox's
  test_b1_exact_formula — don't rely on KAT regression alone;
  compute the first-principles math in the test file. Catches
  algorithm drift the KAT (regenerated against a buggy version)
  would miss.
- **Seed-bleed check**: changing the seed must change EVERY output
  position. Probability of false-positive ≈ 64 · 2^-32 ≈ 2^-26;
  none expected in practice.
- **Parametrized invalid-input tests**: collapsed N separate
  ``test_rejects_*`` functions into ``@pytest.mark.parametrize``
  cones (4 wrong-size-hash cases + 3 non-positive-dim_h cases).
  Same coverage, fewer test functions.

Test count: was 20 in test_anchor_prg.py; now 27 (+7 from
parametrize expansion + new patterns). Full suite: 1720 → 1727.

Hygiene
=======
- make test → 1727 passed, 45 skipped.
- make chain-check-shards → 0 across all 7 shards.
- All new tests use ``pytest.importorskip`` already at module top
  (anchor_prg has no extras gate; tests run unconditionally).

Lessons captured
================
The patterns to remember for future calculator/probe-style code:

  1. KAT regression alone isn't enough. Add hand-computed
     formula tests so the math itself is asserted in the test
     file, not just "consistent with a recorded snapshot".
  2. Test monotonicity / closure invariants. They catch
     algorithm drift, sign errors, missing terms.
  3. Parametrize invalid-input tests. One function, N cases.
  4. Test the doc's numbers against the function. Catches
     calibration drift in the doc itself (this commit's
     finding about §7).
  5. CLI subprocess tests for end-to-end. Argparse + main()
     drift the import-only tests miss.
2026-05-10 12:36:13 -04:00
1104cf97ca
tests/aliases: gap-fill list_term_aliases + tokenizer helpers (10 new tests)
The aliases.py public surface had 18 tests covering happy-paths,
audit discipline, domain isolation, lowercase normalization, and
expand-query semantics. Three direct gaps:

  - list_term_aliases (no test at all): filter-by-domain, filter-by-
    term-substring, unreachable-db fail-closed, missing-table fail-
    closed
  - _tokenize_fts_query (only via expand-query smoke): preserve
    quoted phrases, parentheses-as-tokens (OR-expansion contract),
    unterminated-quote fallback
  - _quote_for_fts + _match_quoting (no direct test): pass-through
    quoted, defensive quote-multi-word, quoted-reference symmetry

10 new tests; aliases.py test count 18 → 28. Same fixture pattern
as the existing tests (sqlite tmp DB with SCHEMA_SQL applied).
2026-05-10 12:35:33 -04:00
0b038f1e36
soft-hash analysis §9.2: pin Phase 1 reference impl landing under #000035
#000035 Phase 1 (φ_PRG reference implementation) landed 2026-05-10:
HMAC-SHA-512 counter-mode KDF at arborist/substrate/anchor_prg.py,
20 tests, 10 KAT vectors, PHI_PRG_VERSION export.

§9.2 of the soft-hash analysis already recorded the design decision
("use HMAC-SHA-512(seed, digest ‖ counter)") but did not yet point
at the landed reference. This commit closes that gap by linking
§9.2 to the impl/tests/KAT artifacts and updating §11 status block
to reflect the new state — decision pinned + Phase 1 landed,
awaiting v7 plastic-training spec for the §9.10 amendment landing
(Phase 2, exogenous gate).

Doc-only update; no schema, no governance hash, no code change.
2026-05-10 12:28:22 -04:00
018a2a163b
docs: refresh stale alias counts (residual 40/54 → 74)
Parallel-shift commit 6f1dbed already refreshed primary surfaces
but missed three sites:

  docs/warrant-substrate-cookbook.md            54 → 74
  docs/tickets/ticket-000031-...md              40 → 74 (Phase 2.5 narrative)
  bench/results/full-warrant-resolution-...md   40 → 74 (×2 sites)

Live count from ~/.arborist/shards/000.db is 74 citation_aliases
+ 13 term_aliases. All four edits add the "grew 40 → 54 → 74
across the day" trail so future readers see the trajectory rather
than a stale point-in-time number.
2026-05-10 12:27:23 -04:00
2d0becf62d
ticket #000043: open empirical-tightening sub-ticket for T3 bound constants
#000036 §10 enumerated three open questions for tightening C_B1 /
C_B2 / C_B3 below their conservative-by-construction
data-processing-inequality ceilings of 1.0. #000036 §7 Phase 2
explicitly parks them as a single deferred work item but didn't
have its own ticket. This commit captures Phase 2 as #000043 so
the work doesn't get lost across three unrelated tickets and
the gating dependencies are visible in the ticket index.

§2 of the new ticket walks the three tightening paths:

- §2.1 C_B1 (gradient-bias) — feeds from #000034 Phase 1b
  (real v7 checkpoint + Hessian-alignment probe). Verdict
  → C_B1 estimate via alignment-score distribution.
- §2.2 C_B2 (LR-trajectory diversity) — per-deployment
  1-Wasserstein clustering across LR-grid mini-replicas.
  Cluster count → effective channel symbols.
- §2.3 C_B3 (SGD shuffle regime) — cheapest path; deployment
  configuration audit (DataLoader settings). Random-shuffle
  → C_B3 ≈ 1/√N_b; cyclic → ~1; adversarial → 1.

§3 ships the override surface already landed in
t3_bound_calculator.py (--c-b1 / --c-b2 / --c-b3 flags) — Phase
2 doesn't change the calculator's interface, only the numeric
values plugged in. New §3.2 sketches a per-deployment YAML
config-file shape; §3.3 routes measurements back into
soft-hash-channel-t3-bound.md §7.4 + §10 closure.

§7 status: parks until v7 plastic-training has at least one
active deployment AND either #000034 Phase 1b lands (unlocking
§2.1) OR a cheap-path operator audit lands (unlocking §2.3).
Partial closure (any one of §2.1/§2.2/§2.3 individually) is
acceptable.

TICKETS.md index row added; Next ID bumped 000043 → 000044.

Status note (separate finding from this commit's scope): fox
landed a comprehensive test_t3_bound_calculator.py
(51 new tests; full suite now 1720 passing vs my 1669 from
1dfb8b9). Tests validate the T3 calculator's mathematical
identities (B1/B2/B3 isolation, monotonicity), input-validation
surface, and operator-guidance text mode transitions. fox's
tests still untracked at this commit — this commit only stages
the ticket draft.

Doc-only commit; no code touched.
2026-05-10 11:55:36 -04:00
7cac942ea8
ticket #000036: 51 unit tests for t3_bound_calculator + doc §11 calibration
Adds tests/test_t3_bound_calculator.py covering:

  - baseline (§11 worked example) bit-for-bit closed-form output
  - B1/B2/B3 isolation + monotonicity in each input
  - SNR_grad = g·‖∇L_max‖/σ_grad formula
  - B3 floor when N_b·σ_grad/‖∇L_max‖ ≤ 1 (adversary can't do
    worse than random shuffle)
  - constant-scaling (C_B1/B2/B3 in [0,1] fold linearly into B_i)
  - input-validation hard checks (gradient_fraction in (0,1],
    positive floats > 0, positive ints, constants in [0,1])
  - recommendation text mode transitions (≤0 / <256 / ≥256 bit)
  - CLI subprocess invocation (argparse + JSON output, error path)
  - exact closed-form B1/B2 formulas across multiple configs
  - sum-of-three closure: I_window ≡ B1 + B2 + B3 (no missing
    term, no double-counting)

51 new tests; pure stdlib + subprocess invocation only. Full
suite now 1720 passed / 45 skipped.

Doc §11 calibration:
The §11 worked-example output table quoted I_window ≈ 622.7,
B1 ≈ 290.0, B3 ≈ 32.7. The closed-form actuals are 625.8716 /
292.4813 / 33.3904 — a ~3-bit total drift from rounding in the
first-cut spec. Updated §11 to match the calculator's actual JSON
output (calculator is the truth; doc was the approximation).
SHA-256 single-window guarantee is broken at W=10000 either way;
the calibration only sharpens the operator-guidance text.
2026-05-10 11:55:11 -04:00
6f1dbed82e
docs: refresh stale citation-alias counts (40 → 54 → 74) across 4 surfaces
Stale-marker check on #000038 surfaced the same drift pattern as
yesterday's earlier sweeps: documentation got snapshotted at
multiple points during the 2026-05-10 alias-substitution sprint
and four surfaces ended up disagreeing about the live row count.

Live count via ``arborist --shards-dir SHARDS_DIR alias citation
list | jq length``: **74** rows.

Stale snapshots refreshed:

- ``docs/tickets/ticket-000041-citation-aliases-table.md`` line 3
  (status header): "40 rows live by 2026-05-10" → "74 rows live
  as of 2026-05-10" with the 40 → 54 → 74 progression noted.
- ``docs/tickets/ticket-000041-citation-aliases-table.md`` line 205
  (§7 close-out): "54 rows live" → "74 rows live" + progression.
- ``docs/tickets/ticket-000038-phase-4-content-acquisition.md``
  line 3 (status header): "(54 rows)" → "(74 rows live as of
  2026-05-10; count grew 40 → 54 → 74 across the day)".
- ``docs/tickets/ticket-000038-phase-4-content-acquisition.md``
  §7 line: "54 rows live (decision_by=...)" → "74 rows live as
  of 2026-05-10".
- ``docs/tickets/ticket-000038-phase-4-content-acquisition.md``
  references line 274: "(40 → 54 rows live)" → "(40 → 54 → 74
  rows live across 2026-05-10)".
- ``docs/TICKETS.md`` line 70 (#000041 row): "54 rows live" →
  "74 rows live as of 2026-05-10 (count grew 40 → 54 → 74; ...)".
- ``docs/TICKETS.md`` line 73 (#000038 row): "(54 rows in #000041
  + 13 rows in #000042)" → "(74 rows in #000041 + 13 rows in
  #000042)".
- ``CLAUDE.md`` line 145: "40 fox-decided citation-aliases" →
  "74 fox-decided citation-aliases" + a note about the live-count
  command for future readers ("alias counts grow as fox adds
  substitutions — ``arborist alias citation list | jq length``
  for live count").

The refreshed numbers will themselves go stale next time fox
adds rows. Each surface now also notes the live-count
mechanism so future readers can check current state without
having to refresh the doc — same pattern as today's earlier
"track Phase 3 fire rate via the audit-line tail" closure
note. The CLAUDE.md note specifically tells future readers
where to look up the live count.

Term-aliases count (13 rows in #000042) was verified live and
matches all surfaces — no refresh needed there.

#000038 phases otherwise clean: §7 close-out + §8 residue
already accurately reflect current state (92/92 records resolve;
4 residue items genuinely-open). No phase status drift to fix.

Hygiene: docs-only commit, no code touched. No test impact.
2026-05-10 10:41:07 -04:00
96e64b88e6
ticket #000039: §13 Phase 1 implementation plan (proposal)
Phase 0 spec (§1-§12) was comprehensive but left four explicit
deliverables open: embedder choice, default quantization, smoke-
test protocol, bench protocol. §13 fills those four with concrete
recommendations + a code structure / test plan / size estimate
that fox can sign off on before Phase 1 code lands.

Recommendations:
  - Embedder path 1 (local sentence-transformer bundled as
    optional dep); model BAAI/bge-small-en-v1.5 (MIT, 33 MB,
    384-dim, unit-normalized, top of MTEB-en/retrieval among
    sub-100MB models)
  - Default quantization int8 × 384 + flat (6% storage tax,
    within the 15% budget per §3.1; binary × 768 reachable via
    --vec-quantization=binary)
  - Pre-Phase-1 smoke (§13.2): 1k chunks under WAL +
    synchronous=NORMAL, kill -9 mid-insert, recovery check;
    gate on insert ≥100 chunk/s, p95 query ≤50 ms, zero data
    loss
  - Bench protocol (§13.3): 3-condition (FTS5-only / vec-only /
    hybrid RRF k=60) on existing fixtures (smoke,
    progressive-and, bench-emergent, qa-modes); Phase 1 success
    = ±5pp STRICT-rate parity AND ≥5pp lift on at least one
    semantic-allusion fixture

Code structure (§13.4): 2 new files (embed.py + search/vec.py)
~200 LOC, 4 patches (store.py + query.py + cli.py + Makefile)
~100 LOC, 4 test files ~250 LOC, pyproject.toml [vec] extras
stanza. Single substantial commit when all gates pass.

§13.8 lists the four go/no-go decisions fox needs to make to
unblock Phase 1: embedder path, model name, default quantization,
and approval of the sentence-transformers PyPI dep under [vec]
extras (not pulled by default; only on pip install '.[vec]').
Fallback paths documented for each rejection.

Phase 0 doc remains awaiting go/no-go; §13 doesn't change that
gate, just provides the substance for fox's decision.
2026-05-10 10:40:07 -04:00
3b37c93810
ticket #000036 Phase 1: T3 per-window covert-channel bound + calculator
Lands the formal derivation deliverable proposed in #000036 §3.1.
Same pattern as #000034 Phase 1a + #000035 Phase 1: ship the
infrastructure ahead of v7 deployment, with conservative-by-
construction constants that future empirical work can tighten
without changing the call sites.

docs/soft-hash-channel-t3-bound.md (new, 12 sections, ~250 lines)
=================================================================

§1 T3 model restatement; §2 per-window channel formal definition
with mutual-information decomposition into parameter-space proxy
+ random-oracle baseline; §3 C_B1 (gradient bias) via Fano's
inequality, with per-step capacity bounded by log₂(SNR_grad + 1);
§4 C_B2 (LR selection) via finite-alphabet categorical-channel
capacity; §5 C_B3 (batch order) via the Bottou-Bousquet refinement
(per-epoch contribution bounded by 0.5·log₂(N_b·σ_grad/‖∇L_max‖),
much tighter than the naive log₂(N_b!) bound that the ticket §3.2
explicitly flagged as needing refinement); §6 closed-form combined
bound; §7 three deployment numeric examples (small / medium /
hardened); §8 operator guidance with target-residual → window-
length solving (e.g. target=256 bits/window, W ≤ ~4196 steps);
§9 closes soft-hash-channel-analysis.md §9.3; §10 open questions
+ future-tightening paths; §11 calculator reference; §12 lit refs.

The closed form (§6):

  I_window ≤ C_B1 · g · W · log₂(SNR_grad + 1)
           + C_B2 · ⌈W/K⌉ · log₂(R)
           + C_B3 · ⌈W/E⌉ · log₂(N_b · σ_grad / ‖∇L_max‖) / 2

Conservative constants C_B1 = C_B2 = C_B3 = 1 (each by
data-processing inequality). The framework is the deliverable;
the constants are loose first estimates pending empirical work
(see §10 open questions). Tightening any of them refines the
bound without invalidating it.

bench/scripts/t3_bound_calculator.py (new, ~190 lines, pure stdlib)
===================================================================

Pure-stdlib CLI — no numpy / scipy dependency, just math.log2 +
ceiling division. Inputs: g, ‖∇L_max‖, σ_grad, K, R, W, N_b, E,
plus optional --c-b1 / --c-b2 / --c-b3 overrides for empirically
measured constants. Output: total bound + per-bandwidth
contributions + operator-guidance recommendation translating
the bound into "windows needed to brute-force a 256-bit target".

Verified against doc §7.1 small-deployment example: produces
625.87 bits/window vs the doc's hand-calculated 622.7. Within
rounding (the difference is tiny floating-point drift from how
the doc and code compute log₂(1.5)).

soft-hash-channel-analysis.md
=============================

§9.3 marked closed-2026-05-10 with reference to the new bound
doc. §11 status updated: open-questions list now reads §9.1
(parks on v7 per #000034 Phase 1b) + §9.2 (awaits v7 §9.10
amendment per #000035 Phase 2); §9.3 closed via #000036.

#000036 status flip
===================

Ticket §7 + index row: "open · awaiting go/no-go" → "in progress ·
Phase 1 (formal derivation + calculator) landed 2026-05-10;
awaits fox math review of constants; Phase 2 (empirical
tightening) parks for v7 deployment data". Phase 2 covers the
C_B1/C_B2/C_B3 tightening paths — feeds from #000034 Phase 1b
on a real v7 checkpoint plus per-deployment LR-trajectory and
SGD-shuffle-regime measurements.

Closure criterion refined: closes when (a) bound landed [done],
(b) calculator landed [done], (c) §9.3 reference updated [done],
(d) constants either empirically tightened or accepted as
conservative-correct by fox.

Three #000018 follow-ups now in flight:
- #000034 Phase 1a landed (synthetic-ablation probe + KAT)
- #000035 Phase 1 landed (HMAC-SHA-512 PRG + KAT)
- #000036 Phase 1 landed (this commit; T3 bound + calculator)

Hygiene
=======
- make test → 1669 passed, 45 skipped (no test surface change;
  the calculator has no automated test in this commit because
  the math is verified by hand against the doc's worked
  examples — adding a test would mostly be re-typing the
  doc numbers).
- make chain-check-shards → 0 across all 7 shards.
- arborist/ Python source unchanged; this commit is doc + script.
2026-05-10 10:32:50 -04:00
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
2bc4a15cc7
docs: ticket #000038 closed — obviated by 2026-05-10 alias-substitution sprint
#000038 was opened to track per-textbook proprietary-license
decisions (Mendelson, Enderton, Jech, Stanley, Brualdi, Knuth,
Barendregt, Dummit-Foote, Goldstein, Kolmogorov + the §6 Hilbert
resolver-miss issue). Yesterday's #000031 Phase 2.5 sprint
obviated all 13 priority items by either:

  - aliasing the cited proprietary work to a peer-level open-
    licensed substrate (Mendelson -> Russell IMP/De Morgan/Boole,
    Stanley/Brualdi/Knuth -> Bogart/Levin/KT, Jech -> Cantor/PoM,
    Dummit-Foote -> Judson, Goldstein -> Newton, Barendregt ->
    PLFA/SF-LF, Kolmogorov -> Grinstead-Snell/Laplace, Boehm-
    Jacopini -> SF-LF, Landau/Goedel -> Peano/Dedekind/IMP/SF-LF)
  - resolving the §6 Hilbert misses via #000040 cascade tuning +
    #000042 term-aliases (incidence/connection, parallel
    postulate/axiom of parallels, non-triviality/space axiom,
    side-angle-side/included angle).

§3.2 option (b) "citation_aliases table" landed as #000041 (54
rows). All 92/92 claim-pack records resolve.

Residue preserved as §8 design log (multilingual PD originals,
Hilbert-Ackermann 1928 OCR, Knuth redistribution permission,
personal-copy path B). None blocks downstream consumers; revisit
only if a future bench surfaces a substrate-deficient record.

Index updated to reflect closed status.
2026-05-10 10:16:27 -04:00
fce88268fd
ticket #000034: propose Phase 1a synthetic-ablation probe (doc-only)
Mirrors #000035's pattern: land deterministic probe infrastructure
+ unit tests + KAT-pinned fixture on synthetic inputs ahead of the
real-deployment target. v7 plastic-training has no representative
checkpoint today (per §5 risk + §7 status); Phase 1a closes that
gap by giving the probe a synthetic test surface that's verifiable
end-to-end without waiting for v7 ramp-up.

What §7 now proposes Phase 1a lands:

1. ``bench/scripts/phi_alignment_probe.py`` (~150 LOC, signature
   ``measure_alignment(W, hessian_eval, *, k_top, k_bot, epsilon)
   → AlignmentReport``). Lanczos top-k + bottom-k via scipy.

2. ``bench/fixtures/phi-alignment/synthetic-checkpoints.jsonl``:
   ~30 deterministic-seed (W, H) pairs across three classes:
   aligned (engineered W in low-λ subspace → expect
   STRUCTURAL_ALIGNMENT), uniform (Gaussian W per v7 reference
   → expect NO_ALIGNMENT), anti-aligned (W in high-λ subspace →
   expect ANTI_ALIGNED). Same KAT-regression discipline as
   #000035's phi_prg fixture.

3. ``tests/test_phi_alignment_probe.py``: round-trip determinism;
   verdict thresholds; Lanczos convergence vs dense decomposition
   on synthetic Hessian; module export shape; KAT regression.

4. New ``[hessian]`` optional-dependencies block in pyproject.toml
   (numpy>=1.26 + scipy>=1.11). Same gating as the existing
   ``[math]`` block for sympy — keeps core install lightweight.
   Tests fail-soft via ``pytest.importorskip`` when absent.

What Phase 1a does NOT land:

- Real v7 checkpoint measurement (parks until v7 deployment
  produces a representative checkpoint per original §5 + §7).
- M1 / M2 implementation (separate tickets).
- Adversarial-training experiment (out-of-scope per §4).

Phase 1b (real-checkpoint measurement) preserves the original §7
closure criterion: ticket closes when a v7 checkpoint produces a
verdict resolving §9.1 of the soft-hash-channel analysis. Phase 1a
is prerequisite infrastructure, not closure.

This is doc-only — no code change in this commit. fox decision
needed before Phase 1a implementation lands.
2026-05-10 10:10:15 -04:00
a9fcb4251d
bench: Phase 3 paraphrase fixture investigation — empirically dormant on current corpus
Three-iteration investigation following c5bc53f's "Phase 3 is a rescue
mechanism, not a default path" finding. Question: can a paraphrase-
eliciting fixture actually drive Phase 3 to fire on real questions?

Key reading from arborist/qa/warrant.py:507 ("warrant_check"):
the function vacuous-passes (returns (True, []) without any anchor
extraction) unless the question shape is one of:
- relation (proper-noun anchors)
- date (4-digit year in claim)
- entity-list
- count-shape
- why-cause-shape

If none of those shapes apply, Phase 3 has nothing to suppress.

Three fixture iterations, all probed before benching:

| iter | strategy                          | chain hits |
|------|-----------------------------------|------------|
| v1   | "What is X?" / "Define X"         | 12/13      |
| v2   | "How would you use X to ..."      |  1/10      |
| v2'  | "X: explain in plain English"     |  2/13      |
| v3   | "Who proposed X?" / "Why does X"  |  1/8       |
| v3'  | "X: who first stated it?"         |  1/8       |

Pattern: title-leading retrieval works (high title-token boost on
chain chunks) but those questions are definitional — no warrant
shape, no Phase 3 trigger. Warrant-shape questions ("who" / "when"
/ "why") trigger warrant_check but retrieval pulls toward
Wikipedia's prose articles instead of the terse claim-pack chunks.

Structural reason: claim-pack chunks (the 92 chain-root documents)
are deliberately terse — they state axioms / theorems precisely
with mathematical formalism but contain no biographical, historical,
or explanatory prose. So warrant-shape questions retrieve from
Wikipedia, where the prose context matches the question shape.
Phase 3's data condition (chain-backed chunk cited for a
warrant-shape claim) is empirically unreachable through normal
retrieval pathways on this corpus shape.

Verdict (`bench/results/phase3-warrant-chain-paraphrase-
investigation-2026-05-10.md`): Phase 3's runtime fire rate is
structurally bounded near zero on the current corpus. Mechanism
is correct, non-regressing, and unit-tested
(tests/test_warrant_chain.py). The lexical layer is strong enough
that the rescue isn't needed at measurable rates.

Recommendation: don't engineer Phase 3 fires via fixture design.
Track fire rate as a corpus-evolution signal. If claim-pack
content gains prose context or the corpus mix changes, Phase 3
will start firing organically and the audit-line tail
(`· warrant proven via chain ×N`) will surface it.

This closes the three-thread investigation cleanly. v1 + v2 + v3
fixtures + reports all retained as the empirical trail.
2026-05-10 10:06:23 -04:00
c5bc53f733
bench: aggressive warrant fixture confirms Phase 3 is rescue-only, not default-path
Followup to dee6623 ("bench: #000031 Phase 3 A/B finds mechanism
dormant on warrant-targeted fixture") — the initial A/B reported
Phase 3 dormant on a 7-question fixture where only 2/7 questions
retrieved any chain-root sources. Open question: was the dormancy
a fixture inadequacy or a structural property of Phase 3?

This commit answers it. Aggressive fixture (13 questions using
exact claim-pack title phrasing — "What is the Pigeonhole
Principle?", "Define the Axiom of Extensionality", etc.; titles
sampled directly from the 92-document chain-root set on shard
000.db) drives retrieval to chain-root chunks on **12/13
questions** (24 chain sources retrieved total).

A/B vs a57b194~1, n=3, 117 cells per condition:

  cache_key parity:                          39/39 cells match
  Phase 3 fire rate (warrant_proven_idxs):   0 / 117 cells
  STRICT-rate:                               85/117 → 85/117 (Δ +0)
  per-cell movement (LLM dice):              4 ↑, 4 ↓

Phase 3 fires zero times even though retrieval does land on chain
roots on 92% of questions. The structural reason now reads as:

  Phase 3 is a rescue mechanism, not a default path. It fires only
  when (a) a cited chunk has warrant-resolver chain backing AND
  (b) the lexical warrant_check would otherwise fail. On
  well-formed axiom questions, the LLM's answer contains the
  technical terminology that the lexical anchor heuristic looks
  for — so warrant_check passes via the cheap lexical path and
  Phase 3 has nothing to suppress.

Two readings of this finding:

1. **Positive for the lexical layer.** It's strong enough on
   clean axiom questions that the chain-fallback isn't needed.
   The mechanism that lands warrants on cheap lexical evidence
   continues to do most of the work.

2. **Phase 3 calibration needs a different fixture shape.** To
   exercise the rescue path empirically, a future fixture would
   need to elicit lexical-fail-but-chain-pass claims —
   paraphrase-heavy questions, disputed-terminology topics,
   questions where the LLM naturally drifts from chunk vocabulary.

Mechanism is correct + non-regressing (cache_keys identical → no
retrieval movement; 0/117 fire rate confirms defensive-only
behavior). No further changes warranted to the implementation.

C — separate finding (refactor sweep verification): a57b194 has
zero v7/v8 patterns. Final exhaustive sweep across arborist/ +
tests/ shows only the intentional historical-note comments in
arborist/cli.py (Was \`arborist v8 score\`...) and
arborist/substrate/__init__.py (explaining why v-dirs were
retired). Refactor cleanup is complete.

B — separate finding (Makefile bench-fork-score smoke):
make bench-fork-baseline + make bench-fork-score runs end-to-end
under the renamed CLI. Verdict MARGINAL (score 0.0 for self-
comparison), exit 0. Yesterday's Makefile:430 fix verified live.
2026-05-10 09:53:21 -04:00
1d2a558635
Phase 3 live validation: 6/7 probes reach EVIDENCE-WARRANTED
End-to-end smoke against the live shard cluster (~/.arborist/shards
+ ~/.arborist/crawl) using the parallel-shift probe fixture
bench/qa_questions_warrant_chain_probe.txt (7 questions explicitly
targeting the 92 claim-pack-warrant-resolved records).

Result: 6 of 7 questions reach EVIDENCE-WARRANTED on the four-rung
ladder. Q1 ("axiom of line incidence in Hilbert geometry") shows
the source-level "warrants: 5 proven" tail correctly counting all
5 cited claim-pack records with derivation chains. Q5 (De Morgan)
falls to ANCHOR-WARRANTED-PARTIAL on mixed Wikipedia/claim-pack
retrieval; Q7 (pigeonhole) hits TITLE_MISMATCH because retrieval
surfaced a Wikipedia article that shares no token with "Bogart".
Both Q5 and Q7 are correct fail-closed behavior given retrieval
choices, not Phase 3 issues.

What this validates:
  - warrant_chain_lookup loads live 92 core_roots
  - warrant_proven_claim_idxs threads through verdict -> result
    dict -> JSON output (was None on cache hits, [] on fresh
    misses — correct cache invariance preserved)
  - source-level "warrants: N proven" tail fires
  - EVIDENCE-WARRANTED rung promotes via existing
    _ladder_rung_for_lattice logic without render-layer changes
  - empty-set fail-closed default preserves backward compat

What's NOT validated end-to-end (still unit-test-only):
  - Per-claim "· warrant proven via chain ×N" tail. Fires only
    when warrant_check would have demoted AND chain present.
    Narrow regime; covered by test_verify_claim_lattice_suppresses
    _warrant_missing_with_chain.

Picks up the parallel-shift's probe fixture (was untracked); now
committed alongside the validation journal.
2026-05-10 09:46:10 -04:00