Per fox: apply the conservative max_envelope B1 model by changing the
v1 calculator's default — NOT by forking a v2. CALCULATOR_VERSION stays
"t3-bound-v1-bottou-refinement" (the descriptor names the unchanged B3
term); b1_model is echoed in the output AND the inputs dict so KAT
replays are unambiguous about which model produced a row.
Calculator (bench/scripts/t3_bound_calculator.py):
- New b1_model kwarg + --b1-model CLI flag, choices:
max_envelope (default) max(fraction_channels, aggregate_bias)
fraction_channels g · W · log₂(1 + G/σ)
aggregate_bias W · log₂(1 + g·G/σ)
effective_control_v1 g · W · log₂(1 + g·G/σ) (old non-worst-case)
- Default is now max_envelope — genuinely upper-bounding across both
interpretations of g (dav1d review §3 closure blocker, RESOLVED).
- Every output reports all three concrete B1 variants
(B1_fraction_channels / B1_aggregate_bias / B1_effective_control_v1),
b1_selected, and both SNR readings (snr_grad = g·G/σ,
snr_per_channel = G/σ) regardless of which b1_model was requested.
- model_assumptions[] now carries f"B1_model_{b1_model}".
- inputs echo now includes c_b1/c_b2/c_b3/b1_model (replay-complete).
- Invalid b1_model rejected with a ValueError naming the field.
- Baseline I_window: 625.8716 (effective_control_v1) → 6183.0154
(max_envelope: B1=aggregate_bias 5849.63 dominates fraction_channels
1729.72), certification_status NOT_CERTIFIED_BY_BOUND at W=10000.
KAT fixture (bench/fixtures/t3-bound/known-answer-tests.jsonl):
- Regenerated 2026-05-11 — 12 entries: the 8 §7-derived configs under
the new max_envelope default, a g=0 edge case, plus explicit-mode
pins for effective_control_v1 / fraction_channels / aggregate_bias.
- Each entry carries b1_model, expected_b1_selected,
expected_b1_{fraction_channels,aggregate_bias,effective_control_v1},
expected_snr_per_channel, expected_certification_status.
Tests (tests/test_t3_bound_calculator.py, 75 → 83):
- test_t3_bound_known_answer_tests no longer skips (fixture active);
pins b1_model, b1_selected, certification_status + numbers, tolerates
optional new fields on older fixtures.
- New: test_b1_max_envelope_exact_formula, test_invalid_b1_model_rejected,
test_cli_b1_model_flag (effective_control_v1 / fraction_channels /
aggregate_bias). test_b1_exact_formula renamed
test_b1_effective_control_v1_exact_formula and now passes the explicit
model. Updated baseline / below-256 / CLI tests for the new numbers.
Doc (docs/soft-hash-channel-t3-bound.md):
- Header + §0 + §3.1 + §6 + §7 (worked examples) + §8 (operator
guidance W-solving) + §10 (closure blockers RESOLVED) + §10.1 +
§11 (calculator schema) + §12 all updated for the max_envelope
default. §8: target-256 W drops from ~4196 to ~415 steps under the
conservative model — the ~10× cost of not assuming which g-reading
holds; operators who can measure effective-control applies can use
--b1-model effective_control_v1 for the looser W (a calibration
claim they must justify, not a default).
Status (#000036 ticket + TICKETS.md): both prior dav1d closure
blockers cleared (B1 worst-case model + active KAT fixture); remaining
= fox's final close-or-iterate call.
AUTOCOUNT markers bumped 75 → 83. Full suite: 2288 passed, 28 skipped.
dav1d's review (RESPONSE_1 + RESPONSE_2) returned 2026-05-11. This
lands the Tier-1 items — everything that doesn't change numeric
outputs or invalidate the KAT discipline. The Tier-2 B1 conservative-
envelope (v2 calculator) is a separate decision and stays a closure
blocker.
Calculator (bench/scripts/t3_bound_calculator.py):
- Recommendation wording: "M2's single-window guarantee is broken"
→ "this conservative bound CANNOT CERTIFY M2's residual". An upper
bound exceeding 256 bits means we cannot certify, NOT that the
adversary can steer 256 bits — the prior wording overclaimed.
- New structured output fields: b1_model ("effective_control_v1"),
certification_status ∈ {CERTIFIED_BY_BOUND, NOT_CERTIFIED_BY_BOUND},
certification_threshold_bits (256), model_assumptions[]. Callers
read a machine-readable status, not just prose.
- Input validation hardening: _require_finite_float / _require_positive_int
helpers reject bools (isinstance(True, int) is True in Python — a
real leak risk for a security calculator) and NaN / ±inf for every
numeric input and constant.
- gradient_fraction = 0 now accepted (no T2 surface; B1 = 0; T3's
LR + batch-order channels still contribute) — improves component
isolation. CLI help + module docstring updated accordingly.
- Numeric outputs UNCHANGED: baseline still 625.8716 / 292.4813 /
300.0 / 33.3904; b1_model stays effective_control_v1; KAT discipline
intact.
Tests (tests/test_t3_bound_calculator.py, 53 → 75):
- Hard-coded cwd="/home/fox/git/arborist" → pathlib.Path(__file__).
resolve().parents[1] so the suite runs on any checkout.
- New: test_gradient_fraction_zero_accepted, test_bool_rejected_for_int_fields,
test_bool_rejected_for_float_fields, test_nonfinite_numbers_rejected,
test_output_carries_b1_model_and_certification_fields,
test_certification_status_certified_below_threshold.
- test_recommendation_exceeds_sha256 now also asserts "CANNOT CERTIFY"
+ certification_status == NOT_CERTIFIED_BY_BOUND.
Doc (docs/soft-hash-channel-t3-bound.md):
- §0 reworked into a reviewer brief recording dav1d's findings
(§2 accepted, §4 accepted, §5 accepted as model-bound, §3 = closure
blocker, wording/validation = applied).
- New §3.1: the B1-double-g issue spelled out — effective_control_v1
vs fraction_channels vs aggregate_bias vs max_envelope, with the
baseline-spread table (292 / 1730 / 5850 / 5850 bits); v2 path
described.
- §5: "B3 is a model-bound, not a directly-quoted theorem" note.
- §10: items 1-2 are now the closure blockers (B1 envelope v2; active
KAT fixture); items 3-7 are tightening paths (#000043). New §10.1
records what the 2026-05-11 hardening pass already landed.
- §11: calculator-output example updated to show the new fields +
corrected recommendation wording.
- §12: references add the dav1d review + clarify Bottou-Bousquet
"inspires" (not "underlies") the §5 model-bound.
Status (#000036 ticket + TICKETS.md row): review-returned + Tier-1-
applied; closure blockers = B1 v2 envelope (awaits fox go/no-go) +
active KAT fixture. R2's architectural integrations (Merkle audit-
event commitment, SQD canonicalization, CTI clause-lattice, 5F
trigger, ForkScore security-risk) noted as out-of-scope (separate
tickets if wanted).
AUTOCOUNT markers in docs/calculator-test-patterns.md +
docs/warrant-substrate-cookbook.md bumped 53 → 75.
Full suite: 2264 passed, 28 skipped.
Land the three test-pattern shapes the Explore-agent investigation
of fox's overnight π* kernel commits surfaced. Patterns 1-8 in
this doc were the original 9-item checklist; patterns 9-11 are
new domain-specific contract pins that the π* kernels require but
that t3_bound_calculator (the original exemplar) does not.
== New patterns added ==
**§9 Projective-contract pin (one-way canonicalizers)**
For canonicalizers whose output type ≠ input type — output is
not in the input domain by design — assert that re-applying the
function raises. Pinned in code-py-ast@v1 (Python → S-expr) and
time-series-quantized@v1 (JSON → quantized text). When the output
type DOES equal the input type (arithmetic kernel's ℚ → ℚ),
use the dual: round-trip idempotence
``canonicalize(canonicalize(x)) == canonicalize(x)``. Both pin a
contract; pick by the kernel's type signature.
**§10 Dispatch-order pin (Python type-hierarchy gotchas)**
Python's ``bool`` subclasses ``int``, so a naive ``isinstance(x,
int)`` chain never reaches a bool branch. Kernels distinguishing
``True`` from ``1`` (Python AST normalizers, etc) must check
``bool`` first. Pin the branch order so a "simplify the dispatch"
PR fires loud. From ``593550b``.
**§11 Tie-breaking-rule pin (banker's rounding)**
Python's ``round()`` uses ties-to-even (PEP 3141): 0.5→0, 1.5→2,
2.5→2. Naive switch to ``math.floor(x + 0.5)`` (round-half-up)
produces 0.5→1, 1.5→2, 2.5→3 — different output for tie inputs
without breaking non-tie tests. From ``2585d3c``.
Each pattern has worked-example pseudocode + cross-reference to
the actual test file in fox's commit. The pattern numbers extend
the existing 1-8 sequence; renumbering would have invalidated
prior references.
== Checklist updates ==
Items 10/11/12 added (conditional — only when the kernel's shape
exposes the corresponding surface). Many calculator modules
(t3 bound, anchor PRG) need only items 1-9.
== Exemplar files reorganized ==
Replaced the single-exemplar reference (t3_bound_calculator only)
with a 5-file table cross-referencing the 9-12 checklist items
each exemplar covers:
test_t3_bound_calculator.py items 1-9 (53 tests)
test_pi_star_arithmetic.py items 1-6 + 9 + idempotence (56)
test_pi_star_logic.py items 1-6 + 9 + 11 (53)
test_pi_star_code.py items 1-6 + 9 + 10 + 11 (32)
test_pi_star_time_series.py items 1-6 + 9 + 10 + 12 (35)
All five test counts AUTOCOUNT-tagged so future drift fires the
regression test landed in ``fc5ba50`` / ``03c0f6a``. Total tagged
claims now 49 (was 44; +5).
== Source ==
Patterns surfaced from the Explore-agent investigation of fox's
overnight 2026-05-10 commits (``6c9bc04`` arithmetic, ``e7bef5f``
logic, ``593550b`` code, ``2585d3c`` time-series — 176 KATs total
across 4 π* canonical-projection kernels). The agent walked each
commit, noted the test patterns that didn't appear in the
original 9-item checklist, and reported the pattern shapes back.
This commit promotes those findings from session memory to
architecture-reference docs.
Verification:
$ pytest tests/test_doc_counts.py -v
3 passed in 3.39s
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.
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.
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".