Commit graph

158 commits

Author SHA1 Message Date
cb9b57eb80
#000070: rewrite ticket as directive forward-spec (Joseph6 as worked example)
Per fox 2026-06-01: same treatment as #000071 — replace the
review-archaeology structure with what we SHOULD grow. Ticket goes
from 978 lines (original Anchor6 §§1-8 design log + dav1d-review §0
retrofit) to 498 lines of directive spec. **Joseph6 stays as the
first registered example grammar** per fox's note — concrete enough
that an implementer sees what a WorldDimensionGrammar looks like
end-to-end, not abstract enough to lose its load-bearing role.

What changed in shape:
  Before: §0 dav1d verdict retrofit + §§1-8 archaeology of the
          original Anchor6 spec being reviewed (validate seed source,
          segmentation method, mapper choice — all decisions long
          since made).
  After:  §1-13 forward spec. Goal · Axis split · Hard constraints
          (all phases) · AnchorN primitive · WorldDimensionGrammar ·
          Quantization mappers (with uint256-H₁ + no-SO(3) corrections
          documented inline) · π*_w_object canonicalizer with
          four-identity-hash record · **Joseph6 as worked example** ·
          Phase 1 deliverables (9 items) · Pre-review empirical
          bench preserved as §7 · Phase 2/3 deferred · Open questions
          (3 remaining; 5 closed by bench, 4 by dav1d's review) ·
          Cross-references · Five-step alignment · One-line review
          history at the bottom.

What changed in content: nothing material. The corrected spec from
the prior §0 retrofit IS the body now. The original Anchor6 design
log is no longer inlined — git history preserves it at commit
`862662b` (pre-rewrite tip); readers who want the rejection-by-
rejection detail go to
docs/dav1d-reviews/000070-spatial-anchor-pi-w-object--2026-06-01.txt.

Critical technical corrections preserved inline (not as "what was
fixed", but as the directive answer):
  - §3.1: uint256 for H₁ position (octree depth >8 entropy
    preservation)
  - §3.2: rename `map_rotation_so3` → `map_rotation_euler_ypr` (no
    SO(3) overclaim — quantized Euler is not SO(3) coverage)
  - §4: WorldObjectRecord carries all four identity hashes
    (grammar_hash, axiom_pack_hash, manifest_hash, seed_hash) for
    replayability
  - §5: Joseph6 ships as one example grammar; future grammars
    register through the same mechanism

TICKETS.md index row also rewritten in directive voice.

doc_counts tests still pass.
2026-06-01 07:24:17 -04:00
9e4645f60e
#000071: rewrite ticket as directive forward-spec (no more rejection archaeology)
Per fox 2026-06-01: replace the descriptive review-archaeology
structure with what we SHOULD grow. Ticket goes from 805 lines
(original §§1-8 design log + my dav1d-review §0 retrofit) to
389 lines of clean directive spec.

What changed in shape:
  Before: §0 "Dav1d review verdict" decision-table + §§1-8
          archaeology of the original Joseph6 spec being rejected.
  After:  §1-12 forward spec. Goal at the top, hard constraints,
          composite ChainRoot identity, five bridge outcomes with
          typed witness shapes, privacy class vocabulary, Phase 1
          deliverables, Phase 2/3/4 roadmap, retro-validation
          appendix, cross-references, three remaining open
          questions, five-step alignment, one-line review history
          at the bottom pointing at the archive file.

What changed in content: nothing material. The corrected spec from
the prior §0 retrofit IS the body now. The original Joseph6 design
log is no longer inlined — git history preserves it at commit
fadc50a; readers who want the rejection-by-rejection detail go to
docs/dav1d-reviews/000071-world-bridge-grammar--2026-06-01.txt.

TICKETS.md index row also rewritten in directive voice. Shorter,
less "what was wrong" + more "what to build."

Net effect: an implementer picking this up reads a forward-looking
ticket they can act on, not an archaeology of which framing was
rejected. The dav1d review history is one line at the bottom, not
the structural frame.

doc_counts tests still pass.
2026-06-01 07:17:31 -04:00
ca7577f680
#000071: dav1d review 2026-06-01 — REJECT-AS-WRITTEN, GO-with-rewrite
The 1026-line de-novo response arrives after #000070 was corrected
from fixed Anchor6 to generic AnchorN/WorldDimensionGrammar. The
bridge concept is valid and necessary; the Joseph6-coupled framing
is now wrong. Same pattern as #000070's review: §§1-8 preserved as
the design log of what was reviewed; new §0 carries the corrected
spec.

Verdict matrix (12 rows in §0 decision table):
   GO: bridge concept (Agreement / Translation / Embassy), Phase 1
        doc-only, bridge_seed@v1 deferred to Phase 2, no audit_mode,
        no SQL, bridge atlas Phase 3.
   REWRITE: #000070-as-Joseph6-sibling → AnchorN sibling;
            chain_id=governance_policy_hash → composite ChainRoot
            with optional v7-W fields (null sentinels for language-
            only QA chains); single event_type='bridge' → typed
            schemas per kind; privacy as Phase 3+ footnote → Phase 1
            vocabulary (4 classes); #000059 "already-shipped"
            overclaim → proposed/structurally-aligned unless repo
            confirms.
   REJECT: doc-only Phase 1 flipping #000013 to "kernel_in_progress"
           — correct status is "bridge_grammar_specified"; kernel_
           in_progress is for actual kernel landings.

Five bridge outcomes (was three):
  Agreement   — grammars match on invariant set
  Translation — hash-pinned adapter proves the mapping
  Embassy     — foreign object hosted with limited rights
  Quarantine  — NEW: bridge attempted, invariant validation FAILED,
                record the rejection so future attempts see what broke
  No-bridge   — NEW: grammars genuinely incompatible, explicit
                declaration that no bridge will exist

Composite ChainRoot identity:
  chain_id = SHA256(canonical({
      chain_id_version, history_root, governance_policy_hash,
      canonicalization_version, schema_version, chunking_version,
      world_manifest_hash, world_dimension_grammar_hash,
      axiom_pack_hash, optional_verifier_policy_hash
  }))
Language-only chains: three v7-W fields are null sentinels →
chain_id collapses to existing identity. v7-W chains: all mandatory.

Phase 1 deliverable (corrected):
  1. Substrate-paper extension §"World-bridge grammar" (5 outcomes
     with typed witness shapes + composite ChainRoot + privacy
     vocabulary + sovereignty rule + #000070 cross-ref + retro-
     validation appendix with corrected shipped/proposed framing)
  2. Optional namespace stub arborist/world/bridge/__init__.py
     (STATUS = "namespace_reserved")
  3. NO kernels / NO bridge_seed canonicalization / NO SQL / NO
     cache-key dimension / NO new audit_mode / NO verifier change /
     NO KATs
  4. #000013 status bumps to "bridge_grammar_specified", NOT
     "kernel_in_progress"

Sovereignty rule survives unchanged (chain law local, bridge law
treaty-only, no bridge overwrites native chain law — guard against
forced-unity failure mode). Hash-pinned translators survive
unchanged. Topic-named under arborist/world/bridge/ unchanged.

Full review archived at:
  docs/dav1d-reviews/000071-world-bridge-grammar--2026-06-01.txt
2026-06-01 07:13:23 -04:00
862662b903
#000070: dav1d review 2026-06-01 — GO with rewrite (AnchorN, not Anchor6)
Folds dav1d's 1904-line review verdict into the ticket as §0 (new),
preserves §§1-8 as the design log of the original Anchor6 proposal
that was reviewed. Status flips from "open · awaiting dav1d review"
to "open · dav1d GO with rewrite · spec revision pending before any
kernel ships."

Verdict matrix:
   GO: generic AnchorN substrate primitive (not fixed Anchor6)
   GO: Joseph6 as the first registered default grammar (not THE
        ontology)
   GO: deterministic object-state canonicalization
   GO: axiom/physics-loaded WorldDimensionGrammar as the scalable
        path
   NO-GO: hard-coding H₁..H₆ as final ontology
   NO-GO: runtime LLM-decided dimensionality (axioms MAY propose,
           only deterministic validators may accept; grammars must
           freeze via grammar_hash before proof-path use)
   NO-GO: framing this as a "semantic verifier warrant"
   NO-GO: relation/event/place/agent_trace in this ticket
   NO-GO: SQL persistence at Phase 1

Critical technical corrections:
  - H₁ MUST use uint256, not uint64 (octree position entropy at
    depth >8)
  - Rotation mapper is map_rotation_euler_ypr(), NOT "SO(3)"
    (review §17 — quantized Euler triple, no continuous SO(3))
  - Canonical record carries grammar_hash + axiom_pack_hash +
    manifest_hash + seed_hash alongside the per-dimension values
  - Missing privacy.class = HARD reject (no PUBLIC fallback)
  - spatial-anchor-object@v1 folds into canonicalization_version
    only — no new audit_mode token, no verifier_policy_hash bump

Corrected package layout:
  arborist/substrate/spatial_anchor.py   (AnchorN, split_anchor_n)
  arborist/world/grammar.py              NEW — WorldDimensionGrammar
  arborist/world/pi_star/object.py       (derive_world_object_record
                                          + 5 mappers)
  arborist/pi_star/spatial_anchor_object.py  NEW — registry adapter
  bench/fixtures/spatial-anchor-object/known-answer-tests.jsonl
  tests/test_spatial_anchor.py
  tests/test_world_dimension_grammar.py
  tests/test_pi_star_spatial_anchor_object.py

Implementation NOT started — arborist/world/__init__.py STATUS still
"namespace_reserved"; only bench/spatial_anchor_validation.py
(pre-review empirical bench, commit 55b651f) on disk. Review arrives
at the right moment: no production code committed against the original
Anchor6 spec yet, so the AnchorN reframe lands in the spec before
the wrong primitive ships.

Full review archived at:
  docs/dav1d-reviews/000070-spatial-anchor-pi-w-object--2026-06-01.txt

Five of ten original open questions resolved by the pre-review bench
(Q1/Q2/Q3/Q8/Q9); review answers Q4/Q5/Q6/Q7; Q10 (paper-amendment
wording) is the only remaining open question — substrate paper text
needs revision to introduce AnchorN + grammar layer instead of fixed
Anchor6.
2026-06-01 07:10:01 -04:00
4098e41563
#000072: open ticket for legacy query() collapse + multi_route regression
Documents the work shipped this session (Phase 1 foundation, 10
commits 9ba6317..20faae0) and the blocker that stops Phase 2: the
multi_route pipeline regresses on 2/5 smoke fixture questions
(Mercury Seven → Sam T. Beddingfield; dinosaurs extinct →
Paul Austin Kelly) because Phase 1 hasn't ported the 5 downstream
rerank stages legacy query() uses to suppress noisy phrase-route
hits — body-density check, body-coverage sqrt rerank, source-role
rerank, title-purity rerank, ordered-token-match rerank.

Path B chosen 2026-05-31: stop here, leave multi_route off by
default (which IS default — policy=None preserves body-only
behavior). Phase 1 foundation stays in tree as future-ready
infrastructure; user surface unchanged.

Path A (port the 5 stages, multi-day effort) reserved for a
future focused session. Until then, legacy query() keeps
producing the same answers it always has, INCLUDING the wrong
"Edwina" pick on dinosaur Q5. The slim-FTS5 cloud path already
fixes that bug for `arborist cloud query` / `arborist
corpus-query` callers (proven 5/5 source parity in d9fb6a9).

Bumps Next ID 000072 → 000073.
2026-05-31 13:06:12 -04:00
bc3f94efeb
#000071: open ticket for Joseph 3-bridge inter-chain framework
Sibling to #000070 on the second axis of Joseph (@TrudoJo)'s spec.
Joseph posted the bridge-framework extension 6h after the 6-dim
spatial-ontology: chain A has its own world rules, chain B has its
own world rules, a bridge exists only where a deterministic
agreement layer can be proven. Three kinds: Agreement, Translation,
Embassy.

Phase 1 is doc-only -- the primary contribution is a retroactive-
validation appendix naming three already-shipped arborist primitives
as Joseph-bridge-shape patterns one-for-one:

  #000066 graft-receipt mode    = Agreement bridge
  #000056 Operation Sandwich    = Translation bridge (opus-mt hash
                                  IS the translator_id)
  #000059 graveyard (proposed)  = Embassy bridge (POINTER-LINKED,
                                  banner-labelled, never promotes)

