fix Leo broad source intake truth (#124)
Some checks are pending
CI / lint-and-test (push) Waiting to run
Some checks are pending
CI / lint-and-test (push) Waiting to run
This commit is contained in:
parent
ee48f82f06
commit
5dfcd32c34
4 changed files with 79 additions and 11 deletions
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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?|"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue