modified: .gitlab-ci.yml modified: bench/qa_questions.txt modified: bench/qa_sweep.py modified: bench/run.sh modified: docs/TICKETS.md modified: docs/_source/README.md modified: docs/_source/_ext/makefile_targets.py modified: docs/_source/api/cli.rst modified: docs/_source/api/distill.rst modified: docs/_source/api/mesh.rst modified: docs/_source/api/qa.rst modified: docs/_source/api/retrieval.rst modified: docs/_source/api/storage.rst modified: docs/_source/api/substrate.rst modified: docs/_source/concepts.rst modified: docs/_source/conf.py modified: docs/_source/cookbook.rst modified: docs/_source/index.rst modified: docs/_source/license.rst modified: docs/_source/quickstart.rst modified: docs/bench-maxing.md modified: docs/benchmarks.md modified: docs/cti-architecture.md modified: docs/diagrams/aborist-modules.dot modified: docs/diagrams/aborist-modules.svg modified: docs/diagrams/mesh-data-flow.dot modified: docs/diagrams/mesh-epoch-lifecycle.dot modified: docs/diagrams/mesh-epoch-lifecycle.svg modified: docs/diagrams/mesh-group-decisions.dot modified: docs/diagrams/mesh-group-decisions.svg modified: docs/diagrams/mesh-identity-stack.dot modified: docs/diagrams/mesh-secret-envelope.dot modified: docs/mesh.md modified: docs/qa-modes-bench.md modified: docs/seven-point-program.md modified: docs/tickets/ticket-000001-retrieval-keywords-audit-gap.md modified: docs/tickets/ticket-000002-reference-frame-polarity-contract.md modified: docs/tickets/ticket-000003-anchor-class-warrant.md modified: docs/tickets/ticket-000005-label-ladder-migration.md modified: docs/tickets/ticket-000006-bench-emergent-findings.md modified: docs/tickets/ticket-000007-query-layer-hyphen-fold.md modified: docs/tickets/ticket-000008-broad-quantifier-preflight-guard.md modified: docs/tickets/ticket-000009-quantifier-preflight-dag-binding.md modified: docs/tickets/ticket-000010-metacognition-preflight-guard.md modified: docs/tickets/ticket-000011-soft-preflight-hint-sidecar.md modified: scripts/backfill_concepts.py modified: scripts/bench_emergent.py modified: tests/crawler/test_async_web_fetcher.py modified: tests/crawler/test_bridge.py modified: tests/crawler/test_web_fetch.py modified: tests/test_bench_qa_sweep.py modified: tests/test_burn.py modified: tests/test_burn_doc.py modified: tests/test_claim_lattice.py modified: tests/test_cli_render.py modified: tests/test_compress.py modified: tests/test_concepts.py modified: tests/test_dag.py modified: tests/test_directives.py modified: tests/test_distill.py modified: tests/test_distill_recursive.py modified: tests/test_evict.py modified: tests/test_frame.py modified: tests/test_grok_source.py modified: tests/test_html_source.py modified: tests/test_ingest.py modified: tests/test_inspect.py modified: tests/test_journal.py modified: tests/test_keys.py modified: tests/test_llm_context_base.py modified: tests/test_merkle.py modified: tests/test_mesh.py modified: tests/test_mesh_aead.py modified: tests/test_mesh_chain.py modified: tests/test_mesh_cli.py modified: tests/test_mesh_cli_pull.py modified: tests/test_mesh_wire.py modified: tests/test_mesh_wire_e2e.py modified: tests/test_metacognition.py modified: tests/test_migration_audit_mode.py modified: tests/test_providence_source.py modified: tests/test_qa.py modified: tests/test_qa_quality_live.py modified: tests/test_quantifier_caps.py modified: tests/test_quantifier_classifier.py modified: tests/test_quantifier_phase4.py modified: tests/test_quantifier_reminder.py modified: tests/test_query.py modified: tests/test_reclassify.py modified: tests/test_repair.py modified: tests/test_resume.py modified: tests/test_snapshot.py modified: tests/test_soft_preflight.py modified: tests/test_tfidf.py modified: tests/test_vcs_source.py modified: tests/test_verify.py modified: tests/test_verify_json.py modified: tests/test_versioned_ingest.py modified: tests/test_warrant.py modified: tests/test_wikipedia_old.py modified: tests/test_wikipedia_xml.py modified: tests/test_wikitext.py
12 KiB
Ticket #000011 — SOFT_PREFLIGHT_HINT model-assisted sidecar
Status: closed · landed 2026-05-04 (zero-shot, full
implementation per §13)
Opened: 2026-05-04
Scope: Add a model-assisted preflight sidecar that augments the
deterministic detectors from #000010 with an LLM-driven shape
classifier. Strict guardrail per #000010 §18 / source doc: the
sidecar produces ONLY soft hints labeled SOFT_PREFLIGHT_HINT; it
cannot create PREFLIGHT_OK or PREFLIGHT_BLOCKED without
deterministic support. Hard rule (D1) preserved.
Audience: fox + future blackops shifts.
Hard constraint: Same as #000010 §1: no schema_version,
canonicalization_version, or chunking_version bumps; pure
additive policy folded into governance_policy_hash. The sidecar
NEVER alters the verifier's hard path; sidecar output lives on
result-dict + bench rows + the run-DAG preflight payload but is
clearly tagged SOFT_* so audit replay can distinguish hard from
soft signal.
1. Premise
The deterministic detectors from #000010 (temporal, contradiction, false-premise-lite, out-of-corpus) are conservative by design — lexical pattern matching catches obvious shapes & misses subtle ones. A model-assisted preflight could catch:
- Subtle false premises that don't match the lite presupposition patterns (e.g. "Why does the Federal Reserve refuse to audit itself?" — false premise hidden in "refuse").
- Multi-hop contradictions invisible to lexical pair matching.
- Style-of-reasoning needs (compare/contrast, summarize, list) that don't surface in the quantifier classifier.
- Implicit time-anchors ("now that the AI bubble has popped") the lexical temporal detector misses.
The architectural rule from #000010 §18 forbids putting an LLM in the hard preflight path. But a sidecar — soft signal, never gates admissibility, can be wrong without breaking guarantees — is admissible under the same separation-of-concerns the substrate already maintains for hard vs soft hashes.
2. What the sidecar produces
A separate SoftPreflightHint dataclass distinct from QuestionState:
@dataclass(frozen=True)
class SoftPreflightHint:
raw_question: str
sidecar_version: str # e.g. "soft-preflight-v0.1"
classifier_label: str # e.g. SOFT_FALSE_PREMISE_SUSPECTED
confidence: float # 0.0-1.0, never used for hard decisions
rationale: str # one-line explanation from the model
timestamp: int # monotonic for replay debugging
model_profile_id: str # which model produced the hint
The hint always carries the SOFT_ prefix on its classifier_label
so it can never be mistaken for a deterministic verdict by:
- The audit-line tail renderer in
arborist/cli.py:_render_warrant_tail - The verifier (which doesn't read sidecar fields anyway)
- Bench aggregations
- Operators inspecting bench JSONL or run-DAG blobs
3. Where it lives
arborist/qa/soft_preflight.py — sidecar implementation
(new module)
Mirrors arborist/qa/inspect.py (the existing read-only sidecar
diagnostic for span classification) — same architectural pattern:
soft signal, never enters proof path, never written to providence
cache, never bumps governance hash on use.
Wired into query() and runner.ask() as an optional pre-LLM call
gated on soft_preflight_enabled (default False). Adds ~200ms of
latency per call (one extra LLM round-trip on the local Hermes
endpoint).
4. Cache binding
Soft sidecar hints DO NOT enter governance_policy_hash. Two cache
rows with the same hard preflight contract but different soft hints
SHARE a cache_key — sidecar disagreement is not a cache split.
Soft hints DO surface on the run-DAG preflight payload's
question_state.soft_preflight_hint field (new optional sub-field).
The hint is hash-bound for audit replay, but two runs with different
sidecar outputs can still hit the same cache. This is intentional:
audit can see what soft signal the sidecar emitted; cache identity
remains driven by the hard policy.
5. Implementation sketch
# arborist/qa/soft_preflight.py
def soft_preflight_question(
question: str,
*,
chat_client: ChatClient,
model_id: str,
policy: dict,
) -> SoftPreflightHint:
"""Call the LLM to produce a soft preflight hint. Pure
sidecar: caller MUST treat the output as advisory only.
Never enters the verifier, never gates admissibility."""
if not policy.get("soft_preflight_enabled", False):
return _stub_hint("SOFT_DISABLED", "sidecar off")
# Short, focused system prompt asking the model to classify
# the question shape from a fixed enum:
# SOFT_WELL_FORMED
# SOFT_FALSE_PREMISE_SUSPECTED
# SOFT_CONTRADICTION_SUSPECTED
# SOFT_TIME_SENSITIVE
# SOFT_SCOPE_AMBIGUOUS
# SOFT_OUT_OF_CORPUS_LIKELY
# ...
# Return one of the enum tokens + a one-line rationale.
# Constrained generation (max_tokens=128, temperature=0.0
# for deterministic-ish output, top_p=1.0).
raw = chat_client.chat_completion(
messages=[
{"role": "system", "content": SOFT_PREFLIGHT_SYSTEM_PROMPT},
{"role": "user", "content": question},
],
model=model_id,
temperature=0.0,
max_tokens=128,
)
label, rationale = _parse_soft_hint(raw)
return SoftPreflightHint(
raw_question=question,
sidecar_version="soft-preflight-v0.1",
classifier_label=f"SOFT_{label.upper()}",
confidence=0.5, # soft signals never claim hard confidence
rationale=rationale,
timestamp=int(time.monotonic_ns()),
model_profile_id=model_id,
)
6. Integration points
arborist/qa/query.py— callsoft_preflight_question()afterpreflight_question()(the hard call) but before the main LLM call. Soft hint surfaces on result dict assoft_preflight_hint; merges into the run-DAGpreflightstage payload as a sub-field ofquestion_state.arborist/qa/runner.py— same wiring.arborist/cli.py— new--soft-preflightflag (per-call override; default off matches policy default).bench/qa_sweep.py— bench rows pick upsoft_preflight_labelsoft_preflight_confidenceas bounded-projection fields.
arborist/cli.py:_render_warrant_tail— soft hints render as· soft: <label>on the audit-line (clearly differentiated from the hard· false premiseetc. tails). Operator can tell at a glance whether a tail is hard or soft.
7. Bench plan
After the sidecar lands:
- Soft-only A/B on the metacog-trigger fixture (#000010
§13.1 + the
bench/qa_questions_metacog_subset.txtfrom the 2026-05-04 work). Measure: does the soft sidecar agree with the hard detectors on the cases where the hard detectors fire? Disagreement rate ≤ 10% signals the sidecar is reliable enough to surface to operators. - Soft-on subtle-cases A/B with hand-crafted fixtures of subtle false premises / multi-hop contradictions that DON'T trigger the hard detectors. Measure: does the sidecar add coverage on shapes the hard detectors miss?
- Latency cost — the extra ~200ms per call multiplied by bench cycle counts. Bench cycle latency budget is currently ~17-35s/call (Hermes); adding 200ms is ~1% overhead. Measure to confirm.
8. What this ticket does NOT do
- Does NOT enter the verifier proof path. D1 preserved.
- Does NOT bump
schema_version/canonicalization_version/chunking_version. Pure additive. - Does NOT change cache identity. Soft hints don't fold into
governance_policy_hash. - Does NOT replace the hard detectors. Hard detectors remain
the source of truth for
PREFLIGHT_OK/PREFLIGHT_BLOCKED. - Does NOT promote a soft hint to hard without deterministic
support. The sidecar can claim
SOFT_FALSE_PREMISE_SUSPECTEDbut the hard detector must agree beforefalse_premise_suspectedenterslogical_statuses.
9. Open questions
- Use a separate cheap model for the sidecar (e.g. Hermes-3 itself, or a smaller model) vs the same model that produces the answer? Bench data needed.
- One-call vs streaming-batch? At 200ms/call across a 75-question bench (n=3), one-call adds ~22s; batched (e.g. 5 questions at once) could compress this significantly but complicates the per-row provenance binding.
- Confidence calibration — initial proposal is
0.5literal for any soft hint. Future refinement might calibrate via empirical agreement-rate with the hard detectors.
10. Status
Closed · landed 2026-05-04 in the same commit batch as the
metacog-trigger fixture expansion + --show-preflight full clause
render + latency profile. Source-doc reference: ticket #000010
§18 + ~/Downloads/meta-cognition_for_hermes(1).txt §18.
The deterministic substrate from #000010 + #000009 is the provable foundation. SOFT_PREFLIGHT_HINT is an enrichment layer that operates strictly within the substrate's "hard hash never enters the proof path" rule (cf. whitepaper §13 decision 8).
11. What landed
-
arborist/qa/soft_preflight.py—SoftPreflightHintdataclass +soft_preflight_question()pure function. 9 canonical labels (SOFT_WELL_FORMED,SOFT_FALSE_PREMISE_SUSPECTED,SOFT_CONTRADICTION_SUSPECTED,SOFT_TIME_SENSITIVE,SOFT_SCOPE_AMBIGUOUS,SOFT_OUT_OF_CORPUS_LIKELY,SOFT_BROAD_QUANTIFIER,SOFT_MULTI_HOP_REASONING,SOFT_SUBJECTIVE) plus stub states (SOFT_DISABLED,SOFT_PARSE_FAIL). Constrained- generation prompt asking the model to pick ONE label + a one-line rationale. Failure-closed across every parse path (raises →SOFT_PARSE_FAIL, drift →SOFT_PARSE_FAIL).SOFT_PREFLIGHT_VERSION = "soft-preflight-v0.1". -
arborist/qa/query.py— wired into the post-classifier / pre-retrieval segment. One short LLM call (~200ms median), result surfaces assoft_preflight_hinton the result dictsoft_preflight_msin the timings dict.
-
arborist/qa/runner.py+arborist/qa/query.py—soft_preflight_enabled: Falsepolicy default; cache row identity unchanged (NOT folded into_VERIFIER_POLICY_FIELDSper §4 — soft hints don't gate cache identity). -
arborist/cli.py—--soft-preflightflag onarborist query. Audit-line tail renders soft hints as· soft: <label>(e.g.· soft: time sensitive) — distinct from hard tails so operators see the signal separation at a glance. SOFT_DISABLED / SOFT_PARSE_FAIL / SOFT_WELL_FORMED suppress (no actionable signal). -
tests/test_soft_preflight.py— 25 new tests pinning: default-OFF behavior, parse-failure modes, label normalization (SOFT_ prefix enforced even when model drops it), all 8 actionable labels round-trip, fail-closed on client exceptions, dataclass JSON round-trip, rationale-length cap.
12. Live verification
End-to-end smoke test on When did Mr. Burns become Homer's biological father? with --soft-preflight:
EVIDENCE-WARRANTED · via claim_lattice · false premise · soft: time sensitive 1/1 16.4s
Both signals compose: hard · false premise from #000010
deterministic detector, soft · soft: time sensitive from
#000011 sidecar. The model classified a different shape than
the hard detector — by design (soft hints are independent
advisory signals, not redundant with the hard layer).
13. Bench plan (deferred)
Per §7 of this ticket — soft-only A/B against the metacog-
trigger fixture (bench/qa_questions_metacog_subset.txt —
expanded 2026-05-04 to 28 questions), measure agreement-rate
between soft sidecar and hard detectors. Disagreement ≤ 10%
signals the sidecar is reliable enough for default-on
consideration. This bench is queued but not run in the same
commit cycle as implementation.