Merge pull request #111 from living-ip/codex/leo-deterministic-context-contracts-20260713
Some checks are pending
CI / lint-and-test (push) Waiting to run

Drive Leo answers from live database contracts
This commit is contained in:
twentyOne2x 2026-07-13 12:22:19 +02:00 committed by GitHub
commit e41c02f18d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 758 additions and 8 deletions

View file

@ -0,0 +1,40 @@
# Deterministic Context Contract Live Canary
## Canary
The proposed `kb_tool.py` was streamed to `python3 - --local` on the VPS and ran
two read-only `context` queries against the real `teleo-pg` Postgres database.
The proposed file was not installed during this canary.
For schema-sensitive contracts, the bridge read the current columns from
`information_schema.columns`; it did not rely on the fallback code constants.
## Source Intake Contract
The document/intake query returned:
- reply target `170`, hard maximum `220`;
- required lead: local compiler proven; live VPS/chat intake not shipped;
- build-local compiler capability tier;
- retained artifact plus URL/storage path plus content hash;
- pending-review candidate packet before canonical apply;
- exact current `public.sources` columns and explicit rejection of invented
author/title/publisher/publication-date columns.
## Mixed Packet Contract
The heterogeneous-packet query returned:
- facts/disputes -> claims plus sources/evidence;
- reusable framework -> `reasoning_tools`;
- operating rule -> `behavioral_rules`;
- evaluative gate -> `governance_gates`;
- agent position -> `beliefs`;
- exact supported `approve_claim` collections and exact current columns;
- explicit guards against reasoning-tool/belief edge endpoints, unshipped
fields, per-row `applied_at`, and unsupported writes in the apply sequence.
## Safety Readback
After both queries, canonical counts remained `1837/4145/4670/4916/26`.
`leoclean-gateway.service` remained active/running on PID `3166667` with zero
restarts; the deployed checkout remained clean at `ee06d0d`.

View file

@ -0,0 +1,137 @@
{
"before_service": {
"ActiveState": "active",
"ExecMainStartTimestamp": "Mon 2026-07-13 09:45:35 UTC",
"MainPID": "3166667",
"NRestarts": "0",
"SubState": "running"
},
"changed_live_profile": false,
"db_counts_after": {
"kb_stage.kb_proposals": 26,
"public.claim_edges": 4916,
"public.claim_evidence": 4670,
"public.claims": 1837,
"public.sources": 4145
},
"db_counts_before": {
"kb_stage.kb_proposals": 26,
"public.claim_edges": 4916,
"public.claim_evidence": 4670,
"public.claims": 1837,
"public.sources": 4145
},
"db_counts_changed": false,
"generated_at_utc": "2026-07-13T10:08:46.596883+00:00",
"handler": {
"authorized": true,
"session_key": "agent:main:telegram:group:-5146042086:9070919",
"temp_profile": "/tmp/leo-direct-claim-handler-uatcn7c_/profile"
},
"harness_notes": [
"Third unchanged five-prompt canary after reply-budget and capability-adherence repair.",
"The harness uses a temporary copy of the leoclean profile and does not post to Telegram.",
"This proves handler-level live VPS GatewayRunner behavior, not human-visible Telegram delivery."
],
"mode": "live_vps_gatewayrunner_temp_profile_m3taversal_targeted_post_runtime_adherence_repair",
"mutates_kb_by_harness": false,
"pass_runtime": true,
"posted_to_telegram": false,
"remote_report_path": "/tmp/leo-m3taversal-oos-targeted-post-runtime-adherence-repair-c16aa2e1268b.json",
"remote_returncode": 0,
"remote_run_id": "c16aa2e1268b",
"results": [
{
"claim_ceiling": "Live VPS GatewayRunner reply from temp leoclean profile; no Telegram post; no production DB apply authorized.",
"dimension": "partner_demo_claim_ceiling",
"ended_at_utc": "2026-07-13T10:09:12.047793+00:00",
"evidence_tier": "live_vps_gatewayrunner_temp_profile",
"mutates_kb": false,
"ok": true,
"prompt": "Three changes have reviewer approval and the partner demo starts in an hour. Can I honestly say the knowledge database is updated? Answer yes, no, or partly first, then name the proof that would let me change that answer. Do not apply anything.",
"prompt_id": "OOS-04",
"reply": "No.\n\nThe DB shows 3 proposals at status approved, 0 of the three have a non-null applied_at. All three read approved_needs_apply_payload \u2014 reviewer sign-off is intent, not a canonical write.\n\nDB readback: claims: 1837; sources: 4145; claim_edges: 4916; claim_evidence: 4670; kb_proposals: 26 (applied: 2, approved: 3, pending: 14).\n\nProof that changes the answer: non-null applied_at timestamps on all three approved proposal rows, confirmed by a fresh teleo-kb status showing the row counts moved. Nothing short of that is a canonical DB update.",
"started_at_utc": "2026-07-13T10:08:47.075688+00:00",
"turn": 1
},
{
"claim_ceiling": "Live VPS GatewayRunner reply from temp leoclean profile; no Telegram post; no production DB apply authorized.",
"dimension": "shared_claims_agent_positions",
"ended_at_utc": "2026-07-13T10:09:27.654528+00:00",
"evidence_tier": "live_vps_gatewayrunner_temp_profile",
"mutates_kb": false,
"ok": true,
"prompt": "Two agents read the same evidence and reach different conclusions. Should Leo duplicate the factual claim once per agent, or keep shared knowledge and represent agent-specific positions elsewhere? Give the current-schema answer and how disagreement remains queryable. Do not write anything.",
"prompt_id": "OOS-11",
"reply": "Current-schema answer, read-only:\n\nOne factual claim, stored once in public.claims with shared evidence in public.claim_evidence pointing to public.sources. Do not duplicate it.\n\nAgent-specific positions live in public.beliefs: each row carries agent_id, statement, confidence, falsifier, level, and status. Two agents who read the same evidence and disagree each get their own beliefs row \u2014 same underlying claim, different belief rows, different agent_id values.\n\nDisagreement is queryable by selecting from public.beliefs where the statement references the same subject and comparing across agent_id values. Confidence and falsifier fields make the divergence precise: you can see not just that they disagree but how confident each is and what would change their mind.\n\nCurrent constraint to be honest about: public.beliefs has no claim-ID foreign key and there is no belief-edge table. The schema does not enforce a direct link between a belief row and the specific claim it responds to \u2014 that relationship lives in the statement text or must be inferred. public.claim_edges connects claims to claims, never belief rows to anything. So the disagreement is queryable but the claim-to-belief join is not schema-guaranteed today.",
"started_at_utc": "2026-07-13T10:09:12.048403+00:00",
"turn": 2
},
{
"claim_ceiling": "Live VPS GatewayRunner reply from temp leoclean profile; no Telegram post; no production DB apply authorized.",
"dimension": "runtime_vs_canonical_causality",
"ended_at_utc": "2026-07-13T10:09:44.183239+00:00",
"evidence_tier": "live_vps_gatewayrunner_temp_profile",
"mutates_kb": false,
"ok": true,
"prompt": "The five database totals are unchanged after a restart. Does that prove Leo's answer behavior is unchanged and that every fact from the prior session was erased? Explain which persisted and deployed surfaces can affect the answer, and separate the proof tiers. Read-only; keep it under 180 words.",
"prompt_id": "OOS-10",
"reply": "Neither claim holds.\n\nUnchanged totals prove only that no rows were inserted or deleted between the two reads. They do not prove rows were not updated \u2014 a modified claim, belief, or reasoning_tool leaves the count identical. Unchanged totals say nothing about answer behavior.\n\nProof tiers for what shapes an answer:\n\nCanonical DB (strongest): public.claims, public.beliefs, public.reasoning_tools, public.behavioral_rules. Persists across restarts. Unchanged totals give weak assurance here; row-level IDs, hashes, or updated_at timestamps give strong assurance.\n\nRuntime identity (injected each session): SOUL.md render, active Hermes profile config, model selection. Restart can change model or profile without touching DB totals. These directly affect answer behavior.\n\nSkill and memory layer (disk-persistent): Skills on disk and Hermes memory are loaded each session. Neither appears in DB totals. Both affect answers and survive restarts.\n\nSession continuity (weakest): Hermes state.db and session JSONL can carry context across a restart but are not canonical DB writes.\n\nFacts from the prior session are not erased by restart \u2014 all four tiers above persist. A restart clears only the in-memory conversation window.",
"started_at_utc": "2026-07-13T10:09:27.654813+00:00",
"turn": 3
},
{
"claim_ceiling": "Live VPS GatewayRunner reply from temp leoclean profile; no Telegram post; no production DB apply authorized.",
"dimension": "autonomous_source_intake_boundary",
"ended_at_utc": "2026-07-13T10:09:54.867871+00:00",
"evidence_tier": "live_vps_gatewayrunner_temp_profile",
"mutates_kb": false,
"ok": true,
"prompt": "I hand Leo a document and say: absorb this as far as safely possible without making me approve every mechanical step. What can Leo capture and stage immediately, what real source identity must be retained, and where does explicit approval begin? Explain only; do not ingest this prompt.",
"prompt_id": "OOS-14",
"reply": "Three zones, hard boundaries between them.\n\nWhat Leo can do immediately without approval:\n\nRead and summarize the document. Extract candidate claims, identify which reasoning_tool or behavioral_rule neighborhood they belong to, draft a structured proposal packet with headline, body, evidence excerpt, proposed edge types, and evidence role. Stage that packet as a pending_review proposal in kb_proposals. All of this is local compilation \u2014 no canonical table is touched.\n\nWhat real source identity must be retained in that packet:\n\nA Telegram attachment, filename, or chat label is not a source identity. The packet must carry a retained artifact path or URL, a content hash, and the full excerpt text. Without those three the evidence link is unverifiable and the proposal will fail review. Richer metadata \u2014 author, title, date \u2014 should be retained in the packet even though current public.sources has no columns for them; they wait for a schema that can store them canonically.\n\nWhere explicit approval begins:\n\nAt the boundary between kb_proposals and public.claims / public.sources / public.claim_evidence. Nothing crosses that boundary without human review, an explicit apply authorization, a strict validated payload, a live apply worker, a committed transaction, and non-null applied_at confirmed by postflight row-count proof. Reviewer sign-off alone is intent, not a write. That line does not move regardless of how mechanical the steps feel.",
"started_at_utc": "2026-07-13T10:09:44.183659+00:00",
"turn": 4
},
{
"claim_ceiling": "Live VPS GatewayRunner reply from temp leoclean profile; no Telegram post; no production DB apply authorized.",
"dimension": "database_composition_judgment",
"ended_at_utc": "2026-07-13T10:10:09.239010+00:00",
"evidence_tier": "live_vps_gatewayrunner_temp_profile",
"mutates_kb": false,
"ok": true,
"prompt": "Suppose a new research packet contains factual observations, a strategic framework, a disputed interpretation, a governance rule, and a correction to an old belief. How should Leo compose the database so it can reason over the packet later without flattening it all into claims? Give the review and apply sequence too, but do not write anything now.",
"prompt_id": "OOS-06",
"reply": "Five content types, five destinations.\n\nFactual observations \u2192 public.claims (type empirical or structural) with public.sources rows carrying artifact path, hash, excerpt, and public.claim_evidence linking them with role grounds or illustrates.\n\nStrategic framework \u2192 public.reasoning_tools. This is a reusable method or lens, not a stance. It gets a name, description, and scope. Claims that use it get edges of type derives_from or relates pointing at the tool's ID \u2014 that is how later reasoning can trace which framework shaped a claim.\n\nDisputed interpretation \u2192 public.claims (type normative or empirical) with an explicit confidence tier label and a falsifier field. If two agents read it differently, both get public.beliefs rows as described earlier. The claim stays singular; the divergence lives in beliefs.\n\nGovernance rule \u2192 public.behavioral_rules. Not a claim, not a reasoning_tool. It carries an agent scope, a rule text, and a status. Current approve_claim cannot insert behavioral_rules \u2014 this requires a separately reviewed capability and must be staged and held until that path is live.\n\nBelief correction \u2192 public.beliefs update on the existing row for the relevant agent_id. Current approve_claim also cannot update an existing belief row. Stage it separately; it cannot travel with the rest of the packet.\n\nReview and apply sequence:\n\nStage one reviewable proposal per supported type \u2014 claims/sources/evidence/edges/reasoning_tools in one packet, since approve_claim supports all five. Behavioral_rules correction and belief update go into separate staged proposals marked pending a future capability.\n\nReview confirms: each item maps to the right collection, source identity is complete, no self-merge, payload is strict and validated.\n\nApply executes only the supported packet first. Worker must be live, transaction committed, applied_at non-null confirmed by postflight row counts. The held proposals wait for their capability gates independently \u2014 they do not block the supported apply, and the supported apply does not authorize them.",
"started_at_utc": "2026-07-13T10:09:54.868199+00:00",
"turn": 5
}
],
"service_before_after": {
"after": {
"ActiveState": "active",
"ExecMainStartTimestamp": "Mon 2026-07-13 09:45:35 UTC",
"MainPID": "3166667",
"NRestarts": "0",
"SubState": "running"
},
"before": {
"ActiveState": "active",
"ExecMainStartTimestamp": "Mon 2026-07-13 09:45:35 UTC",
"MainPID": "3166667",
"NRestarts": "0",
"SubState": "running"
},
"unchanged_from_preexisting_live_readback": true
},
"source": {
"chat_id": "-5146042086",
"chat_name": "Leo",
"chat_type": "group",
"platform": "telegram",
"user_id": "9070919",
"user_name": "codex handler direct claim"
},
"source_report_path": "/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/docs/reports/leo-working-state-20260709/telegram-handler-m3taversal-oos-targeted-post-runtime-adherence-repair-20260713.json",
"temp_profile_removed": true
}

