arborist/tests
russell@unturf.com 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
..
crawler fix+perf: fast-mode ignores crawl-delay; shared session; drop HEAD 2026-05-22 06:55:32 -04:00
fixtures verify: strip wikitext from context before substring matching 2026-04-28 15:48:07 -04:00
__init__.py phase 0 explore: aborist core + sources + distill + evict 2026-04-27 07:53:18 -04:00
test_accent_fold.py feat(retrieval): accent-fold (+30pp recall@1) + fold-search factory hardening 2026-05-18 19:23:22 -04:00
test_aliases.py tests/aliases: gap-fill list_term_aliases + tokenizer helpers (10 new tests) 2026-05-10 12:35:33 -04:00
test_anchor_prg.py ticket #000035: flip φ_PRG counter big-endian → little-endian to match v7 TLV 2026-05-11 07:47:35 -04:00
test_audit_chain_concurrency.py store: append_audit atomic head-read+insert — no audit-chain forks 2026-05-11 08:29:57 -04:00
test_bench_batteries.py #000048 step 2.4 — parse_pointer_claims clause segmentation 2026-05-11 17:09:06 -04:00
test_bench_qa_sweep.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_burn.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_burn_doc.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_canonical_cache.py #000027 + #000028: canonical projections persist; STRICT-WITNESSED reachable 2026-05-09 11:37:06 -04:00
test_canonical_projection.py ticket #000030 Phases 1+2: algebra-symbolic@v1 + calculus-derivative@v1 2026-05-09 12:35:18 -04:00
test_capital.py capital: land ticket #000020 (8-capital-form cost ledger) 2026-05-07 16:41:48 -04:00
test_claim_lattice.py #000048 step 2.4 — parse_pointer_claims clause segmentation 2026-05-11 17:09:06 -04:00
test_claim_pack.py ticket #000029: claim-pack source for axiom/theorem JSON bundles 2026-05-09 11:44:08 -04:00
test_cli_render.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_cli_session.py tests: unit + integration + functional coverage for this session's surface 2026-05-07 21:15:14 -04:00
test_cli_smoke.py arborist controller-events: read-only inspector for #000037 Phase 2 rows 2026-05-10 19:25:54 -04:00
test_cold_object.py #000061: fold 3 gaps from Dav1d review (manifest/latest, license_class, cold_pending) 2026-05-26 10:50:57 -04:00
test_cold_object_boto3.py feat: #000061 cold-pack distribution tier (boto3 S3-compat + DVD-R safe-fit) 2026-05-25 20:23:44 -04:00
test_cold_unpack_routed.py #53: pre-size chunks rows at INSERT to skip phase-2 page splits 2026-05-27 06:09:21 -04:00
test_compress.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_concepts.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_concepts_extract.py #000054: acronym-parens concept extractor (closes abbreviation→expansion retrieval gap) 2026-05-13 07:00:25 -04:00
test_content_tokens.py #000053: acronym-aware verifier content tokens 2026-05-12 19:41:47 -04:00
test_corpus_shard_count_meta.py #000065 step 1: routing helper + meta field + pre-migration snapshot 2026-05-26 13:13:44 -04:00
test_crosslang_guard.py feat: cross-language Q&A (Operation Sandwich) + Windows quickstart — all default-OFF 2026-05-18 12:12:23 -04:00
test_dag.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_demo_plot.py fan-out: witness audit + 5F extractor + function-sampled demo + docs 2026-05-09 13:19:30 -04:00
test_directives.py #000027 + #000028: canonical projections persist; STRICT-WITNESSED reachable 2026-05-09 11:37:06 -04:00
test_distill.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_distill_recursive.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_doc_counts.py ticket #000044: AUTOCOUNT doc-drift discipline + code-fence parser fix 2026-05-10 18:24:50 -04:00
test_embed.py feat: arborist.embed — supported library-embedding surface 2026-05-22 13:03:15 -04:00
test_entity_mask.py feat: cross-language Q&A (Operation Sandwich) + Windows quickstart — all default-OFF 2026-05-18 12:12:23 -04:00
test_evict.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_fivef_threshold_calibration.py #000047 — close: delta_aggregator knob on ForkScore (Option D) 2026-05-11 08:27:38 -04:00
test_fork_score.py #000047 — close: delta_aggregator knob on ForkScore (Option D) 2026-05-11 08:27:38 -04:00
test_frame.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_grok_source.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_honorific_brit_fold.py feat(retrieval): honorific-fold + brit-fold — fold-search batch 3 (both measured wins) 2026-05-18 19:32:03 -04:00
test_html_source.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_ingest.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_inspect.py test: fix the new acronym sub-cases — DNA-stands-for-DNA doesn't use a recognized copula (drop bogus sub-assertion); add FBI-acronym variant to demonstrate all-caps coverage 2026-05-13 13:10:54 -04:00
test_journal.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_judge_code.py feat(#000057): stronger code judge — resolve HYBRID with verified quote + on-topic 2026-05-21 13:10:01 -04:00
test_keys.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_llm_context_base.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_loss_report.py loss_report: land ticket #000022 (adapter LossReport sidecar) 2026-05-07 17:58:50 -04:00
test_memory_root.py memory: land ticket #000017 (memory-root lifelong learning summary) 2026-05-07 16:46:41 -04:00
test_merkle.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_mesh.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_mesh_aead.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_mesh_chain.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_mesh_cli.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_mesh_cli_pull.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_mesh_wire.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_mesh_wire_e2e.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_metacognition.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_migrate_executor.py #000065 follow-up #48: WAL checkpoint between executor phases 2026-05-26 15:34:40 -04:00
test_migrate_planner.py #000065 step 2: hydration planner (pure compute, no execution yet) 2026-05-26 13:21:18 -04:00
test_migration_audit_mode.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_missed_answer_guard.py #000068 Phase 1: verifier-blind missed-answer falsification guard 2026-05-27 10:14:51 -04:00
test_nli_shadow.py #000049 §7 #22: speedup (batch + cuda auto-detect + ONNX-int8 export) + the gate-item-4 verdict at proper n 2026-05-12 17:21:32 -04:00
test_numeral_fold.py feat(retrieval): numeral-fold (ordinal-word <-> Roman) + mined ground-truth eval instrument 2026-05-18 15:16:10 -04:00
test_operation_sandwich.py feat: cross-language Q&A (Operation Sandwich) + Windows quickstart — all default-OFF 2026-05-18 12:12:23 -04:00
test_phi_alignment_probe.py tests: rename v8 → substrate + close 9-item checklist gaps across 3 files 2026-05-10 13:35:52 -04:00
test_pi_star.py fan-out: 5 π* graduations close the registry chapter 2026-05-09 13:04:43 -04:00
test_pi_star_algebra_symbolic.py ticket #000030 Phases 1+2: algebra-symbolic@v1 + calculus-derivative@v1 2026-05-09 12:35:18 -04:00
test_pi_star_algebra_symbolic_simplified.py ticket #000030 Phases 1b+3 + open #000031 2026-05-09 12:50:46 -04:00
test_pi_star_arithmetic.py tests/pi_star_arithmetic: 56 KATs for exact-rational arithmetic kernel 2026-05-10 15:54:37 -04:00
test_pi_star_calculus_derivative.py ticket #000030 Phases 1+2: algebra-symbolic@v1 + calculus-derivative@v1 2026-05-09 12:35:18 -04:00
test_pi_star_calculus_integral.py ticket #000030 Phases 1b+3 + open #000031 2026-05-09 12:50:46 -04:00
test_pi_star_code.py tests/pi_star_code: 32 KATs for Python-AST kernel 2026-05-10 15:54:49 -04:00
test_pi_star_combinatorics.py ticket #000032: combinatorics@v1 π* (pure-integer counting kernel) 2026-05-09 13:20:29 -04:00
test_pi_star_compositions.py fan-out: close #000030 · composition fixtures · witness end-to-end 2026-05-09 13:29:59 -04:00
test_pi_star_logic.py tests/pi_star_logic: 53 KATs for propositional CNF kernel 2026-05-10 15:54:43 -04:00
test_pi_star_phase_3_to_7.py fan-out: 5 π* graduations close the registry chapter 2026-05-09 13:04:43 -04:00
test_pi_star_protocol_and_registry.py tests/pi_star: 21 tests for protocol + registry (foundation, was untested) 2026-05-10 12:44:13 -04:00
test_pi_star_tabular.py fan-out: 5 π* graduations close the registry chapter 2026-05-09 13:04:43 -04:00
test_pi_star_time_series.py tests/pi_star_time_series: 35 KATs for temporal-signal kernel 2026-05-10 15:54:55 -04:00
test_prometheus.py #000037 Phase 1.c: kernel_cost/llm_cost split + sweep_weights profile 2026-05-10 18:29:37 -04:00
test_prometheus_audit.py #000037 follow-through: persist falsification proposals + harvest live stream 2026-05-10 19:40:00 -04:00
test_prometheus_trigger_probe.py #000012 Phase 1c follow-through: wire #000037 §12 Trigger 1 probe to fork_score_branches 2026-05-11 06:56:09 -04:00
test_providence_source.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_qa.py qa: providence_cache INSERT — ON CONFLICT(cache_key) DO NOTHING 2026-05-11 17:29:12 -04:00
test_qa_progress.py tests/qa/progress: 31 tests for Progress emitter (was zero coverage) 2026-05-10 12:45:32 -04:00
test_qa_prompts.py tests/qa/prompts: 20 tests pinning load-bearing system prompts (was zero coverage) 2026-05-10 12:50:20 -04:00
test_qa_quality_live.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_quantifier_caps.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_quantifier_classifier.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_quantifier_phase4.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_quantifier_reminder.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_query.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_qwen_thinking_default.py fix: Qwen3 defaults to enable_thinking=False — was returning empty answers 2026-05-21 12:50:05 -04:00
test_reclassify.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_relevance_shadow.py #000052: more tests for §3.1 + §3.2 — bench-max the detectors against real data 2026-05-13 12:38:09 -04:00
test_repair.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_resume.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_search_fts5.py search/fts5: progressive-AND fallback + DF filter at OR-pool 2026-05-09 18:31:24 -04:00
test_search_vec.py ticket #000039: --quant {float32,int8} + int8 head-to-head 2026-05-11 13:16:51 -04:00
test_selfmodel.py selfmodel: land ticket #000014 (identity record + falsification) 2026-05-07 16:36:34 -04:00
test_selfmodel_chain.py #000025 §10.11 + §10.13 + §10.14 — close the 5F battery 2026-05-11 07:41:37 -04:00
test_session_integration.py #000025 Phase 1e: 5F falsification motif coverage (§10.12 closed) 2026-05-10 16:04:34 -04:00
test_session_migrations.py tests: unit + integration + functional coverage for this session's surface 2026-05-07 21:15:14 -04:00
test_shard_routing.py #000065 step 1: routing helper + meta field + pre-migration snapshot 2026-05-26 13:13:44 -04:00
test_snapshot.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_soft_preflight.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_store_migration_concurrency.py store: idempotent forward migrations — survive concurrent connect() 2026-05-11 07:28:35 -04:00
test_store_migration_memoization.py store: idempotent forward migrations — survive concurrent connect() 2026-05-11 07:28:35 -04:00
test_substrate_fork_score.py tests: rename v8 → substrate + close 9-item checklist gaps across 3 files 2026-05-10 13:35:52 -04:00
test_t3_bound_calculator.py ticket #000036: add KAT-regen tooling + close 2026-05-11 08:02:25 -04:00
test_tasks_runner.py feat: cross-language Q&A (Operation Sandwich) + Windows quickstart — all default-OFF 2026-05-18 12:12:23 -04:00
test_textbook_tex.py textbooks: TeX-source ingest closes pillars I + IV (Hilbert + Boole) 2026-05-09 16:06:53 -04:00
test_textbooks_manifest.py tests/textbooks_manifest: 43 tests for license-discipline gate (was zero coverage) 2026-05-10 13:02:17 -04:00
test_tfidf.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_title_token_provenance.py fix(provenance): bind title-token fold set into run-DAG retrieval plan (Dav1d review 2026-05-19) 2026-05-19 07:34:16 -04:00
test_vcs_source.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_verify.py #000048 step 2.1 — verify_quotes entity salient-token-disagreement gate 2026-05-11 13:57:45 -04:00
test_verify_json.py feat(#000057): arborist+qwen enablement — multi-engine JSON-schema + per-model extras pass-through 2026-05-19 19:53:00 -04:00
test_version_lineage.py feat: version-lineage report in the crawler ingestion pipeline 2026-05-21 18:22:45 -04:00
test_versioned_ingest.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_warrant.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_warrant_authorship.py fan-out: warrant ladder wiring · witness follow-ups · 5F Phase 1d 2026-05-09 12:42:56 -04:00
test_warrant_chain.py ticket #000031 Phase 3: warrant-chain-aware verifier suppresses WARRANT_MISSING 2026-05-10 09:17:48 -04:00
test_warrant_resolver.py ticket #000031 follow-ups B-1 + B-2: alias attribution + source-side title author 2026-05-10 09:35:49 -04:00
test_watt_cogs.py feat(#000057): bench/watt_calibrate.py — separate prefill vs decode energy 2026-05-21 11:48:36 -04:00
test_weights.py #000047 — close: delta_aggregator knob on ForkScore (Option D) 2026-05-11 08:27:38 -04:00
test_wikipedia_old.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_wikipedia_xml.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_wikitext.py aborist/arborist 2026-05-07 09:31:49 -04:00
test_witness.py fan-out: warrant ladder wiring · witness follow-ups · 5F Phase 1d 2026-05-09 12:42:56 -04:00
test_witness_to_5f.py fan-out: witness audit + 5F extractor + function-sampled demo + docs 2026-05-09 13:19:30 -04:00
test_world_namespace.py #000013 closed: v7-W spatial-temporal substrate paper + namespace 2026-05-09 15:00:05 -04:00