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, None,
) )
source_terms = ("document", "pdf", "tweet", "attachment", "ingest", "intake", "absorb", "extract") 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( contracts.append(
{ {
"id": "source_intake", "id": "source_intake",
@ -514,8 +534,9 @@ def operational_contracts(
), ),
"capability_tier": "VPS-local prepared-input compiler and pending-review staging", "capability_tier": "VPS-local prepared-input compiler and pending-review staging",
"safe_without_apply_authorization": [ "safe_without_apply_authorization": [
"retain artifact plus URL or storage_path plus content hash", "prepare and retain the artifact, UTF-8 extracted text, extraction manifest, URL or storage_path "
"extract candidates into a pending_review proposal packet", "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", "approval_begins": "before guarded canonical public.* apply, not before mechanical capture/staging",
"current_public_sources_columns": list(schema.get("sources", ())), "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") source = by_id.get("source_intake")
if source: if source:
safe_steps = [str(item) for item in source.get("safe_without_apply_authorization") or []] 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" 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 candidates in a pending_review proposal" stage_step = safe_steps[1] if len(safe_steps) > 1 else "stage a pending_review proposal"
return ( return (
f"- {source.get('required_lead')} Immediately {retain_step}; retain provenance for each PDF, Telegram " f"- {source.get('required_lead')} Sending a report in chat does not by itself create a proposal or "
"message, and tweet. A filename, chat label, attachment reference, or source_ref is not source identity.\n\n" "persistent knowledge. I can analyze content available in this conversation, but chat attachment "
f"- {stage_step}. Deduplicate overlapping candidate claims, preserve evidence excerpts, source-specific " "capture and extraction are not connected to the staging command.\n\n"
"caveats, uncertainty, and contradictions. Candidates are not canonical until reviewed and applied: create " f"- The live bounded path is to {retain_step}, then {stage_step}. It writes only "
"no public.sources or other public.* rows during capture or staging.\n\n" "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/" 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 " "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") 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( named_packet_question = "helmer" in lowered and any(
term in lowered for term in ("7 powers", "seven powers", "powers framework", "powers packet") 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( return bool(
named_packet_question named_packet_question
or broad_source_intake_question
or ("telegram" in lowered and "gatewayrunner" in lowered) or ("telegram" in lowered and "gatewayrunner" in lowered)
or re.search( or re.search(
r"\b(?:databases?|db|knowledge bases?|kb|proposals?|canonical|source_ref|source rows?|" 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) == [] 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: def test_plugin_replaces_memory_only_status_answer_with_exact_live_db_receipt(tmp_path: Path, monkeypatch) -> None:
module = load_plugin() module = load_plugin()
home = tmp_path / "profile" 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 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"] 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 = { mixed_contracts = {
item["id"]: item item["id"]: item
for item in module.operational_contracts( for item in module.operational_contracts(