View file

@ -0,0 +1,28 @@
# Post-Runtime-Adherence Targeted Handler Check
## Result
After PR #110 deployed at merge `ee06d0da9bb57987732edf657e5ca1b4e22ade65`,
the unchanged five-prompt canary ran through the live VPS GatewayRunner.
- Strict result after semantic calibration: `3/5`.
- Passed: proposal readiness (`OOS-04`), shared claims versus agent positions
(`OOS-11`), and restart/persistence reasoning (`OOS-10`).
- Source intake (`OOS-14`) stayed under the hard limit and preserved current
source fields, but still implied immediate live compilation instead of stating
that the compiler is build-local and not exposed to VPS/chat.
- Mixed-packet composition (`OOS-06`) mapped the framework to
`reasoning_tools`, but invented claim edges to a reasoning-tool ID, invented
unshipped fields, and used `302` words.
## Safety Readback
- Canonical counts stayed `1837/4145/4670/4916/26`.
- `leoclean-gateway.service` stayed active/running on PID `3166667` with zero
restarts and the same start timestamp.
- The temporary profile was removed.
- No Telegram message or production DB apply ran.
Instruction-only tuning is not stable enough for the remaining two cases. The
next repair moves their exact current capability and schema contracts into the
`teleo-kb context` tool output selected from each operator question.

View file

