Make broad Leo replies deterministic (#121)
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
5d135d8818
commit
73f466f899
4 changed files with 63 additions and 5 deletions
|
|
@ -456,6 +456,18 @@ def operational_contracts(
|
||||||
identity_question = any(term in lowered for term in ("soul.md", "soul file")) and any(
|
identity_question = any(term in lowered for term in ("soul.md", "soul file")) and any(
|
||||||
term in lowered for term in ("canonical identity", "canonical", "identity", "source of truth", "database")
|
term in lowered for term in ("canonical identity", "canonical", "identity", "source of truth", "database")
|
||||||
)
|
)
|
||||||
|
visible_sender_match = re.search(
|
||||||
|
r"(?:current visible telegram sender|visible telegram sender|current telegram sender)\s+is\s+@?([a-z0-9_]+)",
|
||||||
|
query,
|
||||||
|
re.I,
|
||||||
|
)
|
||||||
|
participant_identity_question = bool(
|
||||||
|
visible_sender_match
|
||||||
|
and any(
|
||||||
|
term in lowered
|
||||||
|
for term in ("call this participant", "identity sources", "mixing identities", "mix identities")
|
||||||
|
)
|
||||||
|
)
|
||||||
primary_direct_intent = next(
|
primary_direct_intent = next(
|
||||||
(
|
(
|
||||||
intent
|
intent
|
||||||
|
|
@ -585,6 +597,27 @@ def operational_contracts(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if participant_identity_question and visible_sender_match:
|
||||||
|
contracts.append(
|
||||||
|
{
|
||||||
|
"id": "telegram_participant_identity",
|
||||||
|
"current_visible_handle": visible_sender_match.group(1),
|
||||||
|
"allowed_sources": [
|
||||||
|
"the current message sender handle",
|
||||||
|
"that participant's explicit in-chat correction",
|
||||||
|
],
|
||||||
|
"disallowed_sources": [
|
||||||
|
"stale session context",
|
||||||
|
"environment labels",
|
||||||
|
"inferred personal names",
|
||||||
|
"another participant's profile or messages",
|
||||||
|
],
|
||||||
|
"cross_participant_boundary": (
|
||||||
|
"re-anchor every reply to that message's visible sender; never transfer or mix identities"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
mixed_markers = (
|
mixed_markers = (
|
||||||
"packet",
|
"packet",
|
||||||
"factual observation",
|
"factual observation",
|
||||||
|
|
@ -782,6 +815,19 @@ def compile_operational_response(contracts: list[dict[str, Any]]) -> str | None:
|
||||||
"""Compile a safe response when a model draft violates live DB contracts."""
|
"""Compile a safe response when a model draft violates live DB contracts."""
|
||||||
|
|
||||||
by_id = {str(contract.get("id") or ""): contract for contract in contracts}
|
by_id = {str(contract.get("id") or ""): contract for contract in contracts}
|
||||||
|
participant = by_id.get("telegram_participant_identity")
|
||||||
|
if participant:
|
||||||
|
handle = str(participant.get("current_visible_handle") or "").lstrip("@")
|
||||||
|
return (
|
||||||
|
f"Call the current Telegram sender {handle}, exactly as their visible handle identifies them.\n"
|
||||||
|
"Allowed identity sources: the current message sender handle and that participant's explicit in-chat "
|
||||||
|
"correction.\n"
|
||||||
|
"Do not use stale session context, environment labels, inferred personal names, or another "
|
||||||
|
"participant's profile.\n"
|
||||||
|
"When another user replies, never transfer or mix identities; re-anchor to that message's visible "
|
||||||
|
"sender handle."
|
||||||
|
)
|
||||||
|
|
||||||
mixed = by_id.get("mixed_packet_composition")
|
mixed = by_id.get("mixed_packet_composition")
|
||||||
if mixed:
|
if mixed:
|
||||||
mapping = mixed.get("map") or {}
|
mapping = mixed.get("map") or {}
|
||||||
|
|
@ -953,13 +999,14 @@ def compile_operational_response(contracts: list[dict[str, Any]]) -> str | None:
|
||||||
return (
|
return (
|
||||||
f"Not proven.\nFresh live readback.\n{format_database_count_readback(status_data)}\nProposal states are "
|
f"Not proven.\nFresh live readback.\n{format_database_count_readback(status_data)}\nProposal states are "
|
||||||
f"applied: {states.get('applied', 0)}, approved: {states.get('approved', 0)}, pending_review: "
|
f"applied: {states.get('applied', 0)}, approved: {states.get('approved', 0)}, pending_review: "
|
||||||
f"{states.get('pending_review', 0)}. This current snapshot does not establish what changed since "
|
f"{states.get('pending_review', 0)}. This current snapshot does not prove what changed since "
|
||||||
f"yesterday. Existing receipts identify applied types {applied_types or 'none'}, but not a time-window "
|
f"yesterday, so the demo claim is limited to current readback. Existing receipt artifacts identify "
|
||||||
f"delta. Approved is not applied; {approved_needs_payload}/{len(approved_rows)} approved rows are "
|
f"applied types {applied_types or 'none'}, but not a time-window delta. Approved is not applied; "
|
||||||
|
f"{approved_needs_payload}/{len(approved_rows)} approved rows are "
|
||||||
"approved_needs_apply_payload and not directly applyable.\n\n"
|
"approved_needs_apply_payload and not directly applyable.\n\n"
|
||||||
"Next proof-changing follow-up: build and review a strict apply_payload for the highest-impact approved "
|
"Next proof-changing follow-up: build and review a strict apply_payload for the highest-impact approved "
|
||||||
"proposal, then seek explicit apply authorization. Until its applied_at and public.* before/after row "
|
"proposal, then seek explicit apply authorization. Until its applied_at, public.* before/after row "
|
||||||
"IDs or hashes exist, do not claim the canonical database changed."
|
"IDs or hashes, and postflight readback exist, do not claim the canonical database changed."
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
f"Partly.\nFresh live readback.\n{format_database_count_readback(status_data)}\nProposal states are applied: "
|
f"Partly.\nFresh live readback.\n{format_database_count_readback(status_data)}\nProposal states are applied: "
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ COMPILED_CONTRACT_IDS = frozenset(
|
||||||
"source_link_audit",
|
"source_link_audit",
|
||||||
"demo_capability_readback",
|
"demo_capability_readback",
|
||||||
"identity_canonicality_readback",
|
"identity_canonicality_readback",
|
||||||
|
"telegram_participant_identity",
|
||||||
"runtime_persistence",
|
"runtime_persistence",
|
||||||
"shared_claims_agent_positions",
|
"shared_claims_agent_positions",
|
||||||
"forecast_resolution_schema",
|
"forecast_resolution_schema",
|
||||||
|
|
|
||||||
|
|
@ -251,6 +251,10 @@ def test_vps_bridge_broad_db_questions_select_query_specific_live_contracts() ->
|
||||||
"Is the proposal backlog stuck on missing document-to-source links?": "source_link_audit",
|
"Is the proposal backlog stuck on missing document-to-source links?": "source_link_audit",
|
||||||
"Can we demo a real database write from Leo?": "demo_capability_readback",
|
"Can we demo a real database write from Leo?": "demo_capability_readback",
|
||||||
"Does editing the SOUL file alter the source of truth for identity?": "identity_canonicality_readback",
|
"Does editing the SOUL file alter the source of truth for identity?": "identity_canonicality_readback",
|
||||||
|
(
|
||||||
|
"The current visible Telegram sender is @m3taversal. What should Leo call this participant, which "
|
||||||
|
"identity sources are allowed, and how should Leo avoid mixing identities?"
|
||||||
|
): "telegram_participant_identity",
|
||||||
}
|
}
|
||||||
|
|
||||||
for query, expected_id in cases.items():
|
for query, expected_id in cases.items():
|
||||||
|
|
@ -316,6 +320,11 @@ def test_vps_bridge_oos_intents_preserve_specific_contracts_and_negated_actions(
|
||||||
(
|
(
|
||||||
"A temporary-profile GatewayRunner answered, but posted nothing to Telegram. Is delivery proven live?"
|
"A temporary-profile GatewayRunner answered, but posted nothing to Telegram. Is delivery proven live?"
|
||||||
): {"telegram_delivery_proof"},
|
): {"telegram_delivery_proof"},
|
||||||
|
(
|
||||||
|
"The current visible Telegram sender is @m3taversal. An earlier answer shortened that handle. What "
|
||||||
|
"should Leo call this participant, which identity sources are allowed, and how should Leo avoid mixing "
|
||||||
|
"identities when another user replies? Do not write to memory or the KB."
|
||||||
|
): {"telegram_participant_identity"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for query, expected_ids in cases.items():
|
for query, expected_ids in cases.items():
|
||||||
|
|
|
||||||
|
|
@ -573,6 +573,7 @@ def test_db_compiled_responses_pass_all_database_backed_oos_cases() -> None:
|
||||||
"OOS-04",
|
"OOS-04",
|
||||||
"OOS-05",
|
"OOS-05",
|
||||||
"OOS-06",
|
"OOS-06",
|
||||||
|
"OOS-09",
|
||||||
"OOS-10",
|
"OOS-10",
|
||||||
"OOS-11",
|
"OOS-11",
|
||||||
"OOS-12",
|
"OOS-12",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue