Commit graph

266 commits

Author SHA1 Message Date
2c98fc964e
feat: cross-language Q&A (Operation Sandwich) + Windows quickstart — all default-OFF
Three workstreams, full suite 2482 passed, experimental paths default-OFF.

#000055 — Windows quickstart without make
  tasks.py (pure-stdlib runner) + make.bat shim + .gitattributes;
  README Windows section rewritten. Quickstart needs only Python
  3.10+ (no make/bzip2/curl/bash). Mirrors the Makefile quickstart
  subset; drift-pinned by tests/test_tasks_runner.py.

#000001 §7 Phase 0 — deterministic cross-language guard
  arborist/qa/crosslang.py: non-English signal (¿/¡/non-ASCII) + an
  es function-word stoppack. Fail-closed to UNGROUNDED before
  retrieval/LLM (mirrors the quantifier reject-DAG) when no content
  token survives, else strips es stopwords from the retrieval query
  only. English path byte-identical by construction. Default OFF
  (crosslang_guard_enabled). Measured: the anarcocapitalismo field
  case 10.4s -> 1.6s.

#000056 — Operation Sandwich (cross-language grounding)
  arborist/qa/mt/: opus-mt es/fr/ru<->en, lazy per-pair memoised
  singleton (fixes the 88%-engine-error concurrency defect),
  manifest-pinned, [mt] extra; entity_mask wrapper. Sandwich =
  translate query in (retrieval + LLM prompt) -> English answer ->
  UNTOUCHED verifier grounds English-vs-English -> translate the
  verified answer out as display-only (banner-labelled, zero
  grounding). question_hash + verifier_policy_hash invariant; MT
  engine identity binds into RetrievalPlan, not governance. CLI
  --crosslang-translate / make XLANG_MT=1. Default OFF; entity_mask
  default OFF (measured net-negative at bench scale). Fan-out bench
  (bench/*.py): Spanish ~0% -> 71% grounded vs the real no-support
  baseline; the round-trip predictor was tried and refuted; the
  entity-mask lever failed at scale (corpus-title anchoring untried).

CLAUDE.md: cross-language bright-line convention + module map.
Pre-existing modified diagram files are intentionally excluded.
2026-05-18 12:12:23 -04:00
b711215f11
docs: pagers — rename 'not grounded' → 'ungrounded' (agreed label set: grounded / partly grounded / ungrounded)
'not grounded' was a drift from the agreed three-label vocabulary. Single-word labels are cleaner in tables, diagrams, and prose.
2026-05-14 12:56:13 -04:00
42ed5c61a7
docs: pagers — point hermes link at /v1 (display) → /v1/models (href) so readers see the OpenAI-compatible base URL and can click through to the live model card
Previously linked to the bare domain, which serves a marketing page. The actual OpenAI-compatible endpoint is /v1; /v1/models is the clickable verification (returns the served model card on the live deployment).
2026-05-14 11:33:40 -04:00
3a9389f24b
docs: correct storage figures in pagers — actual per-shard target is ~10 GB, live deployment is 4 shards × ~9.6 GB ≈ 38 GB (was wrongly stated as ~2 GB)
Shard capacity convention is documented in arborist/search/fts5.py:113 ("~50ms cold per token on a 10GB shard"). The earlier "~2 GB for a Wikipedia-sized corpus" line in both pagers was a fabricated figure off by 20×. Replaced with the real numbers: per-shard ~10 GB design target, live deployment of four shards totalling ~38 GB and holding 3.5 M documents / 6.2 M chunks.
2026-05-14 11:16:20 -04:00
75ae470581
docs: rewrite arborist-one-pager + arborist-two-pager for external readers — drop ticket refs, schema versions, and internal vocabulary; reframe around user value (verified answers, fabricated-citation prevention, replay)
Old drafts read as internal substrate notes. Rewrites lead with what the system does for a consumer or evaluator and what it costs to run, with no references to internal tickets, table names, schema-version strings, governance hash dimensions, or per-record audit-mode tokens. Appendix diagrams updated in lockstep: friendly labels ("grounded / partly grounded / not grounded") replace the schema-column trichotomy, layer names paraphrased away from SURFACE/CORE/PROVIDENCE.
2026-05-14 10:02:08 -04:00
0aada29a8e
docs: arborist-one-pager + arborist-two-pager — Dav1d/fox-signoff summaries with letterhead, license, and 2 strategic appendix diagrams
1-pager (docs/_source/arborist-one-pager.rst, 1 page) for AI-literate readers: the trichotomy, the 8-dim cache key, CTI synthetic-elision-impossible, soft-channel separation, real-traffic bench numbers (mis-cite 100% @ 0% FP, warrant 92/92, quote 0.54 STRICT-rate).

2-pager (docs/_source/arborist-two-pager.rst, 3 pages = 2 body + 1 appendix) for technical reviewers: letterhead, Permacomputer Preamble license box, six numbered sections, plus appendix figures (pager-arch-stack 3-layer architecture, pager-verifier-flow question→pointer→verifier→trichotomy).

Both pages live under docs/_source/ so the same RST renders into the Sphinx readthedocs site (toctree caption "Summary pages" added to docs/_source/index.rst) AND into standalone PDFs via rst2pdf (docs/pager.style, lazy install into .venv).

Makefile targets: docs-one-pager, docs-two-pager, docs-pagers, docs-pagers-clean. Diagrams render through the existing DOT pipeline.
2026-05-14 09:48:50 -04:00
90d5c54c0a
docs: relevance-and-veto-synthesis-for-dav1d.md — single decision brief synthesizing #000049 + #000052 §3.1 + §3.2 for forward review
Synthesizes the bench-maxing work across:
  #000049 NLI recombination veto (bart-large-mnli/k=12/margin/θ=0.999
    → 48% real-haystack recall at 0/808 STRICT FP — partial closure,
    Phase-3 semantic candidate selector for full closure)
  #000052 §3.1 diagnose_coherence (lexical sidecar, advisory-only,
    1.1% real-STRICT FP after round-2 patch)
  #000052 §3.2 relevance reranker (bge-reranker-large + cleaned +
    θ ≤ -2.42 → 100% mis-cite / 55% deflection / 0% STRICT FP —
    motivating Zionist-shape failure fully covered)

The three are architecturally orthogonal (§3.2.2 step 3C verified:
combining lexical sidecars with the relevance reranker gives no
lift; each owns its own failure-shape slice). Three structurally
distinct demote-only signals layered on the binary verifier.

Three runtime-promotion decisions for fox+dav1d:
  - §3.1: keep advisory or wire policy hook? (probably advisory)
  - §3.2: promote at the fp=0 operating point? (sign-off folds
    relevance_policy_hash into governance_policy_hash)
  - #000049: promote at 48% partial closure, or wait for Phase 3
    semantic candidate selector?

Bench-maxing methodology codified in CLAUDE.md is the transferable
artifact: 'clean candidate-bench can mis-predict in BOTH directions
— real-data fixtures on both precision AND recall axes are the
only load-bearing measurement'. Eight instances across the two
arcs; the discipline applies to any future model-based addition.

Indexed in docs/TICKETS.md 'Distinction from other docs' section as
a non-ticket reference doc. Production verifier unchanged; nothing
in audit_mode; all work SHADOW pending sign-off.
2026-05-13 15:34:21 -04:00
9fc951592d
#000052 §3.2.2 step 2: relevance shadow sweep on 808 pooled bench-qa STRICT — universal walk-back, runtime veto NOT VIABLE on this design
All 6 swept rerankers (bge-large/base, MiniLM-L-2/L-4/L-6/L-12)
false-fire on 4.5–21.8% of real bench-qa STRICT at their
candidate-bench fp=0 θ. The smallest θ that yields fp=0 on real
STRICT is BELOW the candidate-bench NEG max for every model —
meaning at the runtime-safe θ, catch on the 12 candidate-bench NEG
= 0/12 across the board.

Structural reason: real bench-qa STRICT answers have a much wider
score distribution (bge-large STRICT: min -2.20, p10 +2.99, p50
+5.80, p90 +7.54) than the tight contrived candidate-bench POS
band. The bottom 10% of legitimate STRICT score below where the
candidate-bench NEG cases sat. Distributions overlap heavily; no
threshold separates them.

This is the §3.2 mirror of #000049 §7 #27's recall-side walk-back —
clean candidate-bench → fails real-pipeline gate. Same diagnosis:
lexical-candidate selection + cross-encoder scoring + hard threshold
doesn't survive real-pipeline heterogeneity.

Verdict: relevance reranker CANNOT be promoted to a runtime
demotion-only veto on this design. demote_below_score stays null;
manifest gains runtime_viability block documenting the negative
result + the still-viable advisory soft-signal uses (render-tail,
multi-signal advisory, contrastive Q→A vs claim→source delta).

bench/scripts/relevance_shadow_sweep.py + bench/results/
relevance-shadow-sweep-pooled808.json committed. Production
verifier unchanged; advisory only; no audit_mode effect.
2026-05-13 14:17:38 -04:00
5f4f4ceb1c
#000052: more tests for §3.1 + §3.2 — bench-max the detectors against real data
§3.1 diagnose_coherence (now 19 tests, +10 from the parallel session's 9):
- 3 more positive shapes (multi-sentence vacuous, named-entity circular,
  grammar-term phrase_component_reuse).
- 5 xfail regression tests for SHAPES THAT FALSE-FIRE on real bench-qa
  STRICT data (44/808 = 5.4% FP rate measured on the pooled n=1+3+5
  STRICT answers). Each xfail names the exact shape + why it should
  ideally be 'ok' + which rule needs tightening:
    * 'The chemical symbol for gold is Au.' → vacuous (short predicate)
    * 'Michael Jordan's Restaurant was a restaurant ... named after
      Michael Jordan.' → circular (named-after re-use)
    * 'The Western X was the western half of the X' → circular
    * 'The name <Phrase> is a translation ... of the <derivative>' →
      phrase_component_reuse (translation/etymology)
    * claim-lattice [E1 | … …"] tails → vacuous (truncated bracket
      fragment)
    * 'The term <X>' → phrase_component_reuse (idiomatic English)
- 1 load-bearing real-traffic test: FP rate on 808-cell pooled STRICT
  must stay ≤ 7% (current 5.4%) — fires loud if a future change
  regresses it. Skips on fresh-checkout (bench/qa_results/ gitignored).

§3.2 ShadowRelevance (now 20 tests, +7 from the round-1 scaffold):
- Manifest tests for round-2 primary (bge-reranker-large), the size
  spectrum coverage (50-560MB), the candidate-bench findings block
  (biggest-within-family / not-across-families / deeper-not-better /
  capacity-floor).
- Pair-kind distinction (question_answer vs claim_source recorded
  separately for downstream telemetry / governance hashing).
- Batch-order preservation (_score_batch must return scores in input
  order — load-bearing for downstream zip-back).
- Empty-input handling (Q empty, D empty, whitespace-only).
- Zionist-entity discriminator sanity (on-topic > off-topic logit).
- demote_below_score-stays-null invariant (the §7 #18→#27 discipline:
  no hardcoded threshold; must come from a real-traffic shadow sweep).

Total: 101 passed + 6 xfailed (5 §3.1 regressions documented + 1 from
parallel session). The 5 xfails are the bench-maxing receipts — they
document EXACTLY which shapes §3.1 false-fires on, with the rule that
needs tightening named in each reason.
2026-05-13 12:38:09 -04:00
c2c06c971e
#000054 index row: Phase-2 landed ce855db + bench result recorded 2026-05-13 10:28:19 -04:00
79ba3f99fb
#000054: record Phase-2 bench result (n=3 limit=5: 30/45 STRICT, 0 regressions on basics)
`make bench-qa BENCH_QA_N=3 BENCH_QA_LIMIT=5` (2026-05-13T14:24Z) on
the bench/qa_questions.txt set: 30/45 STRICT (67%), zero regressions
on mona lisa / capital of france / new london bridge (each 9/9 STRICT
across quote / pointer / lattice modes). The bench-qa-smoke n=1
flickers I saw ("dinosaurs" S→U, "soviet union" S→H) were LLM
stochasticity at n=1, not retrieval bugs. GNU-linux + python failures
look like genuine hard questions, not Phase-2 side effects.
2026-05-13 10:27:57 -04:00
ce855dbdad
#000054 Phase 2: synonym_expand cap-aware + strict view + retrieval-route surfacing
End-to-end gap-close from the Phase 1 extractor. Five interlocking
fixes; live-verified that `what is a CPU?` → "Central processing unit"
at #1, `what is a GPU?` → "Graphics processing unit" at #1
EVIDENCE-WARRANTED 1/1; Mount Kilimanjaro / Soviet Union queries
unchanged (no regression).

(a) `synonym_expand` over-cap path is now rank-and-truncate by
source-frequency (descending) instead of hard-skip. CPU has 13
legitimate homonym expansions across the corpus; the prior
MAX_NEIGHBORS_PER_TOKEN=8 cap contributed *zero* expansion → no
canonical-article surfacing. Now: keep the 8 dominant by per-(token,
target) source-root count via _load_neighbor_source_freq.

(b) `_search_titles` orders by FTS5 bm25 ASC instead of LENGTH(title)
ASC on the FTS5-MATCH path. The length-asc tie-break was correct for
the 2026-05-02 "Back to the Future" LIKE-substring case but
counter-productive on FTS5 (tokenized; no substring junk; length-asc
preferred "Unit" / "Unite" / "B unit" over "Graphics processing
unit"). LIKE fallback keeps length-asc since the substring issue
persists there.

(c) `accept_tokens` (feeds title-search, core-keyword, title-rerank)
uses the synonym-expanded set instead of qtokens-only. The Phase 1
expansion existed but was only used in the FTS5 OR-fallback; satellite
articles saturated the budget before the canonical article entered.

(d) ARCHITECTURAL: `synonym_expand_strict()` (new — high-trust
evidence-kind subset: manual + manual_legacy + acronym_parens,
**excludes** link_reciprocity) for use in the multiplicative
`_rerank_by_title_purity` and as the source for `accept_tokens`.
Reciprocal-wikilink edges express *topical adjacency*, not synonymy
(a `Dinosaurs` page reciprocally links to `Curious George Brigade` →
edge that should not amplify retrieval); a multiplicative ranker over
them blows up. Strict view preserves the acronym-parens surfacing
(those edges ARE the phrase=expansion identity) while keeping
link-reciprocity to additive retrieval-route boosts via the broad
synonym_expand (still wired to `or_synonym_pool` for the FTS5 OR
fallback).

(e) Extractor regex tightened `[A-Z]{2,6}` → `[A-Z]{3,6}` and purged
~21K 2-letter acronym edges from shards. 2-letter acronyms (AI/ML/OS/
US/UK/IT/PC/TV) homonym-collide too often with common 2-letter QUERY
tokens like `go`/`is`/`am` — without this, "why did the dinosaurs go
extinct?" pulled Curious George Brigade via GO-acronym edges. The
high-value acronyms (CPU/GPU/RAM/DNA/FBI/WHO/…) all clear 3 chars.

Also: CLAUDE.md gains a "prefer existing ticket; only split for
Dav1d-review audience" discipline note (saved as feedback memory) —
this work is itself an example: would have been #000055 + #000056 +
#000057 under the prior pattern; instead extends #000054.

Suite: 2531 passed (no regression). bench-qa in flight separately.
2026-05-13 10:23:36 -04:00
da5af2dfaa
#000052 §3.2.1 round-2: extend size spectrum to 7 models (30MB-560MB, ~20×) — real model science from a wider sweep
7 models on the 4090 against the 26-pair candidate-bench:

  bge-reranker-large    560MB  +6.285  ← new primary (most cushion)
  ms-marco-electra-base 110MB  +5.349  (cost alternate — 5× smaller, 87% the margin)
  MiniLM-L-4-v2          50MB  +3.187
  bge-reranker-base     280MB  +3.076
  MiniLM-L-6-v2          80MB  +3.053  (was primary before §3.2.1)
  MiniLM-L-12-v2        130MB  +2.663  (deeper ≠ better — same pattern as §7 #24)
  MiniLM-L-2-v2          30MB  -1.970  ← capacity floor (NOT separable, 10/12 catch)

Findings:
- Biggest is best WITHIN a family (bge-large > bge-base, 2× size → 2× margin).
- Across families: electra-base (110MB) beats bge-base (280MB) — 60%
  smaller, 75% more margin. Architecture/training corpus > parameter count.
- Depth non-monotonic within MS-MARCO MiniLM: L-4 > L-6 > L-12.
- Capacity floor between L-2 (30MB, fails) and L-4 (50MB, separates).
- 6 of 7 clean-separate the candidate-bench. The 'reranker catches
  Zionist-style mis-cites' claim is a property of competent rerankers
  as a class — once above the floor.

Manifest primary moves to bge-reranker-large for cushion. demote_below_score
STAYS null — clean candidate-bench doesn't predict real-pipeline behavior
(§7 #18→#27 = 6 verdict flips). Expect a walk-back at §3.2.2 step 2.
2026-05-13 10:05:56 -04:00
aeeef603a1
#000052 §3.2.1: candidate-bench landed (4 models × 26 pairs on the 4090 — proper bench, not the 6-pair smoke)
All 4 manifest candidates clean-separate (12/12 NEG catch at 0/14 POS FP),
so 'reranker discriminates Zionist-entity-style mis-cites' is a property
of MS-MARCO-trained rerankers as a class — not the specific L-6 I picked
first. Ranked by separation margin (per §7 #18: separation beats raw):
  ms-marco-electra-base   +5.349  ← new primary
  BAAI/bge-reranker-base  +3.076
  ms-marco-MiniLM-L-6-v2  +3.053  (previous primary, demoted)
  ms-marco-MiniLM-L-12-v2 +2.663  (worst — deeper ≠ better)

Manifest primary moved to electra-base for the cushion. demote_below_score
STAYS null — clean candidate-bench thresholds don't predict real-pipeline
behavior (the §7 #18→#27 history is 6 verdict flips on the NLI side);
§3.2.2 step 2 (real-traffic shadow sweep on pooled bench-qa STRICT) is
what sets it. Expect a walk-back. Reranker still doesn't catch the
Kilimanjaro/Mount-Kenya recombination (aboutness ≠ truth-of-attribution;
that's #000049 territory). fox's bench-maxing correction applied.
2026-05-13 09:57:26 -04:00
9532c47f0e
#000052 §3.2: SHADOW SCAFFOLD landed — arborist/qa/relevance/ mirrors arborist/qa/nli/; primary cross-encoder MS-MARCO-MiniLM-L-6-v2; Zionist-entity field case discriminated (+9.96 vs -9.04, 18-pt margin)
arborist/qa/relevance/ — manifest pins cross-encoder/ms-marco-MiniLM-L-6-v2
(~80MB, Apache) as primary; alternates: L-12, BAAI/bge-reranker-base,
ms-marco-electra-base. demote_below_score=null on purpose — the
#000049 §7 #18→#27 discipline (proved 6× that clean-eval thresholds
don't transfer to bench-qa data) requires the threshold to be set by a
shadow sweep against pooled real STRICT, not by a literature number.
ShadowRelevance class mirrors ShadowNLI (lazy [nli]-extra import, cuda
auto-detect via ARBORIST_RELEVANCE_DEVICE or ARBORIST_NLI_DEVICE,
batched _score_batch, graceful degrade-to-available=False). Two surface
methods: check_question_answer (deflection / Q-A drift) and
check_claim_source (topic-collision mis-cite). 13 tests.

Sanity on the motivating field case (Zionist entity): ON-topic +9.96
vs OFF-topic -9.04 → 18-pt margin. Mona Lisa Q→A deflection: on +10.45
vs deflect +3.56 → ~7-pt margin. The model CLEANLY discriminates the
failure modes #000052 §1 named. It does NOT catch the
recombination-where-the-different-entity-clause-also-mentions-the-target
case (Kilimanjaro/Mount Kenya) — and that's the right architectural
split: aboutness (#000052 §3.2) and entailment (#000049 NLI) are
orthogonal axes; the Kilimanjaro recombination case needs the semantic
candidate selector (#000050/#000051 vec hybrid).

Remaining: build candidate-bench eval (~20-30 deflection + mis-cite
fixtures), shadow-sweep θ over pooled bench-qa STRICT (expect another
walk-back per the #000049 lesson), recall-side realism check, then
fox+dav1d sign-off. Still SHADOW; production verifier unchanged.
2026-05-13 09:46:37 -04:00
658f269d2f
docs: bump warrant-substrate-cookbook AUTOCOUNT 20 -> 28 for #000054 tests
test_concepts_extract.py grew 20 -> 28 with the acronym_parens
extractor's 8 tests; the AUTOCOUNT discipline (CLAUDE.md) fires the
doc-counts regression on stale numeric claims.
2026-05-13 07:01:02 -04:00
58027e9760
#000054: acronym-parens concept extractor (closes abbreviation→expansion retrieval gap)
`arborist/concepts/extract.py:acronym_parens_synonym` — new
corpus-agnostic extractor. Scans each doc's lead chunk (first 4000
chars) for `<Multi-Word Phrase> (ACRO)` where the all-caps acronym's
letters strictly match the content-word initials of the phrase, in
order, after function-word filtering. Emits bidirectional synonym
edges between the lowercased acronym and each ≥3-char content token
of the phrase, evidence_kind="acronym_parens", anchored to that doc's
document_root. Idempotent like link_reciprocity_synonym.

Why this complements link_reciprocity: Wikipedia represents
abbreviation→expansion as a one-way *redirect* (CPU →
Central processing unit), which the ingest does not record as an
edge — so the existing reciprocal-link extractor never learned the
relation. The relation IS in body text by near-universal convention
("Central processing unit (CPU) is..."), which this extractor reads.
Corpus-agnostic: HTML, blogs, textbooks benefit equally.

Conservative: strict 1:1 acronym-to-atom match (rejects HTTP-shape,
where letters land mid-word), function words filtered, repeated
definitions deduped per doc, ≥3-char target floor. 8 new tests
covering CPU bidirectional emit, RAM idempotency, FBI function-word
filter, HTTP length-mismatch reject, XYZ initial-mismatch reject,
ROM hyphenated-word handling, per-doc dedupe, registry presence.

Retrieval-side only — synonym edges reshape FTS5 candidate selection
via synonym_expand at query time, never enter audit_mode / cache_key
/ audit_event_hash. No governance hash bump, no cache invalidation.

Closes #000050 §2a's CPU/GPU abbreviation rows *upstream* of vec;
the Orwell-shape conceptual-allusion row remains the genuine #000050
justification. Operational follow-up (not code): run on each shard
via `arborist concepts derive --extractor acronym_parens` (CLI
surface itself is aspirational in docstrings; extractors are called
programmatically today). Next ID 000054 -> 000055.
2026-05-13 07:00:25 -04:00
4352b84508
#000049 §7 #27: recall-side realism check — synthetic 28/28 was a 4x over-estimate; bart-large-mnli/k=12/max/θc=0.999 is the new fp=0 leader on real haystacks at 0.48 recall (vs §7 #26's claimed 28/28 → 0.24 on real)
Built bench/fixtures/5f/recombination-realcontext-v1.jsonl: 25 hand-built
recombination claims (deliberate re-attributions within real bench-qa
30 KB Wikipedia haystacks the pipeline produced — Mount Kenya into a
Kilimanjaro answer, Galileo onto all 63 Jupiter moons, Joshua Reynolds
onto the Mona Lisa, etc.). Ran the full 7-model × full-grid sweep vs
the 808 pooled STRICT. Result:

- bart-large-mnli / k=12 / max / θc=0.999 → 12/25 = 0.48 catch · 0/808 FP
  (the real-haystack fp=0 leader)
- deberta-large-mnli / k=3 / margin / θc=0.995 → 6/25 = 0.24 (§7 #26's
  'settled' config — 28/28 synthetic, 0.24 real-haystack: 4× over-estimate)
- roberta-large 0.12, MiniLM 0.08, deberta-base 0.04

So §7 #26's 'boundary closed' walks back to 'boundary PARTIALLY closed'
on real haystacks. The bottleneck is architectural: top-k by token
overlap misses the contradicting clause when it shares few subject-area
tokens with the answer (e.g. the Mount Kenya clause only shares 'Kenya'
with a Kilimanjaro claim — ranked low, NLI never sees it). Threshold
tuning doesn't lift the ceiling; a SEMANTIC candidate selector
(vec-driven, sibling of #000050/#000051's hybrid retrieval) does.

bart's pareto above fp=0: fp=0.011 catch=0.52, fp=0.057 catch=0.84,
fp=0.068 catch=0.92 — permissive operating points are on the menu if
fox+dav1d sign off. recommended_operating_point updated to
bart-large-mnli/k=12/max/θc=0.999; deberta-large/margin kept as the
synthetic-eval reference. Sixth meta-lesson instance: clean synthetic
eval doesn't predict bench-qa precision OR recall — neither contrived
dataset axis is load-bearing, only the real pipeline shape is.

Production verifier unchanged; falsification-hard stays 10/12. Still
SHADOW; runtime promotion fox+dav1d-decides.
2026-05-13 06:35:36 -04:00
d57e5c1435
#000049 §7 #26: mining for real recombinations + the pooled-808-STRICT check — verdict settles on margin@0.995
(a) Mined the pooled n=1+3+5 bench-qa runs (808 distinct STRICT answers)
for natural recombinations at lowered θc≥0.7 → 37 would-fires, ALL
token-collision FPs on inspection (Mount Kenya pulled into a Kilimanjaro
answer, Dalí into da Vinci, Donovan into Superman). ZERO genuine
recombination errors — the boundary is theoretical-in-practice; the
failure mode is the candidate selector (top-k by token overlap) pulling
different-entity same-subject-area clauses.

(b) Re-ran the grid against the 808-cell pooled STRICT set: the §7 #25
'max@0.96' was itself a small-sample artifact — the n=5 444-cell set
lacked the high-confidence spurious hits the pooled set has. On 808
cells θc goes back to ~0.995, and at θc=0.995 only agg=margin still
catches 28/28 (max gets 27/28). microsoft/deberta-large-mnli / k=3 /
agg=margin / θc=0.995 → 28/28 synthetic recombinations · 0/808 pooled
real STRICT FP · 0/26 synthetic legit — the ONLY config in the
7-model×full-grid sweep that hits 1.0/0.0 on 808 cells, held at n=3
too. recommended_operating_point reverted to margin@0.995.

Realistic next check: ~20-30 hand-built synthetic-recombination-vs-
real-bench-qa-context fixtures (real haystack, deliberate re-attribution).
Still SHADOW; runtime promotion fox+dav1d-decides. Production verifier
unchanged; falsification-hard stays 10/12.

Meta-lesson instance five: a bigger sample can vindicate a config a
smaller one made look unnecessary — re-confirm the config choice (not
just the threshold) each time the denominator grows.
2026-05-12 21:11:35 -04:00
4ec97bdfaf
#000050: add §2a — semantic-allusion fixture set (tracked cases)
Enumerates the concrete query-words-share-zero-tokens-with-target-title
cases the §2 gate's "semantic-allusion fixtures" must include, as a
running list: Orwell→Eastasia (genuine conceptual allusion — the case
that justifies the vec layer), "what is a CPU?"→Central processing
unit, "what is a GPU?"→Graphics processing unit (abbreviation→expansion
subclass — also fixable upstream by a concepts/ synonym edge; bench
records which fix closes each row). Field cases 2026-05-13, fox.
#000053 fixed the verifier's separate acronym blind spot but not this
retrieval gap.
2026-05-12 21:03:35 -04:00
d9760bc5bb
#000049 §7 #25: n=5 confirmation (444 STRICT cells) — verdict settles; the large models are the robust ones, MiniLM-cost-pick overturned
ARBORIST_NLI_SHADOW=1 make bench-qa BENCH_QA_N=5 → 1125 cells, 444 real
STRICT (5x n=1, 1.6x n=3). Re-ran the 7-model mega-grid: the lexical-
candidate NLI veto robustly clears the §7 #12 gate with
microsoft/deberta-large-mnli / k=2 / agg=max / guard=max_entail /
θc≈0.96 / θe=0.9 → 28/28 synthetic recombinations (incl. both fixtures)
· 0/444 real STRICT FP · 0/26 synthetic legit FP, ~4 pts θc headroom;
roberta-large-mnli equally good (k=2/max/θc=0.95). Resolved: agg=max +
max_entail guard is the robust score-shape (§7 #24's margin win was a
sample tie); the large checkpoints (~350-400M deberta-large-mnli /
roberta-large-mnli) hit 1.0/0.0, bart-large (similar size) only ~0.71,
deberta-base at the cliff (27/28 here, 11/28 at n=3), small models
(MiniLM-82M, deberta-v3-small) cap at ~0.82 — so §7 #18's 'MiniLM is
the cost-pick' is OVERTURNED by the proper-n evidence; k=2 consistent
winner; int8-ONNX costs ~1 catch. recommended_operating_point updated.
Remaining: a bench-qa-derived recombination set (the one check not
done); n=9 if dav1d wants more; still SHADOW; runtime promotion is
fox+dav1d-decides. Production verifier unchanged; falsification-hard
stays 10/12. This run is the worked example behind CLAUDE.md's new
bench-maxing line.
2026-05-12 19:42:55 -04:00
221b784a80
#000053: acronym-aware verifier content tokens
`arborist.qa.evidence._content_tokens` dropped every token under 4
chars, so a short all-caps acronym (CPU, GPU, DNA, FBI, USB…) never
registered as a content token — which defeated Rule 8
(_claim_title_overlap / TITLE_MISMATCH), the subject-tokens-absent
check (Rule 9), the bare-name-claim guard, and spotlight-excerpt token
selection whenever a question/claim's topic IS an acronym. The field
case: `what is a CPU?` cited to the "CPU design" article tripped
TITLE_MISMATCH even though claim and title both contain "CPU".

Fix: keep a token if it's an all-caps 2-3-char alpha run in the source
text; everything else unchanged. The change only ever ADDS tokens, so
TITLE_MISMATCH / SUBJECT_TOKENS_ABSENT / BARE_NAME_CLAIM can only stop
firing, never start — monotone toward fewer spurious demotes; no
STRICT→non-STRICT transition is possible from it.

Versioned: `content_token_rules: "v2-acronym-aware"` added to
runner.DEFAULT_POLICY + query.DEFAULT_QUERY_POLICY +
keys._VERIFIER_POLICY_FIELDS → folds into verifier_policy_hash, prior
cache records orphan on lookup (by design; same discipline as
base_version / hyphen_fold_v1). Does NOT touch the retrieval
abbreviation→expansion gap (CPU→Central processing unit — #000050 vec
hybrid / concepts/ synonym edges; the root cause of the satellite
retrieval). 8 new tests; full suite green (2502); bench-qa-smoke clean.
Next ID 000053 -> 000054.
2026-05-12 19:41:47 -04:00
824b1bc21c
#000049 §7 #24: n=3 confirmation — §7 #23 was a small-FP-sample artifact; the no-stone-unturned mega-grid found the config that survives
ARBORIST_NLI_SHADOW=1 make bench-qa BENCH_QA_N=3 → 275 real STRICT cells
(3x the n=1 sample). Re-ran the expanded grid (7 aggregations incl.
margin = max_clause(p_contra - p_entail), paired-entail guard variant,
θc to 0.999, --extra-models) over all manifest models + 4 extra
xsmall→large (microsoft/deberta-large-mnli, roberta-large-mnli,
nli-deberta-v3-small, deberta-v3-xsmall), synth-28 recombination vs the
275 STRICT cells. Result: the §7 #23 deberta-base/k=2/θc=0.99 config
does NOT survive — it catches only 11/28 at θc=0.995 (which the larger
STRICT sample forces). BUT the broader sweep found the config that does:
microsoft/deberta-large-mnli / k=3 / agg=margin / θc=0.995 → 28/28
synthetic recombinations (incl. both fixtures) + 8/12 falsification-hard,
0/275 real STRICT FP, 0/26 synthetic legit FP — a passing config at
proper n. Findings: margin is the right score-shape (single threshold,
folds the guard in); the specific checkpoint matters more than param
count (deberta-large-mnli wins clean, deberta-base collapses,
roberta/bart ~0.71-0.75 — no 'bigger is better' law). recommended_operating_point
updated. Still SHADOW; runtime promotion needs a bigger STRICT sample +
a bigger recombination set + fox/dav1d sign-off. Production verifier
unchanged; falsification-hard stays 10/12.

Meta-lesson sharpened twice: clean eval ≠ bench-qa precision (§7 #18→#20),
default config ≠ best config (§7 #22→#23), small FP sample ≠ large FP
rate (§7 #23→#24).
2026-05-12 18:38:43 -04:00
421b2c5fd5
#000049 §7 #23: grid sweep flips the verdict — the lexical-candidate NLI veto PASSES the gate
The §7 #22 'fails the gate' was the verdict for the DEFAULT config
(k=6/θc=0.5/θe=0.9, tuned on the clean synthetic set), not the
approach. A {model × candidate-cap k × aggregation × θc × θe} grid
sweep (bench/scripts/nli_shadow_grid.py — NLI runs once per
(model,record) over the top-12 candidate clauses, the k/agg/θ grid is
then arithmetic on cached scores; ~10s on the 4090 for 4 models) finds
clean passing configs: on the 89 real STRICT cells (n=1 bench-qa),
deberta-base-184M / k=2 / agg=max / θc=0.99 / θe=0.9 → 27/28 synthetic
recombinations caught (incl. both 5f-fal-hard fixtures), 0/89 STRICT
FP. MiniLM-82M passes too (24/28 · 0/89). Model science: 184M > 82M >
407M for fp=0 recombination recall; int8-ONNX costs ~1 catch vs fp32.

Caveats: FP side is n=1 (BENCH_QA_N=3 run in flight); recall is on the
synthetic set; flipping to a runtime demotion-only veto is fox-decides
(then nli_policy_hash folds into governance_policy_hash per §7 #2).
Manifest active defaults stay k=6/θc=0.5; recommended_operating_point
(deberta-base, k=2, agg=max, θc=0.99, θe=0.9) documented in the
manifest. 3 grid result JSONs committed. Standing lesson: neither the
clean synthetic eval NOR the default config predicts bench-qa precision
— you have to sweep. Production verifier unchanged; falsification-hard
stays 10/12.
2026-05-12 18:12:36 -04:00
68c6665db9
#000049 §7 #22: make bootstrap-nli-only (lean GPU/CPU NLI compute-node setup) + GPU benchmark
bootstrap-nli-only: a venv + [nli] only — no [dev] extras (no crawler/
hessian/vec/sympy). On a CUDA host PyPI's torch wheel is the CUDA build,
so ShadowNLI auto-detects cuda and bench-nli-shadow / export-nli-onnx /
the candidate bench all run on the GPU with no further wiring. Verified
on the ai box (RTX 4090): torch 2.11+cu130, cuda True; 82M cross-encoder
batched ≈ 0.09 ms/pair (512 pairs in 0.047s — ~350x onnx-int8-cpu,
~1300x torch-cpu-batch1); 62-record synthetic shadow sweep in 2.4s wall;
24/24 tests pass. The GPU only accelerates the NLI half — make bench-qa
(Hermes LLM) still runs wherever the shard corpus is.
2026-05-12 17:55:54 -04:00
87d9db15c7
#000049 §7 #22: speedup (batch + cuda auto-detect + ONNX-int8 export) + the gate-item-4 verdict at proper n
Speedup (§3 plan): ShadowNLI._nli_batch batches forwards
(ARBORIST_NLI_BATCH=64); device auto-detect (ARBORIST_NLI_DEVICE, else
cuda-if-available); auto-prefer an ONNX export — bench/scripts/export_nli_onnx.py
/ make export-nli-onnx exports + int8-dynamic-quantizes the pinned
checkpoint into ~/.arborist/models/nli/<ver>/onnx/ (operator state, NOT
committed), _ensure_loaded loads model_quantized.onnx via
optimum.onnxruntime (backend onnx-int8), falls back to torch silently.
torch-cpu-batch1 ~120ms/pair → onnx-int8-cpu-batched ~32ms/pair (~4x);
seconds on a 4090. optimum[onnxruntime] added to the [nli] extra; 24
tests.

Gate-item-4 verdict at proper n: ARBORIST_NLI_SHADOW=1 make bench-qa
BENCH_QA_N=1 → 223 cells (89 STRICT / 90 HYBRID / 44 UNGROUNDED; also
surfaced + fixed a lone-surrogate bug). Shadow sweep over those: NLI-as-
runtime-veto on STRICT has ~26% FP at θc 0.5, ~8% at θc 0.90, ~0% only
at θc 0.99 — and θc 0.99 gives up most recombination recall (hard
synthetic recombinations bottom out ~0.76). FAILS the §7 #12 gate on
this design. Only untried path that might pass: a Phase-3 runtime hook
running NLI on the verifier's actual matched clauses (1-3), not
top-6-by-overlap. Until then: runtime NLI demotion stays off; the 2
fixtures stay permanent boundary markers; θc stays 0.5. Production
verifier unchanged; falsification-hard stays 10/12.
2026-05-12 17:21:32 -04:00
96ff586da1
#000052 §3.1: diagnose_coherence — lexical answer-shape sidecar
Per-sentence shape check (no model) emitting kind ∈
{phrase_component_reuse, circular, vacuous, ok, empty}:
  - circular: subject content-tokens ⊆ predicate's and the predicate
    leads with a subject token ("Water is water").
  - phrase_component_reuse: subject quotes a phrase, predicate reuses
    one of that phrase's own tokens as a bare "the/a/an <token>"
    referent — the 2026-05-12 field case ("the phrase 'Zionist entity'
    is used as the entity"), a token collision the verifier +
    deflection + title-relevance all pass and NLI returns neutral on.
    Copulas inside a quoted span are skipped so 'war is peace' doesn't
    break the subject/predicate split.
  - vacuous: predicate is only placeholder hypernyms + filler ("X is
    a thing").

Conservative — no full token-salad parsing; legit definitions pass ok.
Surfaced in inspect_cache_key + the `arborist inspect` human view
(· incoherent: <kind>). Advisory only — never writes providence_cache
/ audit_events / run_dag_root; demote-only verifier hook deliberately
not wired. 9 tests; full suite green (2500 passed).
2026-05-12 17:19:07 -04:00
f955082ebe
#000049: fix loose 'real traffic' wording → 'bench-qa traffic' (defined in §7 #20: arborist's own query pipeline driven by the curated bench question set, not live users) 2026-05-12 16:54:28 -04:00
59d8a17a14
#000052: open — relevance + coherence meta-cognition (answer-shape sidecars)
Doc-only scaffold. Two more read-only/demote-only/never-in-proof-path
sidecars joining the diagnose_deflection family: (1) diagnose_coherence
— word-salad/circular/vacuous answers; lexical, no model; the near-term
win. (2) diagnose_relevance — semantic 'aboutness' (does the answer
address the question / is each claim about its cited source?); today's
checks are lexical and a token collision defeats them; a small
aboutness/reranker model (NOT NLI) under #000049 §7's discipline cage
verbatim; gated on evidence, travels with #000049's model question.
Motivating field case: the 'Zionist entity' claim_lattice query —
incoherent token-collision recombination NLI can't catch (returns
neutral) and both lexical relevance checks waved through. Flags an
upstream retrieval (polysemy/title-soup) root-cause ticket, not scoped
here. Next ID 000052 → 000053. #000049 sibling
2026-05-12 14:49:10 -04:00
02f8dfec07
#000049 §7 #21: candidate-clause restriction in ShadowNLI.check — helps, doesn't close it
candidate_clauses() — NLI now runs only on the top-N source clauses by
content-token overlap with the answer claim (max_candidate_clauses=6),
not the whole context; records n_candidate_clauses / best_clause_overlap
/ recombination_risk. Synthetic sweep unchanged (28/28 recombination,
0/26 legit FP, mean 1.45 candidate clauses/record). Real-traffic smoke
re-run: STRICT would-demote 30% → 20%, overall 47% → 33% — better, not
fixed; recombination-risk split doesn't separate either. Residual STRICT
false-contras at ~0.83-0.92 → θc would need ≈ 0.90 (vs the clean-set
0.5); at θc=0.90 the data in hand gives 27/28 synthetic recall, 0/26
legit FP, 0/10 smoke STRICT FP — but n=10 is too small to set on.
Next: a fuller ARBORIST_NLI_SHADOW=1 bench-qa run → sweep θc on hundreds
of STRICT cells → confirm → set it. θc stays 0.5; runtime NLI demotion
stays off. Production verifier unchanged; falsification-hard stays 10/12.
2026-05-12 14:34:44 -04:00
f4de936ff9
#000049 §7 #20: first real-traffic NLI shadow sweep — the haystack problem
Live hook: ARBORIST_NLI_SHADOW=1 makes query() surface the verifier-input
text (gated off-by-default, never a cache_key/governance/audit_mode
input); qa_sweep.py carries it + the answer into bench rows; the shadow
sweep reads them and buckets by audit_mode. ARBORIST_NLI_SHADOW=1 make
bench-qa-smoke (15 cells) → the naive 'NLI on every context clause'
scaffold has a ~30% would-demote rate on STRICT answers — a haystack /
multiple-comparisons artifact (real contexts segment into 100-336
clauses; max-over-all almost always finds a tangential clause the model
reads as contradicting; a paraphrased STRICT answer often isn't verbatim-
entailed by any single clause so the entailment guard doesn't rescue it).
Lesson: the §7 #5 'candidate source clauses' + recombination-risk gating
is load-bearing, not optional. Do NOT enable runtime NLI demotion on the
current scaffold; next step is the candidate-clause restriction, then
re-run, then gate item 4 is meaningful. Production verifier unchanged;
falsification-hard stays 10/12.
2026-05-12 14:28:44 -04:00
70ecda3d6c
#000049 Phase 2: NLI shadow scaffold in arborist (§7 #19)
arborist/qa/nli/ — SHADOW ONLY (never an audit_mode input; manifest not
yet in governance_policy_hash per §7 #2). manifest.json pins
cross-encoder/nli-MiniLM2-L6-H768 @ a fixed HF revision + the
bench-validated θc 0.5/θe 0.9 + 2 alternates + the Phase-3 TODO;
shadow.py = ShadowNLI/shadow_check (lazy transformers+torch behind a new
[nli] extra, clauses() segmenter, the §7 #5 clause-level Demote()
decision, degrades to available=False when [nli] absent);
bench/scripts/nli_shadow_sweep.py + make bootstrap-nli / bench-nli-shadow
(the gate-item-4 instrument); 16 tests.

First sweep (116 records — 5f-falsification packs + the arborist-nli-bench
eval sets): 28/28 synth recombination demoted, 0/26 FP on legit summaries,
0/9 fires on already-STRICT_SPAN records, 25/50 on UNGROUNDED (the
contradiction half; quiet on non-sequiturs). Gate items 1/2/3/5/6 clear
on available data; item 4 — shadow FP rate on a real live-bench-qa
sample — remains the open measurement. Production verifier unchanged;
falsification-hard stays 10/12.
2026-05-12 14:14:21 -04:00
87c92162a1
#000049 §7 #18: harder-set 5-candidate NLI bench — 28+26 cases; the two-threshold rule is load-bearing (entailment guard filters spurious competing-superlative contradictions, 0% guarded FP vs ~4% single-threshold); MiniLM-82M cost-pick 2026-05-12 14:04:41 -04:00
23e934aa55
#000049: Phase-2 candidate-NLI bench — first run (§7 #18); both candidates 18/18 catch, 0/18 FP on synthetic set; harness in ~/git/arborist-nli-bench 2026-05-12 13:57:54 -04:00
57bb26ba4e
#000049: incorporate de novo review (2026-05-13) — shadow-path approved, governance-hash correction, demotion-only rule, NLI manifest fields, nli_pair@v1, bench gate, roadmap 2026-05-12 13:06:42 -04:00
7ff37f8d70
docs: fold 2026-05-13 Dav1d review amendments into #000050 + #000051
#000051 §6a: vecpack manifest + entry_root (transit integrity, not
embedding-correctness proof); vec_backend_version must commit the full
reproducible input (model/tokenizer revisions, preprocessing/pooling/
normalization policies, named quant recipe); trust tiers 0-3 (untrusted
OK for raw search, cached hybrid QA needs Tier 2+ and #000050 wiring);
streaming/resumable/bounded-memory import + disk budget; bad-row
thresholds + duplicate policy; exception matrix; soft audit events;
extra CLI (inspect/verify/--dry-run/--replace/--trust-policy); SQD
canonical-bytes discipline now, pi* module later; 15 test additions.

#000050 §5a: governance_policy_hash must cover the fusion policy
(retrieval_backend, vec_top_k, rrf_k, route set, accept_path_version,
fallback/coverage policy, candidate budget) not just the 6 vec fields;
RRF must survive the post-merge rerank (Option A: RRF score is one
bounded feature in the existing reranker) + deterministic tie-break;
split accept-path-5 into 5a warranted-survival vs 5b exploratory-
UNGROUNDED-survival (5b hard-excluded from verified-evidence counting);
mixed-fleet vec_coverage metadata + bench-validity rule; exact bench
denominators + row schema + good-label-by-mode; consume #000051
metadata in run-DAG; implementation order (governance+cache-guard
before RRF code can persist); 12 test additions.
2026-05-12 12:57:39 -04:00
e391f1f01c
#000049: expand — where would the NLI weights live? (§2.4 provenance & distribution)
fox asked: JIT-trained, gossip-pulled, or repo-embedded?

Added §2.4 — three shapes, two dead ends:
- JIT-trained per deployment:  — GPU-hours over MNLI/SNLI/ANLI, not
  a per-deployment step; non-deterministic across runs → different
  audit_mode → breaks the verifier's reproducibility invariant.
  "Training" is a one-time act by someone; the distributed thing is
  the resulting fixed blob, not the recipe.
- Embedded in the git repo as data:  — a few-hundred-MB binary in
  .git blows the standing "fresh clone = python3.12 + venv + sqlite3"
  invariant; Git LFS adds a dep and still bloats; the repo is source
  + tiny fixtures + docs, not a model registry.
- One-time obtained, content-addressed, fetched on demand, mesh-
  distributable: ✓ — the repo carries a tiny manifest
  (arborist/qa/nli/manifest.json: {checkpoint_sha256, source_url,
  license, nli_model_version}); the weights live under
  ~/.arborist/models/nli/<hash>/, fetched on first use (make
  fetch-nli or auto-fetch on first --enable-nli query) with the
  sha256 verified fail-closed against the manifest; nli_model_version
  folds into governance_policy_hash (a swap stales the cache, like
  chunking_version / canonicalization_version), keeping audit_mode a
  deterministic function of (answer, source, policy, pinned hash);
  and once arborist's mesh grows blob-sync, a deployment with peers
  pulls the checkpoint from a peer (AXFR-style, like ClouDNS slaves
  pulling a zone, like a shard rehydrating from snapshot.db) instead
  of the origin URL — content-addressing makes peer-pull and
  origin-pull interchangeable, the mesh is the optimization not the
  canonical source, cold start falls back to origin. Source: a
  published off-the-shelf NLI checkpoint (MIT/Apache, recorded) or a
  one-time fox/blackops-trained-and-published one.

Bottom line: not JIT-trained, not repo-embedded weights — a
content-addressed hash-pinned checkpoint, manifest in the repo,
weights under ~/.arborist/, fetched on demand (origin or peer), hash
in governance_policy_hash. Precedents cited: the textbook manifest
(pointers + licenses not texts), the [vec] extra (fastembed's
bge-small fetched not committed — #000039), ~/.arborist/ operator-
state, docs/mesh.md + snapshot rehydrate. All presupposes the §2.2/§5
discipline call came back "yes" (is a fixed NLI model allowed in the
audit_mode path?); if "no", none of it builds. Also wired §2.2 con
(b)/(c), §3, §5, §6 to point at §2.4. Doc-only.
2026-05-12 12:36:09 -04:00
0d55fea3a6
docs: #000051 — add GPU-producer fast path (CUDA Embedder, minutes not days)
bge-small-en-v1.5 batched on a 4090 ≈ 10^3-10^4 chunks/s → full
6.24M-chunk corpus in minutes. Drop a CUDA Embedder (fastembed
CUDAExecutionProvider, or sentence-transformers device=cuda) into
default_embedder()'s pluggable callable; int8 quant stays CPU-side
post-embed; CUDA stack lives only on the producer box. Determinism
note: GPU backfill isn't byte-identical to CPU — irrelevant, soft
data, pin model revision + recipe not output bytes.
2026-05-12 12:18:27 -04:00
07b8ceb638
docs: open #000051 (federated vecpack distribution) + expand #000050 Phase-2 scope
#000051: gossip the embedding backfill over mesh — backfill once on any
CPU box, publish a vecpack (leaf_hash-keyed, soft data, cheap structural
gate, never proof path), peers pull + bulk-load. The laptop never runs
the transformer; this is the mechanism behind whitepaper §1's "the
embedding pass runs off the device". Supplies #000050's backfill prereq
as a distributable artifact.

#000050: fold the Dav1dPrometheus-review high-value items into Phase-2
scope — accept-path-5 (vec hits clear the title gate via span-level
warrant, not similarity score, so the gate doesn't drop the semantic
candidates vec exists for), six vec config fields into
governance_policy_hash + a cache-write guard until wired, run-DAG
records the vec stage, four-condition bench (A/B/C/D, C-beats-D) on
semantic-allusion + curated + adversarial-semantic-neighbor fixtures.
Backfill prereq now routes through #000051.

Next ID 000051 -> 000052.
2026-05-12 12:17:04 -04:00
b5da0473a1
docs/#000012: refresh the header status line — Phase 1c landed (was stale)
The #000012 top-of-file Status line still said "Phase 1c (branch-set
persistence) remains proposed-not-opened" — but Phase 1c landed
2026-05-10 (d53115e: fork_score_branches table + persist_branch_score
/ branch_set_density + the default-off CLI flags), the #000037 §12
Trigger 1 probe was wired to it 2026-05-11 (dbe8249), and the ticket's
own §7 Phase 1c section + the TICKETS.md index row already say
"landed". Only the header was stale.

Refreshed: Phase 1c landed (with the probe wire — measurable, not yet
fired); §8 = the ForkScore threshold-calibration handoff from #000025
§10.14 (delta_aggregator knob #000047; harder-fixture-tier line
#000046 closed / #000048 closed / #000049 open); Phase 2 (the v8
multi-validator consensus implementation) noted as gating on a
multi-validator deployment, like #000045. Doc-only.
2026-05-12 11:47:04 -04:00
eba4c3a545
#000006 — +30 emergent cycles (2026-05-12); verifier-ladder health re-confirmed
make bench-emergent EMERGENT_N=30 — 30 fresh 3-word-triangulation
cycles appended to bench/emergent_log.jsonl.

Aggregate: 29/30 UNGROUNDED, 1/30 HYBRID, 0 STRICT — the expected
healthy null result. The triangulator generates absurd questions
("How does the depth of one's music-making abilities on a kazoo …")
with no real corpus support; the verifier ladder honestly returns
UNGROUNDED rather than hallucinating-then-STRICTing. 0 false-positive
STRICT on garbage input.

The one HYBRID (perversely/succeeds/disagreeably) is a re-run of
failure shape E ("total deflection to unrelated trivia"): the common
words pulled Hirabah / Original-righteousness chunks via FTS5; the
model quoted them verbatim (3/4 claims verify) but the answer is
total topic-drift → DEFLECTION_DETECTED + CITATION_MISMATCH → capped
at HYBRID, not STRICT. The deflection sidecar + verbatim verifier
holding on adversarial-by-construction input — nothing new, logged as
a confirmation.

No new failure shape or correctness concern. #000006 amend records
it; the 30 entries join the --print-pending queue if a future
teacher-review pass wants a closer look. Doc + log only.
2026-05-12 11:28:57 -04:00
1d4d7c549c
docs: lexical-first-rationale.md — why the cheap retrieval path is the default
Capture the positioning fox articulated: arborist's per-document ingest
is ~10-100x cheaper than building a vector-DB representation — same
SQLite substrate, different retrieval philosophy — which is the
difference between "ingest + search runs on a phone" and "the NPU is
now a hand-warmer."

New docs/lexical-first-rationale.md (positioning/architecture
reference, not a ticket): the cost asymmetry with the measured numbers
(FTS5 + SHA-256 leaf + Merkle commit + sqlite + zstd pipeline << 1 ms/
chunk vs bge-small ONNX inference ~5-30 ms/chunk, worse contended; the
query side too — a vec query embeds the query string first, an FTS5
query is B-tree lookups); the same-SQLite-different-philosophy table
(inverted index vs dense vectors + ANN; build cost; query cost;
matching; proof-bearing); the deep version of the point — arborist IS
the Merkle Providence model and that model is cheap by construction,
embeddings are a soft signal (CLAUDE.md "soft hash vs hard hash") that
never enter a proof and are the expensive bolt-on; the edge/mobile
consequence; the honest caveat (lexical-first trades the semantic
allusion gap — which is why vec is opt-in/additive, never the default,
and the embed pass is lazy/out-of-band so the heavy transformer work
runs off-device/off-peak; int8 keeps the storage tax at +6%).

Wired in: TICKETS.md "Distinction from other docs" reference list gains
the doc; #000039 §14.6 gains a "Strategic framing" pointer to it.

(A possible follow-up: fold the mobile-viability argument into the
Merkle Providence Reverse RAG whitepaper proper — noted in the doc's
references; not done here, that's a deliberate cross-repo paper edit.)

Doc-only.
2026-05-12 09:23:50 -04:00
906606072d
ticket #000039: close — Phase 0 + Phase 1 landed; Phase 2 split to #000050
#000039 (the optional sqlite-vec retrieval backend) closed 2026-05-12.
Shipped: Phase 0 doc + Phase 1 — arborist/search/vec.py (VecBackend,
chunk_vecs vec0 + vec_meta sibling tables, embed_documents
incremental/--rebuild, pluggable Embedder w/ fastembed bge-small-en-v1.5
default), CLI (arborist embed [--limit/--batch-size/--quant/--rebuild]
+ search --backend vec + ingest --embed eager opt-in), [vec] extra,
--quant {float32,int8} with the int8 head-to-head (3.8-4x smaller,
recall ~= float32 — int8 is the production config), ingest integration
+ idempotency (§14), embed-throughput measurement (§14.6 — ~4 chunks/s
contended, ~2.4 GB int8 full-corpus, full backfill abandoned as a
days-long batch job, non-vec ingest unchanged), 16 vec tests.
Demonstrated on crawl_appliedcombinatorics_org.db + a 54K-chunk partial
on wiki shard 000. UNGROUNDED hits, never proof path; vec config folds
into governance_policy_hash (noted in Phase 1, wired in Phase 2).

Phase 2 (RRF hybrid fusion in query.py — wire VecBackend as a 5th
retrieval route alongside the 4 FTS5 routes) → new ticket #000050,
gated on (a) a corpus backfill and (b) a recall bench clearing the
5pp floor. New doc-only scaffold docs/tickets/ticket-000050-vec-rrf-
hybrid-fusion.md (the design already lives in #000039 §4.2 + §8;
#000050 is the tracked continuation). Next ID 000050 -> 000051.
TICKETS.md: #000039 row -> closed, #000050 row added.

(Working tree also has parallel-clone work — ticket-000048-*.md
modified, ticket-000049-*.md untracked — not touched here.)
2026-05-12 08:33:45 -04:00
20f6061f83
#000048 closed; #000049 opened — the attribution-aware verifier is its own ticket
fox 2026-05-12: the attribution-aware path (#000048's deferred §2.3 —
closing the 2 recombination over-grounds in falsification-hard) is its
own ticket, not a #000048 phase. So:

#000048 → closed (at 2.1 + 2.4). Steps 2.1 + 2.4 landed 2026-05-11
(12 of 16 residual items: 4 HYBRID_ENTITY over-grounds + 8 Formulate
mis-segments → formulate-hard 12/12, falsification-hard 10/12; each
bench-gated, no STRICT-rate regression). Step 2.2 (single-clause-
containment paraphrase check) attempted + reverted — recombination-
vs-summary isn't lexical (§5 "What we learned"). The 2 residual
falsification-hard fixtures (hard-003 Mercury, hard-005 Einstein)
stand as a documented marker of where the lexical verifier stops.
Header + §5 Closure + §2.3 updated; cross-refs in #000046 / #000012
§8 / TICKETS.md repointed from "#000048 §2.3" to "#000049".

#000049 opened (doc-only, awaiting go/no-go) — "Attribution-aware
grounding check (the recombination boundary)". The recombination
class needs an attribution / dependency-parse or mini-NLI check
(distinguishing "Mercury is the largest" against "Jupiter is the
largest; Mercury is the smallest" from a legit cross-sentence
summary). Options: 2.1 hand-rolled dependency-attribution heuristic
(no model, brittle — same threshold-can't-separate problem one rung
up); 2.2 small purpose-built NLI model ([nli] extra, policy-gated,
off-by-default, bench-gated — the right capability, but forces the
"is a fixed NLI model an LLM-judge?" discipline call + a model
dependency + a non-determinism surface to pin); 2.3 do nothing (the
2 fixtures are a boundary marker, no observed real-traffic harm).
Recommends 2.3 until real-traffic recombination over-grounds show up,
then 2.2 *if* fox rules a fixed NLI model is acceptable in the
proof-adjacent path; the first decision the ticket needs is that
discipline question. Next ID 000049 → 000050. #000048 follow-up.
Doc-only — no code change.
2026-05-12 08:31:57 -04:00
2ad2dceada
ticket #000039: record embed-throughput measurement + ingest-stays-fast rationale (§14.6)
New §14.6 captures the 2026-05-11 findings:

- Measured embed rate: ~4.3 chunks/s on the contended dev box (load
  ~11 on 8 cores; the embed process got ~28% of one core). One wiki
  shard (~1.56M chunks) at that rate ≈ 100h ≈ 4+ days; all four ≈
  ~16 days. The full int8 backfill was abandoned as not feasible to
  brute-force there.
- The 54K-chunk partial on 000.db confirmed ~409 B/chunk apparent
  → 384 B amortized → ~2.4 GB for the full 6.24M-chunk corpus at
  int8 — the deterministic number a full backfill would only
  re-confirm, so finishing it bought nothing.
- On an idle healthy box (batching + all cores) bge-small does
  ~50-200 chunks/s → full corpus ≈ ~9-35h (the ticket's earlier
  "~17h" is the optimistic end).
- Per-chunk cost breakdown: bge-small ONNX inference ~5-30 ms/chunk
  dominates; the existing arborist ingest steps (chunker + SHA-256
  leaf + Merkle commit + sqlite INSERTs + zstd + FTS5) are well
  under 1 ms total. So adding vec multiplies ingest by ~10-100×,
  entirely in the ONNX matmuls — the non-vec ingest path is
  unchanged and still runs at hundreds of chunks/s.
- Implication for §14.2: this is *why* lazy-out-of-band is the
  default and `arborist ingest --embed` is the opt-in. Production
  guidance: a corpus-wide backfill is a one-time batch job (hours
  on idle / days on contended), best run off-peak or on a dedicated
  box; it does not slow ongoing ingest (which never embeds unless
  --embed is passed); a GPU/accelerated embedder is a drop-in via
  the pluggable Embedder callable if backfill latency matters.

Status line updated to point at §14.6. Doc-only.
2026-05-12 07:14:12 -04:00
5428b3b1d6
#000048 — fold the step-2.2 finding through the ticket + the cross-refs
What we learned from the (reverted) step-2.2 attempt, stated as a
general principle in #000048 §5 "What we learned":

  A recombination ("Mercury is the largest planet …" reusing the
  source's "largest planet …" with its "Mercury") and a legitimate
  cross-sentence summary ("Batman, who is the alias of Bruce Wayne,
  lives in Gotham City." reusing two adjacent source sentences) are
  the same SHAPE to any lexical signal — both scatter the answer's
  content tokens across source clauses, and the recombination's
  best-single-clause coverage (4/5 = 0.8) sits ABOVE the legit
  summary's (4/6 = 0.67), so no token-coverage / clause-containment /
  bigram threshold separates them in the safe direction. The
  discriminating thing is *attribution* — in the source, are these
  tokens attached to the same subject/predicate the answer attaches
  them to? — which is a dependency / NLI question, not a string
  metric. That's the boundary of the deterministic, no-LLM-judge
  lexical verifier: absence signals (#000046 numeric gate, #000048
  step 2.1 entity gate) and structure-of-the-model's-own-output
  signals (step 2.4 segmenter) are lexical and work; "the source
  contradicts this pairing" is not, and proxying it with a coverage
  cut trades a small contrived-fixture win for honest demotions of
  real summaries — a net loss against bench-maxing's 5-pp floor.

Updated: #000048 §2.2 (the attempted idea kept as design log + the
no-threshold-separates finding), §2.3 (now framed as the only path to
the last 2 — attribution / mini-NLI, its own ticket if ever), §3
(original plan annotated with the LANDED / ATTEMPTED+REVERTED / NOT
DONE outcome), §5 (the step-2.2 receipt + the "What we learned"
subsection + the closure recommendation). Stale cross-refs fixed:
TICKETS.md #000048 + #000046 rows, #000046 ticket Headroom section,
#000012 §8 #4 — all of which said "#000048 step 2.2 closes the last
2", now corrected to "step 2.2 attempted + reverted; the 2 recombination
fixtures stand as documented residue; #000048 §2.3 is the path if
ever wanted".

Recommendation unchanged: close #000048 at 2.1+2.4 (12 of 16 residual
items closed — formulate-hard 12/12, falsification-hard 10/12). Doc-
only — no code change.
2026-05-11 17:34:18 -04:00
f6ac72270c
#000048 step 2.2 — attempted, reverted (not feasible as a conservative lexical change)
Tried a single-clause-containment check on the paraphrase path (and
the entity path's weakest slot): a span is grounded only if a single
source clause (;/. -delimited) covers >= paraphrase_coverage of its
content tokens — a recombination spreads them across clauses. On the
contrived fixtures it works (hard-003 Mercury, hard-005 Einstein →
UNGROUNDED → falsification-hard 10/12 → 12/12). But it ALSO rejects
legitimate cross-sentence summaries — the established fox-2026-04-29
Batman case ("Batman, who is the alias of Bruce Wayne, lives in
Gotham City." against "Batman is the alias of Bruce Wayne. Batman
lives in Gotham City.": spans two clauses, best clause covers 4/6 =
0.67 → demoted, but it's a correct paraphrase). And there's no
threshold that separates the two directions — the recombination
("Mercury …": best clause covers 4/5 = 0.8) sits ABOVE the legit
summary's 0.67, so any cut that rejects Mercury also rejects Batman.
Distinguishing "recombined into a different statement" from
"summarized two adjacent sentences" needs attribution / dependency
parsing or a mini-NLI model (the §2.3 territory), not a conservative
lexical proxy.

Reverted — verify.py stays at its post-step-2.4 state; falsification-
hard stays at 10/12 with hard-003 + hard-005 as documented residue.
#000048 §5 records the attempt + the no-threshold-separates argument;
recommendation: close #000048 at 2.1+2.4 (12 of 16 residual items
closed), with the 2 recombination fixtures a marker for a future
attribution-aware verifier (its own ticket). Awaiting fox's call.
Doc-only — no code change in this commit.
2026-05-11 17:27:43 -04:00
1908fba162
docs/#000018 §9.2: mark resolved — φ_PRG = HMAC-SHA-512 (#000035 closed)
#000035 closed 2026-05-11 (commit 4b85eb1: v7 substrate spec into the
repo at docs/_source/merkle-agi-dag-v7.rst, § 9.10 folded in). Update
soft-hash-channel-analysis.md §9 open-question 2 from "Phase 2 lands
when v7 gains a deployment target" to resolved: φ_PRG = HMAC-SHA-512
with a 32-byte committed seed, little-endian.
2026-05-11 17:20:48 -04:00
7bb11ed62f
#000048 step 2.4 — parse_pointer_claims clause segmentation
Closes the 8 mis-segments #000046 left in formulate-hard-v1.jsonl.
The parser was line/bullet-only — one line ⇒ one claim — so a line
that crammed several pointered claims onto one row ("Water is wet
[E1]; fire is hot [E2]", "X happened [E1]. Y followed [E2]") became
one monolithic claim with all the pointers, and a wrapped bullet
became two.

arborist/qa/parse_claims.py: _SEGMENT_SEP_RE splits a line on ';',
sentence boundaries ('. '/'! '/'? ' then a Capital), spaced dashes
(' - '/' — '/' – '), ' and '/' or '/' because '/' although '/' since
'/' while ', inline '(N)' enumeration markers, and commas — with
'(?![^\[]*\])' so a comma inside a [E1, E2] bracket never splits it.
_segment_line keeps the split ONLY IF every resulting non-empty
segment is a well-pointered claim — a legit single claim ("The cat
is black and white [E1].", "The cast: A, B, C [E1].") is never
broken because splitting it would manufacture pointer-less prose
fragments → guard rejects; a leading colon-terminated header with no
pointer ("Two facts:", "Key points:") is allowed and dropped. Plus a
wrapped-bullet join: a continuation line (leading whitespace then a
lowercase letter, no bullet glyph) folds its text + pointers into the
previous claim.

Effect: formulate-hard rate 4/12 → 12/12 (the pack is now at ceiling
— a harder Formulate tier would re-open below-ceiling headroom; a
#000046 follow-up). Remaining #000048 headroom: 2 STRICT_PARAPHRASE
recombinations in falsification-hard (Mercury, Einstein — step 2.2).

Bench gate: make bench-qa (n=3 × 75 × 3 = 675 cells; parse_pointer_claims
feeds the 450 claim_lattice_pointer + claim_lattice cells) after
(bench/qa_results/2026-05-11T20-26-37Z) vs the pre-step-2.4 baseline
(...T17-12-41Z = HEAD's parse_claims.py). STRICT-rate quote 0.54→0.55,
pointer 0.22→0.22, lattice 0.43→0.45 — all within the 5-pp noise
floor. Per-row diff: the segmenter changed the parsed-claim count on
the SAME answer text for 7 of the 450 lattice cells (0 in
claim_lattice, 7 in claim_lattice_pointer); of those, 2 caused an
audit_mode change — both correct: a wrap-join recovered an answer's
intended structure (4 claims, 2 pointer-less wrap-fragments → HYBRID)
into 2 well-pointered claims → STRICT; and a crammed-one-line blob (1
monolithic claim, all pointers → STRICT) split into 8 claims, some
not individually verifying → HYBRID (the honest verdict — false-
positive STRICT was the corruption). Every other lattice/quote delta
is LLM re-answer variance. No regression — the segmenter's only
visible effects on real traffic are honest improvements. Summarized
in qa-modes-bench.md Addendum 7 + ticket-000048 §5 step 2.4.

Tests: 8 new in test_claim_lattice.py (semicolon/sentence/conjunction
splits; pointerless-fragment + cast-list guards; leading-colon-header
drop; wrapped-bullet join; pointer-order/multi-pointer); existing
parse_pointer_claims tests pass untouched; test_5f_formulate_hard_pack
re-pinned 4/12 → 12/12. make test 2358 passed, 28 skipped.

#000048 → steps 2.1 + 2.4 landed; #000046 / #000012 §8 / TICKETS.md /
Makefile / fixture _meta + notes updated.
2026-05-11 17:09:06 -04:00
4b85eb1fcf
#000035 closed — v7 substrate spec into the repo; § 9.10 folded in
Brought the Merkle-AGI v7 formal substrate spec into the repo as
docs/_source/merkle-agi-dag-v7.rst (previously referenced only as the
un-version-controlled ~/Downloads/merkle-agi-dag_v7.txt). Section
structure converted to reStructuredText; inline math kept in the
source's literal notation; added to the docs/_source/index.rst
"Substrate" toctree (also added the pre-existing merkle-agi-v8-consensus
entry that was missing from it).

Folded ticket #000035's § 9.10 + § 9.10.1 (anchor PRG map φ_PRG;
dav1d-reviewed-final, little-endian, HMAC-SHA-512 / 32-byte seed) in at
their numbered positions, after § 9.9, with a .. note:: citing the
reference implementation (arborist/substrate/anchor_prg.py). #000035 ->
closed (Phase 1 + Phase 2 both landed); #000018 §9.2 ("which PRG?")
resolves to HMAC-SHA-512 with a 32-byte committed seed. Full upstream
v7 spec revision stays exogenous; this lands the amendment into the
tracked in-repo copy where future amendments also go.

(docs/TICKETS.md also carries the in-flight #000048 index-row update
from a concurrent session.)
2026-05-11 17:06:19 -04:00