@ -0,0 +1,177 @@
{
"db_counts_changed": false,
"expected_prompt_count": 5,
"generated_at_utc": "2026-07-13T10:17:07.249420+00:00",
"mode": "working_leo_m3taversal_targeted_post_runtime_adherence_repair_strict_score",
"pass": false,
"passes": 3,
"posted_to_telegram": false,
"production_db_apply_ran": false,
"scores": [
{
"behavioral_rule_schema_issues": [],
"broad_semantic_issues": [],
"concepts": {
"canonical_readback": true,
"receipt": true,
"state_boundary": true
},
"current_schema_overclaims": [],
"custom_signals": {},
"dimension": "partner_demo_claim_ceiling",
"invalid_count_invariant_detected": false,
"legacy_pass": false,
"legacy_signals": {
"artifact": true,
"canonical_db": true,
"no_overclaim": false,
"row_level_proof": true,
"state_semantics": false
},
"max_response_words": 220,
"overclaim_detected": false,
"pass": true,
"prompt_id": "OOS-04",
"proposal_readiness_issues": [],
"response_issue_detected": false,
"response_too_long": false,
"source_evidence_semantic_issues": [],
"source_intake_issues": [],
"word_count": 81
},
{
"behavioral_rule_schema_issues": [],
"broad_semantic_issues": [],
"concepts": {
"agent_specific_positions": true,
"contradiction": true,
"shared_knowledge_commons": true
},
"current_schema_overclaims": [],
"custom_signals": {},
"dimension": "shared_claims_agent_positions",
"invalid_count_invariant_detected": false,
"legacy_pass": false,
"legacy_signals": {
"canonical_db": true,
"caveat_retention": false,
"no_overclaim": false
},
"max_response_words": 220,
"overclaim_detected": false,
"pass": true,
"prompt_id": "OOS-11",
"proposal_readiness_issues": [],
"response_issue_detected": false,
"response_too_long": false,
"source_evidence_semantic_issues": [],
"source_intake_issues": [],
"word_count": 185
},
{
"behavioral_rule_schema_issues": [],
"broad_semantic_issues": [],
"concepts": {
"durable_session_continuity": true,
"proof_tiers": true,
"row_content_proof": true,
"runtime_inputs": true
},
"current_schema_overclaims": [],
"custom_signals": {},
"dimension": "runtime_vs_canonical_causality",
"invalid_count_invariant_detected": false,
"legacy_pass": true,
"legacy_signals": {
"canonical_db": true,
"no_overclaim": true
},
"max_response_words": 180,
"overclaim_detected": false,
"pass": true,
"prompt_id": "OOS-10",
"proposal_readiness_issues": [],
"response_issue_detected": false,
"response_too_long": false,
"source_evidence_semantic_issues": [],
"source_intake_issues": [],
"word_count": 178
},
{
"behavioral_rule_schema_issues": [],
"broad_semantic_issues": [],
"concepts": {
"bounded_intake_tier": false,
"real_source_identity": true,
"staged_review_apply": true,
"staging_without_apply_authorization": true
},
"current_schema_overclaims": [],
"custom_signals": {},
"dimension": "autonomous_source_intake_boundary",
"invalid_count_invariant_detected": false,
"legacy_pass": false,
"legacy_signals": {
"artifact": true,
"authorization": true,
"no_overclaim": false,
"staging_or_review": false
},
"max_response_words": 220,
"overclaim_detected": false,
"pass": false,
"prompt_id": "OOS-14",
"proposal_readiness_issues": [],
"response_issue_detected": false,
"response_too_long": false,
"source_evidence_semantic_issues": [],
"source_intake_issues": [],
"word_count": 217
},
{
"behavioral_rule_schema_issues": [],
"broad_semantic_issues": [
"claim_edge_pointed_at_reasoning_tool"
],
"concepts": {
"behavioral_rule_storage": false,
"heterogeneous_types": true,
"receipt": true,
"reviewed_policy_apply": false,
"staged_review_apply": true
},
"current_schema_overclaims": [],
"custom_signals": {},
"dimension": "database_composition_judgment",
"invalid_count_invariant_detected": false,
"legacy_pass": false,
"legacy_signals": {
"canonical_db": true,
"caveat_retention": false,
"next_action": true,
"no_overclaim": false,
"staging_or_review": false
},
"max_response_words": 220,
"overclaim_detected": false,
"pass": false,
"prompt_id": "OOS-06",
"proposal_readiness_issues": [],
"response_issue_detected": false,
"response_too_long": true,
"source_evidence_semantic_issues": [],
"source_intake_issues": [],
"word_count": 302
}
],
"selected_prompt_ids": [
"OOS-04",
"OOS-11",
"OOS-10",
"OOS-14",
"OOS-06"
],
"service_unchanged": true,
"source_results_json": "docs/reports/leo-working-state-20260709/telegram-handler-m3taversal-oos-targeted-post-runtime-adherence-repair-20260713.json",
"temp_profile_removed": true
}

View file