The framework is not a new requirement on arborist. It is a unifying
spec that names what we already do in 3+ places, plus surfaces a
fourth pattern (bridge atlas for multi-instance federation with
potentially-different governance_policy_hash peers) as genuinely new
work for arborist/mesh/.

Bundle:
- docs/tickets/ticket-000071-world-bridge-grammar.md (~440 lines)
- docs/TICKETS.md index row + Next ID 000071 -> 000072
- docs/tickets/ticket-000070-spatial-anchor-pi-w-object.md §6 gains
  one-line cross-reference to #000071 as adjacent axis
- Joseph memory extended to cover both frameworks

Phase 2/3/4 deferred to separate tickets. Hard constraints: A1-A3,
no audit_mode token, no SQL change at Phase 1, sovereignty rule.

Status: open, awaiting dav1d Phase 1 review + fox go/no-go.
2026-05-31 10:43:34 -04:00
2eea5b5655
#000070: fold bench results into ticket as dav1d-ready handoff
Updates the spatial-anchor ticket so the pre-review empirical bench
(landed in 55b651f) reads as a self-contained dav1d review packet:

- Status line: notes bench shipped in 55b651f
- §7a Pre-review empirical evidence: expanded with reproducibility
  notes (RNG seed 0xa8c90e551fd34427, wall ~2s, stdlib-only), the
  five bench purposes mapped to open questions, full headline-results
  table, and per-headline "what each one buys dav1d" prose for Q1
  through Q9.
- §3 Land sequence: step 1 marked done in 55b651f with explicit
  pre-review-bench scope; step 2 annotates that 5 of 10 open
  questions now resolve by measurement.
