fix Leo broad source intake truth (#124)
Some checks are pending
CI / lint-and-test (push) Waiting to run

This commit is contained in:
twentyOne2x 2026-07-13 20:59:28 +02:00 committed by GitHub
parent ee48f82f06
commit 5dfcd32c34
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 79 additions and 11 deletions

View file

@ -504,7 +504,27 @@ def operational_contracts(
None,
)
source_terms = ("document", "pdf", "tweet", "attachment", "ingest", "intake", "absorb", "extract")
if any(term in lowered for term in source_terms) and primary_direct_intent is None:
broad_source_object = any(term in lowered for term in ("report", "article", "file", "url", "link"))
broad_source_action = any(
term in lowered
for term in (
"send",
"hand",
"drop",
"upload",
"learn",
"absorb",
"ingest",
"extract",
"stage",
"add",
"make it part",
)
)
source_intake_question = any(term in lowered for term in source_terms) or (
broad_source_object and broad_source_action
)
if source_intake_question and primary_direct_intent is None:
contracts.append(
{
"id": "source_intake",
@ -514,8 +534,9 @@ def operational_contracts(
),
"capability_tier": "VPS-local prepared-input compiler and pending-review staging",
"safe_without_apply_authorization": [
"retain artifact plus URL or storage_path plus content hash",
"extract candidates into a pending_review proposal packet",
"prepare and retain the artifact, UTF-8 extracted text, extraction manifest, URL or storage_path "
"locator, and content hash",
"run teleo-kb propose-source to validate and stage a pending_review proposal",
],
"approval_begins": "before guarded canonical public.* apply, not before mechanical capture/staging",
"current_public_sources_columns": list(schema.get("sources", ())),
@ -878,17 +899,20 @@ def compile_operational_response(contracts: list[dict[str, Any]]) -> str | None:
source = by_id.get("source_intake")
if source:
safe_steps = [str(item) for item in source.get("safe_without_apply_authorization") or []]
retain_step = safe_steps[0] if safe_steps else "retain the artifact plus its locator and content hash"
stage_step = safe_steps[1] if len(safe_steps) > 1 else "stage candidates in a pending_review proposal"
retain_step = safe_steps[0] if safe_steps else "prepare the artifact, extracted text, and manifest"
stage_step = safe_steps[1] if len(safe_steps) > 1 else "stage a pending_review proposal"
return (
f"- {source.get('required_lead')} Immediately {retain_step}; retain provenance for each PDF, Telegram "
"message, and tweet. A filename, chat label, attachment reference, or source_ref is not source identity.\n\n"
f"- {stage_step}. Deduplicate overlapping candidate claims, preserve evidence excerpts, source-specific "
"caveats, uncertainty, and contradictions. Candidates are not canonical until reviewed and applied: create "
"no public.sources or other public.* rows during capture or staging.\n\n"
f"- {source.get('required_lead')} Sending a report in chat does not by itself create a proposal or "
"persistent knowledge. I can analyze content available in this conversation, but chat attachment "
"capture and extraction are not connected to the staging command.\n\n"
f"- The live bounded path is to {retain_step}, then {stage_step}. It writes only "
"kb_stage.kb_proposals. A chat label, filename, attachment reference, or source_ref is not provenance. "
"Before review, deduplicate overlaps and retain exact excerpts, source caveats, uncertainty, and "
"contradictory interpretations. Candidates are not canonical until reviewed and applied, and no "
"public.sources or other public.* rows are created during staging.\n\n"
f"- Explicit approval begins {source.get('approval_begins')}. Receipt: locator and content hash, proposal ID/"
"status, reviewed payload, applied_at, created row IDs, and postflight readback. Next proof-changing "
"follow-up: run the retained artifact through the staging compiler, then review its typed candidates."
"follow-up: prepare the three inputs, run teleo-kb propose-source, then review its typed candidates."
)
named_packet = by_id.get("named_packet_readback")

View file

@ -83,8 +83,27 @@ def _requires_database_truth(query: str) -> bool:
named_packet_question = "helmer" in lowered and any(
term in lowered for term in ("7 powers", "seven powers", "powers framework", "powers packet")
)
broad_source_intake_question = any(
term in lowered for term in ("report", "article", "file", "url", "link")
) and any(
term in lowered
for term in (
"send",
"hand",
"drop",
"upload",
"learn",
"absorb",
"ingest",
"extract",
"stage",
"add",
"make it part",
)
)
return bool(
named_packet_question
or broad_source_intake_question
or ("telegram" in lowered and "gatewayrunner" in lowered)
or re.search(
r"\b(?:databases?|db|knowledge bases?|kb|proposals?|canonical|source_ref|source rows?|"

View file

@ -170,6 +170,16 @@ def test_source_validator_accepts_explicit_schema_and_canonical_write_prohibitio
assert module.response_contract_issues(response, contracts) == []
def test_broad_report_learning_question_requires_database_truth() -> None:
module = load_plugin()
query = (
"If I send you a report here, can you learn it into your knowledge base and make it part of what you know? "
"What actually happens right now?"
)
assert module._requires_database_truth(query) is True
def test_plugin_replaces_memory_only_status_answer_with_exact_live_db_receipt(tmp_path: Path, monkeypatch) -> None:
module = load_plugin()
home = tmp_path / "profile"

View file

@ -220,6 +220,21 @@ def test_vps_bridge_operational_contracts_are_query_specific_and_schema_exact()
assert source["current_public_sources_columns"] == list(module.CURRENT_PUBLIC_SCHEMA["sources"])
assert "author/title/publisher/publication date are current public.sources columns" in source["must_not_claim"]
broad_source_query = (
"If I send you a report here, can you learn it into your knowledge base and make it part of what you know? "
"What actually happens right now?"
)
broad_source_contracts = {
item["id"]: item for item in module.operational_contracts(broad_source_query)
}
assert "source_intake" in broad_source_contracts
broad_source_response = module.compile_operational_response(list(broad_source_contracts.values()))
assert broad_source_response is not None
assert "Sending a report in chat does not by itself create a proposal or persistent knowledge" in broad_source_response
assert "chat attachment capture and extraction are not connected" in broad_source_response
assert "teleo-kb propose-source" in broad_source_response
assert "writes only kb_stage.kb_proposals" in broad_source_response
mixed_contracts = {
item["id"]: item
for item in module.operational_contracts(