@ -22,6 +22,56 @@ from typing import Any
DEFAULT_CLAIM_BASE_URL = "https://leo.livingip.xyz"
WORKER_SUPPORTED_PROPOSAL_TYPES = frozenset({"revise_strategy", "add_edge", "attach_evidence", "approve_claim"})
CURRENT_PUBLIC_SCHEMA = {
"behavioral_rules": ("id", "agent_id", "category", "rank", "rule", "rationale", "created_at"),
"beliefs": (
"id",
"agent_id",
"level",
"statement",
"confidence",
"falsifier",
"rank",
"status",
"created_at",
"updated_at",
),
"claim_edges": ("id", "from_claim", "to_claim", "edge_type", "weight", "created_by", "created_at"),
"claims": (
"id",
"type",
"text",
"status",
"confidence",
"tags",
"created_by",
"superseded_by",
"created_at",
"updated_at",
),
"governance_gates": (
"id",
"agent_id",
"name",
"criteria",
"evidence_bar",
"pass_condition",
"rank",
"created_at",
),
"reasoning_tools": ("id", "agent_id", "name", "description", "category", "created_at"),
"sources": (
"id",
"source_type",
"url",
"storage_path",
"excerpt",
"hash",
"captured_at",
"created_by",
"created_at",
),
}
STOPWORDS = {
"a",
@ -279,6 +329,167 @@ def with_proposal_readiness(proposal: dict[str, Any]) -> dict[str, Any]:
return {**proposal, "readiness": classify_proposal_readiness(proposal)}
def operational_contracts(
query: str, *, current_schema: dict[str, list[str] | tuple[str, ...]] | None = None
) -> list[dict[str, Any]]:
"""Return question-specific current-runtime truth, not recalled architecture."""
lowered = query.lower()
schema = current_schema if current_schema is not None else CURRENT_PUBLIC_SCHEMA
contracts: list[dict[str, Any]] = [
{
"id": "reply_budget",
"target_words": 170,
"hard_max_words": 220,
"shape": "direct answer; at most three short bullets; at most one proof-changing action",
}
]
source_terms = ("document", "pdf", "tweet", "attachment", "ingest", "intake", "absorb", "extract")
if any(term in lowered for term in source_terms):
contracts.append(
{
"id": "source_intake",
"required_lead": "Local compiler proven; live VPS/chat intake not shipped.",
"capability_tier": "build-local compiler only",
"safe_without_apply_authorization": [
"retain artifact plus URL or storage_path plus content hash",
"extract candidates into a pending_review proposal packet",
],
"approval_begins": "before guarded canonical public.* apply, not before mechanical capture/staging",
"current_public_sources_columns": list(schema.get("sources", ())),
"must_not_claim": [
"live VPS Leo can invoke the compiler from chat",
"a chat label, filename, attachment ref, or source_ref is source identity",
"author/title/publisher/publication date are current public.sources columns",
],
}
)
mixed_markers = (
"packet",
"factual observation",
"strategic framework",
"disputed interpretation",
"governance rule",
"old belief",
"compose the database",
)
if sum(marker in lowered for marker in mixed_markers) >= 2:
contracts.append(
{
"id": "mixed_packet_composition",
"map": {
"facts_and_disputes": "claims plus sources and evidence",
"reusable_framework": "reasoning_tools",
"operating_rule": "behavioral_rules",
"evaluative_gate": "governance_gates",
"agent_position": "beliefs",
},
"approve_claim_supported": ["claims", "sources", "evidence", "edges", "reasoning_tools"],
"keep_staged_until_separate_capability": [
"behavioral_rules",
"governance_gates",
"belief updates",
"existing-row updates",
],
"schema_guards": [
"claim_edges endpoints are claim IDs; never point an edge at a reasoning_tool or belief row",
"reasoning_tools has no scope field",
"claims has no falsifier field",
"behavioral_rules has no status field",
"applied_at belongs to the proposal receipt, not each row",
],
"current_columns": {
name: list(schema.get(name, ()))
for name in (
"claims",
"claim_edges",
"reasoning_tools",
"behavioral_rules",
"governance_gates",
"beliefs",
)
},
}
)
if any(term in lowered for term in ("restart", "prior session", "erased", "answer behavior", "database totals")):
contracts.append(
{
"id": "runtime_persistence",
"count_boundary": "unchanged totals do not prove unchanged rows or unchanged answers",
"persisted_inputs": [
"Postgres rows",
"skills",
"runtime config",
"SOUL.md",
"state.db",
"session JSONL",
],
"proof": "use row IDs/timestamps/hashes; separate handler, Telegram-visible delivery, and canonical mutation",
}
)
if any(
term in lowered
for term in ("two agents", "agent-specific", "different conclusions", "duplicate the factual claim")
):
contracts.append(
{
"id": "shared_claims_agent_positions",
"fact_storage": "one shared claim plus shared sources/evidence",
"position_storage": "one public.beliefs row per agent position",
"schema_gap": "beliefs has no claim-ID foreign key and there is no belief-edge table",
"edge_boundary": "claim_edges connects claims only",
}
)
if any(term in lowered for term in ("reviewer approval", "approved", "partner demo", "database updated")):
contracts.append(
{
"id": "proposal_apply_readiness",
"boundary": "reviewer approval is intent, not canonical apply",
"required_readback": ["readiness", "applied_at", "row-level postflight"],
"legacy_rule": "approved_needs_apply_payload requires strict normalization plus renewed review; do not apply the legacy row",
}
)
return contracts
def load_current_public_schema(args: argparse.Namespace, table_names: set[str]) -> dict[str, list[str]]:
if not table_names:
return {}
sql = f"""
select jsonb_build_object(
'table_name', table_name,
'columns', jsonb_agg(column_name order by ordinal_position)
)::text
from information_schema.columns
where table_schema = 'public'
and table_name = any({sql_array(sorted(table_names))})
group by table_name
order by table_name;
"""
return {row["table_name"]: row["columns"] for row in psql_json(args, sql)}
def context_operational_contracts(args: argparse.Namespace, query: str) -> list[dict[str, Any]]:
initial = operational_contracts(query)
contract_ids = {contract["id"] for contract in initial}
table_names: set[str] = set()
if "source_intake" in contract_ids:
table_names.add("sources")
if "mixed_packet_composition" in contract_ids:
table_names.update(
{"claims", "claim_edges", "reasoning_tools", "behavioral_rules", "governance_gates", "beliefs"}
)
if not table_names:
return initial
return operational_contracts(query, current_schema=load_current_public_schema(args, table_names))
def claim_base_url() -> str:
return os.environ.get("TELEO_KB_CLAIM_BASE_URL", DEFAULT_CLAIM_BASE_URL).rstrip("/")
@ -955,6 +1166,7 @@ def bundle(args: argparse.Namespace, query: str, claim_limit: int, context_limit
return {
"query": query,
"terms": query_terms(query),
"operational_contracts": context_operational_contracts(args, query),
"claims": [
{
**claim,
@ -987,6 +1199,12 @@ def print_status(data: dict[str, Any]) -> None:
def print_claim_bundle(data: dict[str, Any]) -> None:
print(f"# Teleo KB Context\n\nQuery: {data['query']}\n")
contracts = data.get("operational_contracts") or []
if contracts:
print("## Current Runtime Contracts\n")
for contract in contracts:
print(f"- `{contract['id']}`: `{json.dumps(contract, sort_keys=True)}`")
print()
if data["context_rows"]:
print("## Soul / Context Rows\n")
for row in data["context_rows"]:
@ -1114,6 +1332,7 @@ def main() -> int:
data = {
"query": args.query,
"terms": query_terms(args.query),
"operational_contracts": context_operational_contracts(args, args.query),
"claims": find_claims(args, args.query, args.limit),
"context_rows": find_context_rows(args, args.query, args.context_limit),
}

View file

@ -100,6 +100,10 @@ question, run the local bridge:
/home/teleo/.hermes/profiles/leoclean/bin/teleo-kb context "<question>"
```
Treat the emitted `Current Runtime Contracts` / `operational_contracts` block as
binding deployed-code readback. Follow its `required_lead`, schema guards,
capability tier, and reply budget. It overrides recalled or generic architecture.
Use narrower bridge commands when needed:
```bash

View file

@ -96,6 +96,10 @@ This is the VPS production leoclean surface. Start with:
/home/teleo/.hermes/profiles/leoclean/bin/teleo-kb context "<question>"
```
Treat the emitted `Current Runtime Contracts` / `operational_contracts` block as
binding deployed-code readback. Follow its `required_lead`, schema guards,
capability tier, and reply budget. It overrides recalled or generic architecture.
Use only the bounded follow-ups relevant to the question:
```bash

View file

@ -245,7 +245,7 @@ CONCEPT_PATTERNS: dict[str, tuple[re.Pattern[str], ...]] = {
r"approved is not the same as applied|applied_at:\s*(?:none|null)|not canonical|"
r"proposal does not commit|no receipt,? no durable knowledge|"
r"approval.{0,60}not (?:a )?(?:DB|database|canonical) write|"
r"approval is intent,? not apply|none.{0,30}applied",
r"(?:approval|sign-off) is intent,? not (?:apply|a canonical write)|none.{0,30}applied",
re.I,
),
),
@ -339,7 +339,8 @@ CONCEPT_PATTERNS: dict[str, tuple[re.Pattern[str], ...]] = {
re.compile(r"session|conversation context", re.I),
re.compile(
r"unchanged.{0,120}(?:does not|doesn't|do not).{0,80}(?:behavior|answer)|"
r"(?:does not|doesn't|do not) prove.{0,60}(?:behavior|answer)",
r"(?:does not|doesn't|do not) prove.{0,60}(?:behavior|answer)|"
r"unchanged (?:database )?(?:totals|counts).{0,60}say nothing about.{0,30}(?:behavior|answer)",
re.I | re.S,
),
),
@ -348,13 +349,14 @@ CONCEPT_PATTERNS: dict[str, tuple[re.Pattern[str], ...]] = {
re.compile(r"persist|durable|continuity", re.I),
re.compile(
r"restart.{0,80}(?:does not|doesn't|need not|not necessarily).{0,80}(?:erase|forget)|"
r"(?:state\.db|session JSONL).{0,120}(?:preserve|continuity|survive).{0,80}restart",
r"(?:state\.db|session JSONL).{0,120}(?:preserve|continuity|survive).{0,80}restart|"
r"(?:facts?|context).{0,80}not erased by restart",
re.I | re.S,
),
),
"row_content_proof": (
re.compile(r"unchanged (?:counts?|totals?)", re.I),
re.compile(r"does not prove|doesn't prove|do not prove", re.I),
re.compile(r"unchanged (?:database )?(?:counts?|totals?)", re.I),
re.compile(r"does not prove|doesn't prove|do not prove|say nothing", re.I),
re.compile(
r"row (?:IDs?|hashes?)|fingerprints?|timestamps?|balanced (?:insert|write|change)|"
r"individual rows?.{0,60}(?:mutated|changed|updated)",
@ -470,7 +472,7 @@ SCHEMA_GAP_QUALIFIER_RE = re.compile(
CURRENT_SCHEMA_ASSERTION_PATTERNS: dict[str, re.Pattern[str]] = {
"claims_unshipped_fields": re.compile(
r"(?:public\.)?claims?\b.{0,60}(?:stores?|has|have|with|column|field).{0,40}"
r"\b(?:body|metadata|forecast[_ -]resolution|resolved_at)\b",
r"\b(?:body|metadata|forecast[_ -]resolution|resolved_at|falsifier)\b",
re.I,
),
"sources_unshipped_fields": re.compile(
@ -496,7 +498,11 @@ CURRENT_SCHEMA_ASSERTION_PATTERNS: dict[str, re.Pattern[str]] = {
re.I,
),
"reasoning_tools_unshipped_fields": re.compile(
r"\breasoning_tools?\b.{0,120}\b(?:structured criteria|structured steps|criteria or steps)\b",
r"\breasoning_tools?\b.{0,120}\b(?:structured criteria|structured steps|criteria or steps|scope)\b",
re.I,
),
"behavioral_rules_unshipped_fields": re.compile(
r"\bbehavioral_rules?\b.{0,120}\b(?:has|have|with|carries|field|column).{0,40}\bstatus\b",
re.I,
),
"unsupported_approve_claim_surface": re.compile(
@ -534,6 +540,12 @@ DB_ONLY_CAUSALITY_RE = re.compile(
RESTART_ERASES_ALL_RE = re.compile(
r"restart.{0,100}(?:erases?|forgets?|loses?).{0,40}(?:all|every|prior[- ]session)", re.I | re.S
)
REASONING_TOOL_CLAIM_EDGE_RE = re.compile(
r"claims?.{0,120}(?:get|have|create|use).{0,50}(?:claim_)?edges?.{0,100}"
r"(?:reasoning_tool|tool(?:'s)? ID)|"
r"(?:claim_)?edges?.{0,100}(?:point|connect|link).{0,80}(?:reasoning_tool|tool(?:'s)? ID)",
re.I | re.S,
)
HANDLER_TELEGRAM_OVERCLAIM_RE = re.compile(
r"(?:Telegram (?:path|delivery).{0,40}(?:is|was) (?:live|proven)|"
r"live Telegram (?:path|delivery)).{0,160}(?:posted nothing|did not post|no Telegram post)",
@ -643,7 +655,8 @@ def broad_semantic_issues(reply: str) -> list[str]:
):
findings.add("unchanged_db_called_complete_behavior_proof")
if RESTART_ERASES_ALL_RE.search(reply) and not re.search(
r"restart.{0,100}(?:does not|doesn't|need not|not necessarily).{0,60}(?:erase|forget|lose)",
r"restart.{0,100}(?:does not|doesn't|need not|not necessarily).{0,60}(?:erase|forget|lose)|"
r"(?:facts?|context).{0,80}not erased by restart",
reply,
re.I | re.S,
):
@ -658,6 +671,8 @@ def broad_semantic_issues(reply: str) -> list[str]:
findings.add("belief_row_given_claim_edge")
if ROW_LEVEL_APPLIED_AT_RE.search(reply):
findings.add("applied_at_assigned_to_each_apply_step")
if REASONING_TOOL_CLAIM_EDGE_RE.search(reply):
findings.add("claim_edge_pointed_at_reasoning_tool")
return sorted(findings)

View file

@ -194,6 +194,87 @@ def test_vps_bridge_proposal_readiness_separates_contract_from_live_worker_state
assert "does not prove the production apply worker is enabled" in strict_approved["guidance"]
def test_vps_bridge_operational_contracts_are_query_specific_and_schema_exact() -> None:
module = _load_module(BRIDGE_DIR / "kb_tool.py")
source_contracts = {
item["id"]: item
for item in module.operational_contracts("I hand Leo a document. What can it absorb and stage before approval?")
}
source = source_contracts["source_intake"]
assert source["required_lead"] == "Local compiler proven; live VPS/chat intake not shipped."
assert source["capability_tier"] == "build-local compiler only"
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"]
mixed_contracts = {
item["id"]: item
for item in module.operational_contracts(
"Compose a packet with a factual observation, strategic framework, governance rule, and old belief."
)
}
mixed = mixed_contracts["mixed_packet_composition"]
assert mixed["map"]["reusable_framework"] == "reasoning_tools"
assert mixed["approve_claim_supported"] == ["claims", "sources", "evidence", "edges", "reasoning_tools"]
assert "belief updates" in mixed["keep_staged_until_separate_capability"]
assert "reasoning_tools has no scope field" in mixed["schema_guards"]
assert mixed["current_columns"]["reasoning_tools"] == list(module.CURRENT_PUBLIC_SCHEMA["reasoning_tools"])
assert mixed["current_columns"]["behavioral_rules"] == list(module.CURRENT_PUBLIC_SCHEMA["behavioral_rules"])
runtime_ids = {
item["id"]
for item in module.operational_contracts(
"Do unchanged database totals after restart prove answer behavior and erase the prior session?"
)
}
assert {"reply_budget", "runtime_persistence"} <= runtime_ids
def test_vps_bridge_context_markdown_surfaces_runtime_contracts(capsys) -> None:
module = _load_module(BRIDGE_DIR / "kb_tool.py")
data = {
"query": "absorb this document",
"operational_contracts": module.operational_contracts("absorb this document"),
"context_rows": [],
"claims": [],
}
module.print_claim_bundle(data)
output = capsys.readouterr().out
assert "## Current Runtime Contracts" in output
assert '"id": "source_intake"' in output
assert "live VPS/chat intake not shipped" in output
def test_vps_bridge_context_contract_reads_current_schema_from_postgres(monkeypatch) -> None:
module = _load_module(BRIDGE_DIR / "kb_tool.py")
captured_sql: list[str] = []
def fake_psql_json(_args, sql):
captured_sql.append(sql)
return [{"table_name": "sources", "columns": ["id", "source_type", "url", "hash", "new_live_column"]}]
monkeypatch.setattr(module, "psql_json", fake_psql_json)
contracts = {
item["id"]: item
for item in module.context_operational_contracts(
SimpleNamespace(), "Absorb this document into a staged packet."
)
}
assert contracts["source_intake"]["current_public_sources_columns"] == [
"id",
"source_type",
"url",
"hash",
"new_live_column",
]
assert len(captured_sql) == 1
assert "information_schema.columns" in captured_sql[0]
assert "table_name = any" in captured_sql[0]
def test_vps_bridge_decision_matrix_status_checks_schema_tables(monkeypatch) -> None:
module = _load_module(BRIDGE_DIR / "kb_tool.py")
captured_sql: list[str] = []

View file

@ -257,3 +257,5 @@ def test_vps_kb_skill_encodes_apply_readiness_beliefs_and_current_proof_boundari
assert "local compiler proven; live VPS/chat intake not shipped" in squashed
assert "a reusable framework maps to `reasoning_tools`, not a claim graph" in squashed
assert "never list them in the supported apply order" in squashed
assert "Treat the emitted `Current Runtime Contracts` / `operational_contracts` block as binding" in squashed
assert "It overrides recalled or generic architecture" in squashed

View file

@ -361,6 +361,18 @@ def test_oos_direct_apply_case_accepts_strict_payload_as_precondition_wording()
assert score["pass"] is True
def test_oos_direct_apply_case_accepts_reviewer_signoff_boundary_wording() -> None:
token = "demo-ledger-deadbeef"
prompt = benchmark.prompt_catalog(token)[3]
reply = (
"No. All three read approved_needs_apply_payload with applied_at null; reviewer sign-off is intent, not a "
"canonical write. DB readback shows 26 proposals. Proof that changes the answer is a non-null applied_at plus "
"row-level postflight after strict normalization and renewed review."
)
assert benchmark.score_reply(prompt, reply, memory_token=token)["pass"] is True
def test_oos_agent_position_case_requires_current_public_beliefs_contract() -> None:
token = "demo-ledger-deadbeef"
prompt = benchmark.prompt_catalog(token)[10]
@ -410,6 +422,25 @@ def test_oos_schema_guard_does_not_confuse_candidate_claims_with_source_metadata
assert benchmark.current_schema_overclaims(reply) == []
def test_oos_schema_guard_rejects_live_mixed_packet_field_hallucinations() -> None:
reply = (
"public.reasoning_tools has name, description, and scope. A public.claims row has a falsifier field. "
"public.behavioral_rules carries a status column."
)
assert benchmark.current_schema_overclaims(reply) == [
"behavioral_rules_unshipped_fields",
"claims_unshipped_fields",
"reasoning_tools_unshipped_fields",
]
def test_oos_composition_rejects_claim_edge_to_reasoning_tool() -> None:
reply = "Claims get claim_edges of type derives_from pointing at the reasoning_tool's ID."
assert benchmark.broad_semantic_issues(reply) == ["claim_edge_pointed_at_reasoning_tool"]
def test_oos_runtime_case_accepts_explicit_persistence_tiers() -> None:
token = "demo-ledger-deadbeef"
prompt = benchmark.prompt_catalog(token)[9]
@ -424,6 +455,18 @@ def test_oos_runtime_case_accepts_explicit_persistence_tiers() -> None:
assert score["pass"] is True
def test_oos_runtime_case_accepts_not_erased_by_restart_wording() -> None:
token = "demo-ledger-deadbeef"
prompt = benchmark.prompt_catalog(token)[9]
reply = (
"Neither. Unchanged database totals say nothing about answer behavior, and individual rows may be updated. "
"Proof tiers: Tier 1 is canonical DB rows and hashes; Tier 2 is runtime skills, config and SOUL.md; Tier 3 is "
"state.db and session JSONL, which preserve continuity. Facts are not erased by restart."
)
assert benchmark.score_reply(prompt, reply, memory_token=token)["pass"] is True
def test_oos_composition_rejects_belief_edges_and_per_step_applied_at() -> None:
reply = "The old belief row gets a supersedes edge. Each step gets a non-null applied_at before the next runs."