- docs/TICKETS.md index row: leading status cell now opens with the
  bench headline + per-section numbers so the index reads as the
  dav1d handoff summary, not just "open · awaiting review".

No new code, no new commits to the bundle itself -- 55b651f remains
the bench's shipping commit. Pure documentation refresh.
2026-05-31 10:23:02 -04:00
55b651f624
#000070: spatial-anchor pi*_w_object ticket + pre-review bench
New ticket for Joseph (@TrudoJo)'s 6-dim procedural spatial-anchor
framework as the first verifier kernel under the #000013 v7-W reserved
namespace. A single committed 32-byte SHA-256 hash deterministically
expands into six 32-byte regions H1..H6 via the HMAC-SHA-512 KDF already
shipped in arborist/substrate/anchor_prg.py (#000035); each region drives
one quantized object dimension under a fixed canonical mapper. Domain
separation from #000035 by dedicated spatial_anchor_seed published in
the v7-W manifest -- preserves #000035's KAT freeze + dav1d 2026-05-11
final review intact.

Bundle:
- docs/tickets/ticket-000070-spatial-anchor-pi-w-object.md (718 lines):
  full spec with 8 design-choice subsections, working Python sketch,
  12-NOT scope boundaries, 8-row cross-references, five-step deletions,
  10 open questions for dav1d.
- bench/spatial_anchor_validation.py: pure-stdlib pre-review evidence
  (~2s, RNG-seed-pinned, reproducible). Five benches: avalanche,
  cell-distribution uniformity, collision vs birthday-bound, cross-region
  independence, domain separation.
- bench/spatial_anchor_validation_results.md: report from first run.
- Makefile: 'make bench-spatial-anchor [SPATIAL_N=N]' target + PHONY.
- docs/TICKETS.md: index row + Next ID 000070 -> 000071.

Bench headlines (N=10000):
- Avalanche mean 767.85 bits (PRF null 768, z=-0.49)        -> PASS
- Cell-distribution chi^2 |z|<1 at L=2,3,4                  -> PASS
- Birthday-bound ratio obs/exp 0.989/1.038 at populated L   -> PASS
- Cross-region Pearson all 15 pairs < 2sigma                -> PASS
- Domain separation Arm A 767.91 / Arm B exact 0 collision  -> PASS

Five of dav1d's ten open questions (Q1 seed source, Q2 segmentation,
Q3 position mapper, Q8 endianness, Q9 KAT adversarial vectors) now
resolve with measurements rather than appeals to PRF authority.
Q4/Q5/Q6/Q7/Q10 remain non-empirical design decisions.

Status: open, awaiting dav1d review + fox go/no-go. No registry slot
booked, no substrate-paper amendment landed, no kernel module created.
2026-05-31 10:16:02 -04:00
7f7eeefeb9
crawl central-db + query auto-include + read-seam provenance
- make crawl-ingest writes to one central crawl db (CRAWL_DB, default
  ~/.arborist/crawl/web.db) instead of per-domain shards in the
  peer-shared main dir: keeps locally-crawled content out of peer
  sharing by default and a growing domain set under SQLite's 10-attach
  cap (Makefile, docs/crawler.md).

- arborist query auto-includes the local crawl db (query() gains
  extra_shards; CLI --include-shard / --no-crawl-db, default-on when
  web.db exists). Fix latent --db single-file query AttributeError
  (cli.py). Persist used / used_pointer_ids + retrieval_purity into
  merkle_proof so read-only consumers can see which chunks fed the
  answer (qa/query.py).

- arborist.read: read-only seam for dashboards / verifiers; on a
  multi-source context root surface the real primary source instead of
  the opaque corpus://multi-source sentinel (read.py). Backs the
  arborist-viz Merkle Command Center (#000069).

- tests for extra_shards, the CLI crawl-db resolver, and the read seam.
2026-05-29 13:45:47 -04:00
ec55db513c
#000068 Phase 2+3: bench + opt-in demote flag for missed-answer guard
Phase 2 — bench instrumentation + measurement run

bench/qa_sweep.py picks up the answerability sidecar projection per row
(answerability_fired, answerability_confidence, answerability_denial_
pattern, answerability_answer_type, answerability_candidate_count) and
aggregates per-mode (answerability_fires + S/M/W confidence breakdown)
into a new column in the markdown summary table.

Measurement run on bench/qa_results/phase2-sidecar-on/2026-05-27T14-
16-22Z (76 questions × n=3 × claim_lattice × Hermes-3-8B × tail layout,
228 runs). Headline:

  sidecar fires        2/228 (0.88%)
  confidence dist      2 strong / 0 medium / 0 weak
  precision            100% (2/2 fires were the Ballestrini fixture)
  recall on Ballestrini 2/3 across n=3 (third run model extracted
                                       correctly -> sidecar silent,
                                       correct behavior)
  false positives      0/226 non-Ballestrini runs
  verifier verdict     both fires labeled STRICT by the binary
                       verifier (the verifier-blind class, exactly
                       as predicted)

Detection rule's three-clause conjunction (denial + extraction-shape +
candidate proximity near cleaned subject tokens) is operating at the
precision floor. The strong-confidence-only firing pattern is what
calibrates Phase 3's demote threshold.

Phase 3 — opt-in demote flag (default OFF per Dav1d Phase 4 NO-GO)

arborist/qa/keys.py: answerability_demote_enabled added to
_VERIFIER_POLICY_FIELDS so flipping the flag partitions cache via
verifier_policy_hash. Justification: when on, the rendered audit_mode
changes (EVIDENCE-WARRANTED -> EVIDENCE-MISSED-PARTIAL), which IS a
verifier-output property; verifier hash must move accordingly. The
other answerability_* fields stay governance-only (sidecar
diagnostic, no audit_mode mutation).

arborist/cli.py:_render_audit_label extended with answerability +
demote_enabled kwargs. Logic:

  demote_triggers = (
      demote_enabled
      and answerability["answerability_warning"] is True
      and answerability["confidence_class"] in ("strong", "medium")
  )

  lattice modes:
    EVIDENCE-WARRANTED -> EVIDENCE-MISSED-PARTIAL    (rung transition)
    POINTER-LINKED / ANCHOR-WARRANTED -> "rung · missed-answer"
                                          (tail tag; rung itself already
                                          signals degradation)

  non-lattice modes (quote/span/entity/paraphrase):
    audit_mode token unchanged + "· missed-answer" tail tag

  weak confidence: NEVER demotes (Phase 2 saw zero weak fires on real
  failures; reserved for future expanded detection ladder)

CLI flag --demote-on-missed-answer on both `arborist query` and
`arborist ask`, default OFF. Flows into call_policy[
"answerability_demote_enabled"] and through to result[
"answerability_demote_enabled"] so the renderer reads it without
needing the policy dict.

End-to-end verified live: 4 fresh Hermes-3-8B runs with --demote-on-
missed-answer on `songs by veronica ballestrini`, all 4 rendered
EVIDENCE-MISSED-PARTIAL · via claim_lattice (Hermes hit the failure
mode in all 4, sidecar fired strong, demote logic transformed the
label).

Phase 4 (default flip to demote-on) — NO-GO per Dav1d 2026-05-27 §3.4:
"a false sidecar warning is tolerable; a false audit-label demotion
can damage trust in correct abstentions." Phase 2 precision is 100%
but n=2 fires is too few samples to claim precision floor empirically.
Default flip blocks on wider bench + human spot-check of the warnings.

Tests: 47 total (36 Phase 1 + 11 new Phase 3 covering hash partitioning
discipline + render-label projection across all four rung/confidence
matrices). Full suite 2794 passed (delta +22 from prior 2772).

Bench output (bench/qa_results/phase2-sidecar-on/) intentionally not
committed — bench/qa_results/ is gitignored per existing convention;
the ticket carries the headline numbers + path for re-inspection.
2026-05-27 10:40:35 -04:00
2ab11d2e59
#000068 Phase 1: verifier-blind missed-answer falsification guard
Adds a deterministic read-only sidecar to detect a class of failure the
binary verifier is structurally blind to:

  Evidence contains the answer.
  Model says the evidence does not contain the answer.
  Verifier sees no unsupported positive claim -> marks run clean.
  User receives a false negative under EVIDENCE-WARRANTED.

The motivating case: "songs by veronica ballestrini" against the 2010
Wikipedia corpus. Hermes-3-8B under user_payload_layout=tail returned
"the specific songs by her are not mentioned in the provided evidence
blocks" when evidence E2 literally contained "Amazing", "Out There
Somewhere", "Fascinated", "What's Up With That", "Don't Say". Verifier
correctly returned EVIDENCE-WARRANTED 2/2 because the existing layered
verifier (quote / span / entity / paraphrase + Rule 8 title-relevance +
Rule 9 subject-tokens-absent + claim-count ceiling) guards unsupported
*presence*, has no hook for unsupported *absence*.

Layout fixes attention placement on the specific instance (the 5/27
n=3x75q bench confirms bookend/per_chunk recover Ballestrini); layout
alone cannot close the class -- adversarial phrasing or a bigger prompt
resurfaces the failure under any layout. The right substrate move is to
falsify "not mentioned" as a testable claim.

Detection rule (three-clause conjunction, all must fire):

  A. Denial pattern in answer (sealed v1 phrase list: "not mentioned",
     "not provided", "the evidence does not say", "does not mention",
     "no specific", "no evidence", "cannot determine from the provided
     evidence", "is not stated", "is not specified"). Casefolded +
     whitespace-normalized substring match.

  B. Question is extraction/list-shaped. Either a surface cue ("songs
     by", "works by", "books by", "who wrote", "who composed", "what
     year", "list of", "name all", ...) matches, OR the existing
     arborist.qa.quantifier classifier returns intensity in {ALL,
     COMPREHENSIVE, OPEN_REQUEST, MANY, PLURAL}.

  C. Evidence contains candidate spans matching the answer_type within
     a proximity window (default 600 chars) of cleaned subject tokens.
     Candidate kinds aligned to answer_type:
       title_like -> quoted_string, title_case_span, comma_list_item
       person     -> title_case_span
       date       -> year, date

Hardenings folded in from the 2026-05-27 Dav1d de-novo review:

  1. Subject tokens strip cue/relation/stop words. For "songs by
     veronica ballestrini" the cleaned subject is ["veronica",
     "ballestrini"], NOT all four tokens. Without this the guard
     false-triggers on "Harvard University" or "New York" near
     proper-noun subjects.

  2. Answer-type alignment. Candidate span kind must match query type
     so "songs by John Smith" + evidence about Harvard/NY does not
     strong-trigger.

  3. Confidence class is deterministic (weak | medium | strong), not
     boolean. Strong requires quoted_string near exact subject mention
     + multiple type-matched candidates. Phase 3 demote will gate on
     confidence_class.

  4. Cap output at 10 candidates (the per_chunk-quote-inflation
     lesson). Prevents the guard becoming another claim amplifier.

  5. Offsets are offset_start + offset_end + offset_basis=
     "evidence_object_text", never an ambiguous single offset.

  6. Cache-hit path returns answerability: None. Cached records do not
     carry the evidence_map, only the rendered sources summary, so the
     sidecar cannot recompute candidate spans without re-running
     retrieval. Operators wanting fresh diagnostics use --burn.

  7. Phase 1 stays out of verifier_policy_hash. The
     answerability_sidecar_enabled / answerability_threshold /
     denial_patterns_version / extraction_cues_version fields fold
     into governance_policy_hash only. Phase 3 demote flag
     (answerability_demote_enabled, default False) will move the
     verifier hash WHEN ON because it changes the rendered audit_mode
     (EVIDENCE-WARRANTED -> EVIDENCE-MISSED-PARTIAL).

Sidecar discipline (matches arborist.qa.inspect.diagnose_* sister
functions deflection / coherence / title_relevance):

  - no model calls (no LLM-as-judge, no NLI, no translation)
  - no audit_events writes
  - no providence_cache writes
  - no answer text mutation
  - no claim promotion -- the trigger conjunction makes promotion
    structurally impossible (only fires on denial answers)
  - byte-deterministic: same (question, answer, evidence, policy) ->
    same output every time

Result-dict integration: result["answerability"] is None when the
guard did not fire, or a structured diagnostic dict when it did
(diagnostic_version, confidence_class, triggered_clauses,
denial_pattern_matched, extraction_cue_matched, extraction_shape,
answer_type, subject_tokens, candidate_count, threshold,
missed_answer_candidate_spans). Read by bench_qa (Phase 2 will add
warning-count aggregate to bench rows) and CLI render.

Three return points carry the key:
  - miss-path (full retrieval + verify): computed from evidence_map
  - cache-hit: None (Dav1d cache-hit recompute discipline -- evidence
    not stored, recompute requires re-retrieval)
  - reject-broad early-return: None (no evidence examined)

Tests: 36 new pinning the three-clause logic, positive (Ballestrini)
regression, negative control (John Smith + Harvard/NY), each-clause-
alone silence, schema integrity, byte-determinism, sidecar-disabled
short-circuit, dict-shaped evidence support. All pass; existing
inspect tests (60) all pass.

End-to-end verified live via the CLI on the real corpus (2010 ~/.arborist
/shards): 3 fresh Hermes-3-8B runs on "songs by veronica ballestrini",
run 1 hit the failure (sidecar fired with confidence: strong, 351
candidates, denial: "not mentioned"), runs 2-3 model extracted
correctly and sidecar correctly silent.

Phase 2 (bench + threshold tuning) and Phase 3 (opt-in demote flag)
are open as follow-ups. Per Dav1d: NO-GO on default demote-on until
benchmark + human spot-check confirms low false-positive rate.

Full spec in docs/tickets/ticket-000068-verifier-blind-missed-answer-
guard.md (post-review hardenings section at top names the seven
load-bearing changes from the Dav1d 2026-05-27 review).
2026-05-27 10:14:51 -04:00
9cfb9c8d01
#000067: M-aware cold-pack hydration (route per-row into M target shards)
Open ticket. Today's hydrate_from_metadata_pack takes one conn and
writes every incoming row into one shard — fine when the corpus
was a single shard, broken now that #000065 put the producer in
M=4 hash-routed topology. A fresh peer pulling packs must land each
doc on `shard_for_document(document_root, M)` — same routing
function as the producer — or the consumer's M=4 ATTACH-and-route
assumption is just decoration over a single-shard reality.

Plan:
  1. Add corpus_shard_count to pack manifest (read from source meta
     during dump_shard_metadata) — pack carries the M it was built
     against.
  2. restore_shard_metadata_routed(targets, M, table_dir) in
     cold_pack_metadata.py — mirrors _route_per_doc_table from
     migrate.py (per-document tables route by document_root /
     src_root / core_root; consolidated tables all go to target 0).
  3. hydrate_from_metadata_pack gains a targets / shards_dir param.
  4. arborist cold unpack --shards-dir DIR initialises M target
     shards from the manifest's corpus_shard_count and routes.
  5. Regression test: pack 2 shards → hydrate into fresh 4 shards
     → assert every doc on its hash-routed target.

Refactor question (raised, not decided): the routing rules
(ROUTED_BY_DOCUMENT_ROOT, CONSOLIDATED_TABLES) currently live in
migrate.py. Either duplicate them in cold_pack_metadata.py (fast)
or factor into arborist/multi_shard.py (cleaner, also serves
#000066 graft mode). Shared module is more honest.

Prerequisite for #46 (genesis on 3090 from cloud). Without this,
genesis is a 2-step α-kludge (hydrate-then-reshard) that wastes
~30 min and treats packed shards as if from an arbitrary topology.

Index entry bumped; next-id 67→68. Per-ticket spec doc to follow
when the implementation gates open.
2026-05-26 16:08:49 -04:00
514dcd8342
#000065 closed: production reshard landed; record in corpus-history
2026-05-26 19:47 UTC. ~94 min wall. 3,468,226 globally-unique docs +
6,235,588 chunks + 90,592,990 edges + 3,468,403 audit events re-routed
from non-deterministic spray-by-ingest-order layout to canonical
content-hash M=4 layout (shard_idx = int(document_root[:8], 16) % 4).

Final state:
  per-shard doc uniformity within ±0.04% (theoretical max ±0.05% for
    first-32-bit SHA-256 prefix)
  audit chain consolidated to shard 000 via Option A (re-sorted by ts,
    re-chained; bodies preserved unchanged; tail event type=reshard
    carries plan+result body, hash 8da3aa19…)
  on-disk sizes: 000=11.0 / 001=8.8 / 002=8.8 / 003=8.8 GB
  validation: chunks delta 176 (0.003%) + edges delta 547 (0.0006%)
    are cross-shard dupes from re-ingest history, collapsed by
    INSERT OR IGNORE; within the 1% tolerance gate
  smoke queries: Barack Obama / YouTube / Albert Einstein all
    returned proper evidence from correct (hash-routed) shards
  chain-check-shards: 0 breaks on every shard

Two mid-flight defect fixes (also committed):
  04edff7: derivations.src_root FK guard fired on legitimately
    cross-shard refs → writer connection PRAGMA foreign_keys = OFF
  c86d5ac: WAL accumulated ~37 GB across passes (SQLite auto-checkpoint
    blocked by open reader cursors) → _checkpoint_truncate between
    phases. Production migration was rescued mid-flight by manual
    sibling-connection wal_checkpoint(TRUNCATE) freeing 27.7 GB.

Closes #000065 in both the index and the per-ticket file. The
per-ticket design doc stays open as a design-log artifact (its
content is still the right reference for the next reshard / for
graft mode #000066).

Follow-on tracked as tasks #44–#47:
  #44 re-pack post-reshard shards into DO Spaces (current bucket
      packs are stale, still in pre-reshard topology)
  #45 verify bucket pack hydration is deterministic against the new
      content-hash layout
  #46 genesis a fresh peer on 3090-ai.foxhop.net from cloud — first
      real SPV-wallet end-to-end test
  #47 retire stale pre-reshard bucket packs after #46 confirms
2026-05-26 15:51:20 -04:00
f4397a9217
#000066: cold-pack overlay/graft mode (pack-as-package)
Scaffold-only ticket. Captures the architecture for taking the
#000061 cold-pack format and adding a second mode beside hydrate:
overlay an existing pack onto a populated shard set ("graft").

Surfaced while running the #000065 reshard cutover and fox extended
the design: each pack carries a `corpus_name` field
(wikipedia-2010, wikipedia-current, arxiv-cs, ...), making
`arborist cold graft wikipedia-current` feel like `apt install`.

Three concerns analysed:
  doc/chunk/edge overlay   trivial (INSERT OR IGNORE on content-
                           addressed PKs collapses dupes)
  FTS5 overlay             trivial (new chunk_ids → new fts rows)
  audit chain overlay      the only hard part — three approaches:
                           A graft receipt (chosen): one event in
                             host chain carrying pack_hash +
                             event_count + first/last hashes; pack
                             file is the durable witness; zero
                             schema cost; aligned with v8/v9
                             witness pattern
                           B re-chain everything: rejected — graft
                             is frequent so invalidating external
                             refs is wrong tradeoff (different
                             story from the one-time reshard)
                           C chain forest with chain_id col: right
                             answer when graft dominates lifecycle
                             but premature now

Long-game payoff: mesh-peer-corpus-merge. Two peers diverge over a
partition, each carries packs the other lacks, reconciliation =
exchange + graft what's missing. Makes "mesh of arborists"
coherent rather than "fleet of arborists."

Scaffold gated on (a) #000065 lands+stabilises, (b) a second
corpus exists to graft, (c) at least two peers want to exchange.
No code until then; the design lock is what the ticket buys.

Index bumped Next ID 000066→000067.
2026-05-26 14:09:07 -04:00
967fedbbe0
#000065: pin M=4 + bench script + SQLite-alternative decision tree
Pinned the canonical shard count at M = 4 based on real-Wikipedia
ingest + query benchmark (bench/shard_count_sweep.py). Captured the
"when does SQLite stop being the right substrate" decision tree so
future operators know what bench would justify a fork or replacement.

Bench numbers (Wikipedia 2003 cur dump, 2000 docs, 4 cells of
M ∈ {1, 2, 4, 8}, 50 FTS queries per cell):

     M   chunks/s    q_p50_ms    q_p99_ms   attach_ms
     1    3,648        0.05        0.20        1.61
     2    5,649        0.03        0.19        3.24
     4    6,405        0.07        0.30        9.00
     8    6,959        0.03        0.28        9.65

Key observations:
- M=1→M=2 is the biggest ingest win (+55%). Most gain happens there.
- M=2→M=4 is +13%. M=4→M=8 is only +9% — diminishing returns.
- Real wikitext canonicalization is per-worker Python CPU bound, not
  SQLite-writer-lock bound. More shards don't unlock more CPU.
- Query p50/p99 is flat across M within noise (50 queries small).
- ATTACH cost grows linearly: 1.6 / 3.2 / 9.0 / 9.7 ms.

Why M=4 specifically:
- Captures 92% of peak ingest throughput (6,405 / 6,959).
- 6 ATTACH slots free under SQLite's 10 ceiling for aux DBs
  (qa.db, snapshots.db, selfmodel-chain.db, crawl_*.db, future
  mesh_*.db) — comfortable headroom. M=8 leaves only 2 slots.
- Mobile-tolerable: phone NAND attach is 5-10x slower than NVMe;
  M=4 = 45-90 ms cold start (instant), M=8 = 50-100 ms (sluggish
  with no headroom).
- Matches fox's current 4-shard layout = cheapest migration.

Decision tree for when SQLite stops being right (full text in
ticket §"When the SQLite-default substrate stops being right"):

A. ATTACH ceiling pressure (auxiliary DBs grow past 5) → bench
   forked SQLite with SQLITE_MAX_ATTACHED=125, M ∈ {16, 32, 64};
   if attach cost stays linear past M=10, fork viable but pays
   permanent "no longer stock sqlite3" tax.

B. Ingest hits >10k chunks/s sustained ceiling → first tune
   page_size / WAL checkpoint / mmap_size / synchronous. If
   tuning gets 2-5x, stay on SQLite. If still ceiling-limited,
   candidates: DuckDB (columnar, MVCC, FTS), libmdbx (B+tree no
   FTS; we'd build it). In-house DB rejected without specific
   failure of those.

C. Federation needs multi-writer-same-shard → SQLite writer-lock
   serializes peers, becomes federation bottleneck. First try
   leader-election (single-writer-per-shard with WAL replication
   to followers). If true multi-writer required, SQLite is wrong;
   candidates: FoundationDB, CRDT-on-KV-store. DuckDB does NOT
   solve this — its MVCC is single-process.

Honest verdict: for current arborist workload (single-writer-per-
shard, read-mostly federation), stock python3 sqlite3 is the right
substrate. None of A/B/C are close to firing. The bench discipline
exists to know what to measure when something changes.

bench/results/shard-count-sweep-2026-05-26T16-20-48Z.csv (synthetic
baseline) + 2026-05-26T16-31-34Z.csv (real Wikipedia) committed as
the load-bearing measurement for the M=4 choice.
2026-05-26 12:40:48 -04:00
fb38212fe8
docs: #000065 — correct re-ingest framing to teleport (content-addressed rebalance)
fox caught the imprecision: "the shards are teleported if we fix this
because we know the shard a doc will end up in."

Re-ingest = re-read source files, re-canonicalize, re-chunk, re-hash.
Hours-to-days from Wikipedia dumps.

What's actually needed = content-addressed rebalance. Every row in
the corpus is already addressed by content (document_root, leaf_hash,
merkle_nodes.hash, audit_event_hash). Migration reads existing rows,
computes new_shard_idx via the routing function, INSERTs into the new
M shards. No source-file work, no canonicalization, no LLM.

Updated the ticket's "Migration story" section with the per-table
teleport recipe:

  documents:            move by document_root → new shard
  chunks (+content):    follow doc to its new shard, re-assign chunk_id
  chunks_fts:           rebuild per new shard from chunks.content
  merkle_nodes:         move with document_root
  edges:                move by src_root
  concept_relations,    move by content-derived parent
    derivations,
    providence_cache,
    citation_aliases,
    term_aliases:
  audit_events:         ALL → shard 000 (canonical), re-numbered + re-hashed
  snapshots, mesh_*:    canonical shard 000

Audit chain handling: chose Option A (canonical shard 000) over
Option B (split-by-subject_root). Preserves global event ordering,
re-hashing happens once at migration time. The alternative loses
cross-shard event ordering for falsification + replay reasoning.

Estimated wall: ~20-40 min I/O-bound on current corpus
(35 GB across 4 shards → ~35 GB across 8 shards, moves once).

Hard discipline added: move into ~/.arborist/shards.v2/, keep
originals as rollback, atomic dir-swap when verified. Mistake in
routing function = corrupted federation, recoverable only by going
back to the originals.
2026-05-26 12:11:25 -04:00
7f29ee91e6
docs: open #000065 — canonical shard count + content-hash routing
Surfaced while sizing #000061's federation story. Today shard count
conflates two roles:

  - producer ingest parallelism (wants = vCPU count)
  - consumer ATTACH fan-out (capped at SQLITE_MAX_ATTACHED=10)

On default Python sqlite3, the ATTACH ceiling is 10 and can't be
raised without a custom sqlite3 build (which violates CLAUDE.md's
"python3 + venv + sqlite3 is enough" property). Producer with 16
shards → consumer fails to attach the 11th, federation silently
breaks.

Design: introduce M = canonical shard count (corpus-wide constant,
default 8) decoupled from N = ingest workers. Document → shard
assignment becomes content-deterministic:

    shard_idx = int(document_root[:8], 16) % M

Same input → same output across every peer. Today's "spray by ingest
order" is non-deterministic across peers — two peers re-ingesting
the same corpus put the same document_root in different shards. That
weakens federation more than it should.

Migration hard-constraint (fox: "this implies we will need to
reprocess all our data into shards"): re-ingest required. Current
layout is sprayed by ingest order; post-ticket is sprayed by content
hash. Two layouts are incompatible by construction. Captured in
ticket §Migration as the load-bearing operational note.

Phases laid out (0-4: design lock → read path → ingest path →
pack-restore → corpus migration tool). Open audit-chain re-numbering
question (per-shard event_hash chains break when rows rebalance
across shards). Kept as one ticket — do-not-proliferate.

Scaffold only. No code yet — design lock first.

Next ID bumped to 000066.
2026-05-26 11:59:05 -04:00
576cb0eeaf
#000061: fold 3 gaps from Dav1d review (manifest/latest, license_class, cold_pending)
Dav1d's reviews of #000061 (Response A + Response B/FINAL in
~/Downloads, 2026-05-26) flagged a long list of items — most already
shipped in the SPV-split work. Three were genuine gaps worth folding
into #000061 before close:

Gap 1: manifest/latest pointer for new-peer discovery.

  A fresh peer doing `cold list` got a list of metadata-pack hashes
  but no obvious "which one is current for shard X." Added
  get_latest_pointer + update_latest_pointer to the backend ABC.
  push_pack writes manifest/latest.json on every successful metadata
  pack push (read-modify-write keyed by snapshot_root). Mutable
  pointer; content addressing of the packs themselves preserves the
  trust root. Last-writer-wins on contention.

Gap 2: license_class field + producer-side refuse for public buckets.

  Maps documents.source_type to a license bucket (wikipedia_cur /
  textbook_tex → public_redistributable; html / grok / vcs → unknown;
  anything else → unknown). Strictness order: public < unknown <
  private. compute_shard_license_class() walks DISTINCT source_type
  in documents. push_pack now refuses to upload if the shard's
  strictest license is more restrictive than the operator's
  allow_license_class (default: public_redistributable). The
  metadata pack's manifest carries _license_class so consumers /
  auditors can see the producer's classification without inspecting
  source documents. ValueError on refusal — the bucket ACL is the
  operator's call, but arborist refuses to participate in a
  licensing/membership leak unless explicitly opted in.

Gap 3: cold_pending table for resumable uploads.

  Killed mid-upload, push_pack left orphan multi-GB tempfiles in
  /tmp with no DB trace. Added schema:

    CREATE TABLE cold_pending (
        tempfile_path TEXT PRIMARY KEY,
        pack_hash TEXT NOT NULL,
        kind TEXT NOT NULL,
        backend_endpoint TEXT NOT NULL,
        backend_bucket TEXT NOT NULL,
        object_key TEXT NOT NULL,
        started_at INTEGER NOT NULL,
        state TEXT NOT NULL DEFAULT 'pending'
    );

  push_pack INSERTs a row before each upload + DELETEs on success.
  A killed process leaves the row pointing at the orphan tempfile;
  a recovery script (future) reads cold_pending, checks bucket for
  the object, either deletes the row + tempfile (success was just
  unreported) or re-uploads from the tempfile if it still exists.
  Matches the same pattern as the audit chain — explicit state
  rows beat inferring from chunks.content IS NULL.

Sibling tickets opened for the larger items the reviews flagged
(scaffold-only, no code; opening them captures the design in the
log without proliferating, per CLAUDE.md):

- #000063 Cold-object private-ciphertext mode (mesh-keyed object
  keys for non-public corpora on public-read buckets). Needs mesh
  group-key ABI + real non-public corpus before code.

- #000064 Cold-object operations toolkit (verify / diff / doctor /
  repair-fts / gc-plan CLI + expanded audit-event taxonomy).
  Bundled so the audit-event vocabulary gets one design pass.

5 new tests:
  test_gap2_license_gate_refuses_unknown_class_to_public_bucket
  test_gap2_license_class_in_metadata_manifest
  test_gap1_latest_pointer_resolves_metadata_pack_per_snapshot
  test_gap3_cold_pending_clears_on_successful_upload
  test_gap3_cold_pending_records_inflight_upload

26 cold-object + 7 evict tests pass (33/33 green incl. boto3 wire).

Next ID bumped to 000065.

Live v3 SPV corpus run (bmq47x6t3) completed cleanly during this work.
Will report sizing + memory profile in the next message.
2026-05-26 10:50:57 -04:00
eba08beb61
docs: fold Dav1d review (2026-05-26) into ticket stack
Three doc-only housekeeping items from Dav1d's de-novo reconciliation
of the architecture stack (no code changes; the active build is
#000061 cold-pack work, which is unaffected by this review):

1. Accepted-error formula. Dav1d corrected p_raw × (1-d)(1-r) to
   p_raw × (1 - dr) where r is conditional on detection. Searched
   docs/ and arborist/ — the wrong form does NOT appear in this
   tree (it lives in the external recursive-truth-maintenance / RCO
   manuscripts Dav1d cited). Nothing to fix here; recorded for the
   manuscript authors.

2. #000060 H-ABCDEFG split. Folded the M/C/X axis split into the
   harness scope: M (mechanism — does the substrate's plumbing work),
   C (capability — does it improve task performance), X (external
   adversarial — does it generalize outside author-designed fixtures).
   ACCEPT requires clearing all three. Without X, the harness risks
   self-validating benchmark theology — passing tests its own designers
   picked. Tagged at fixture-definition time; aggregator emits per-axis
   pass rates + combined ACCEPT verdict. Doesn't change the existing
   BatteryResult row schema.

3. #000062 Mechanistic Witness — new scaffold-only ticket. Specifies
   a content-addressed MechanisticWitnessRoot over (model_config,
   capture_policy, contrastive_prompts, features/neurons, intervention
   result, behavioral delta, safety policy) as a DIAGNOSTIC sidecar
   feeding SelfModel + benchmark fixtures. Four hard guardrails:
   diagnostic-only by default; sandbox intervention only; no production
   steering without governance ACCEPT via #000060 M+C+X; feature labels
   never become semantic proof. No code until a real falsifier use case
   exists + guardrails are CLAUDE.md rules + #000060 harness gates
   promotion. The dual-use risk (Pan et al. 2025: 0.1% MLP ablation
   breaks refusal in 72B models) makes governance-first framing
   load-bearing.

Next ID bumped to 000063.

No code change to arborist/. The in-flight v3 SPV corpus pack
(bmq47x6t3) continues unaffected.
2026-05-26 10:22:17 -04:00
727cb1bd96
feat: #000061 cold-pack distribution tier (boto3 S3-compat + DVD-R safe-fit)
Ship arborist corpus state to new peers and DVD-R archival via
point-in-time tar.zst packs. One artifact serves both channels —
bucket+CDN delivery and physical-media archival.

Bucket holds packs only. Pack key = hash_leaf(manifest_bytes), so same
chunk set on two writers produces the same pack_hash and upload is
idempotent. Each pack pins the corpus snapshot_root it covers in audit
+ result body — packs are delayed snapshots, not live mirrors;
falsifications between repacks produce new pack_hashes.

stream_packs runs streaming zstd over tarfile, peeking compressed-buffer
size after each chunk via FLUSH_BLOCK (preserves dictionary). Default
cap 4_400_000_000 — 4.4 GB DVD-R safe-fit, ~6.5% buffer below the
4.7 GB marketing capacity to absorb ISO9660 overhead, growisofs
lead-in/lead-out, media variance, and drive-edge refusal. Each disc
fills to ~4.4 GB recorded data, not the ~1.5 GB an uncompressed cap
produced.

One backend class (S3CompatibleBackend via boto3 + endpoint_url) covers
AWS S3, DO Spaces, R2, B2, GCS S3-interop, MinIO. Optional dep
[object-store] = boto3>=1.34; dev extras pull moto for the wire test.
Voyeur: credentials via AWS_ACCESS_KEY_ID/_SECRET_ACCESS_KEY env or
~/.aws/credentials, never printed; only endpoint URL + bucket name
surface in logs.

CLI: arborist cold {pack,unpack,stats}. Makefile: cold-pack,
cold-pack-dvd (local-dir output for growisofs), cold-unpack, cold-stats.

Sizing for current shards (14.1M chunks, ~17 GB compressed): ~4 packs
at the default cap, ~\$0.34/mo DO Spaces storage, ~\$0.0001/fresh-peer
hydrate.

Always-on raw-UTF-8 leaf store (per ticket "Hard invariants") deferred
— packs-only for now, backfill later.

2557 passed, 28 skipped, 1 xfailed.
2026-05-25 20:23:44 -04:00
7a43ceb699
docs(#000059): bounded-ingestion hard constraint on the claim graveyard
fox: a graveyard that keeps every wrong answer forever grows unbounded
like cancer and is counter to constraint-optimization. Bake in the
bound:

- earn-to-enter (recurrence-gated) — a failure earns a tombstone only
  when its canonical claim-family re-fails; one-offs dropped.
- fingerprints not transcripts (UTXO-set analogy) — store
  canonical_claim_family|falsifier_root|failure_class, prune bulk text.
- decay/compact to steady-state — evicts like a surface, never a core.
- off the hot path — dedicated graveyard shard, bloom-filter burden
  check only.

Gossip-group falsifier admission inherits the same discipline:
difficulty-adjusted stable-rate ingestion (BTC block-rate target) +
per-window budget (#000036), enforced in #000012/mesh. BTC lesson is
bounded self-regulating ingestion, not store-everything. If it cannot
be bounded to a steady state, the graveyard is not built.
2026-05-20 19:28:48 -04:00
d4480cddb7
docs(#000058,#000059,#000060): ticketize Dav1dPrometheus protocol-layer report
Three tickets from the 2026-05-20 Dav1dPrometheus "Protocol-Layer AGI"
working report (held outside the repo; referenced not committed):

- #000058 cache_key_9 verifier-policy mandatory-vs-legible decision +
  doc reconcile. Records the five-step-#1 correction: verifier fields
  already fold into governance_policy_hash, so the 9th dim is audit
  legibility not a correctness gap.
- #000059 admission discipline: claim-graveyard burden-shift +
  self-providence quarantine (guards the existing ingest-self-providence
  self-confirmation loop).
- #000060 H-ABCDEFG same-model substrate-delta harness (jaggedness +
  curvature); curvature-aware ForkScore folded into #000012 Phase 2,
  not spawned as a sibling.

Reconciles CLAUDE.md cache_key invariant (8-dim -> 8 + optional 9th).
Next ID 000058 -> 000061.
2026-05-20 19:27:08 -04:00
a4f3e126f7
feat(#000049 §7 #28): tinygrad NLI backend + deterministic engine-agreement A/B; ONNX-immunity rationale
Opt-in third NLI inference backend (ARBORIST_NLI_BACKEND=tinygrad) in
qa/nli/shadow.py, parallel to torch/onnx-int8, behind the #000049
cage: shadow-only, never an audit_mode input, never auto-preempts the
proven path (guarded so it cannot regress torch/onnx). Loads the ONNX
export through tinygrad's frontend wrapped to the existing
model(**enc).logits contract so _nli_batch is byte-unchanged.

bench/scripts/nli_backend_ab.py + make bench-nli-backends: deterministic
A/B, gate is numerical agreement with the torch reference first,
latency second (a divergent engine = a different shadow signal = a
different nli_policy_hash). Instrument is honest — reports a requested
backend as unavailable rather than relabelling a fallback's numbers.

First CPU-smoke run already quantified that the deployed §7 #22 int8
export diverges Δmax≈0.42 from torch — the immunity property made
measurable, not a defect. Real tinygrad numbers pending a producer-box
run (tinygrad not an arborist dep; frontend op-coverage for the large
MNLI checkpoints unverified by design).

docs/onnx-vendor-capture-immunity.md: why the model-in-proof-path cage
makes the inference engine an interchangeable sidecar, never a trust
dependency — public-domain positioning capital. Indexed in CLAUDE.md.

Full suite 2498 passed (identical to baseline); 24/24 NLI tests green.
2026-05-19 12:34:04 -04:00
1fdae8830a
docs(#000057): correct judge design — strong SOTA external judge (fox), not deterministic-only
I over-applied a proof-path rule. "No LLM-as-judge" guards Arborist's
*verifier* (an LLM in the proof path = the circularity Arborist
kills; #000049's poor reliability is a proof-path-model constraint).
The control experiment's judge is external science — outside BOTH
arms, scoring post-hoc, touching neither system's internals — so it
cannot break the experiment. fox: use a strong SOTA model
(stronger than both systems under test), blinded + reference-
grounded + transcript-logged. This lifts the wrongly-imposed
atomic-fact-only limit (judge handles essay grounding; #000049's
exclusion was right for the proof path, wrong for external science);
deterministic gold-key demoted to a cheap atomic cross-check.
Still fox calls: fixture population, which SOTA judge (API
cost/egress), spend. Scaffold; no build past gate-1.
2026-05-19 08:33:36 -04:00
deb388a39b
docs(#000057): fold in fox's control-arm ruling — Hermes-solo vs Arborist, external deterministic gold-fact judge
The review's strongest point (§4.1) + fox: every measurement so far
is WITHIN Arborist — no control arm. Folded into #000057 (not a new
ticket): control = Hermes-solo; judge external/deterministic/
paraphrase-tolerant via a mined gold-fact answer key (resolves
circularity + no-LLM-judge + paraphrase at once); headline metric =
fabrication-vs-honest-abstention delta, not raw accuracy (common-
knowledge fixture would falsely show null — parametric memory).
Smallest-proof reorder: v1 = single-shot Hermes-solo vs Arborist on
a fabrication-bait atomic-fact fixture; recursive-drift loop is v2,
gated on v1. Atomic-fact only; essay-grounding = #000049's unsolved
NLI, OUT. Still fox calls: fixture population, gold-key shapes,
spend. Scaffold; no build past gate-1.
2026-05-19 08:26:14 -04:00
7100f7277b
docs(#000057): scaffold — minimal deterministic recursive-drift A/B (Hamming de-novo review)
The 2026-05-19 GPT-5.5 Hamming-framed review's ONE arborist-scoped,
ticket-worthy nugget: prove the Merkle-Providence-Reverse-RAG
whitepaper's headline claim (untracked evidence loss -> unbounded
recursive drift; witness-preserving state bounds it). Scaffold only,
awaiting fox go/no-go on scope.

Discipline encoded from the 2026-05-18 precedent (a grand target is
unfalsifiable until the instrument can resolve it — four hypotheses
died, only the deterministic mined-recall instrument broke it):
instrument-before-experiment, ONE task not eight, minimal ON/OFF
A/B, non-claims pinned (necessary substrate, NOT AGI).

Everything else in the review (rename, corpus hierarchy, IQ/talent,
ToE/Riemann/identity/geopolitics) deliberately NOT ticketed —
narrative/positioning, not arborist engineering; don't-proliferate.
Exactly one ticket. Next ID 000057 -> 000058 (same commit).
2026-05-19 08:14:04 -04:00
5d43fdc037
docs(#000056): firm cross-language numbers + correct the French figure
The fr-no-mask sweep (2026-05-18) corrected an over-pessimistic read:
French was reported 47% but that was the failed-mask artifact; honest
fr no-mask is 61%. §9 + index now carry the firmed n=1 table (EN 85%
· es-nomask 71% · es+mask 65% · fr-nomask 61% · fr+mask 47%), the
comparator-corrected verdict (sandwich is a ~0%→61-71% net win vs the
real no-support baseline; the −14/−24pp is vs native English, not a
regression), and the entity-mask lever's confirmed net-negative
status (default-OFF). Doc-only; no code change.
2026-05-18 14:23:49 -04:00
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
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
c2c06c971e
#000054 index row: Phase-2 landed ce855db + bench result recorded 2026-05-13 10:28:19 -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
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
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
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
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