First consumer of en_core_relational_predicates_v1: a fail-closed sibling reader that maps '<A> is [the] <connective> <B>' onto the pack's closed predicate vocabulary (parent_of, less_than, left_of, before_event, ...), producing a standard Comprehension. realize_comprehension consumes it unchanged; determine's guard widens from the single 'member' predicate to a CLOSED direct-entailment set (member + the ground binary relational predicates), keeping categorical/propositional predicates soundly excluded. Direct entailment only — no transitive/symmetric/rule inference (symmetric-converse questions are a sound-but-incomplete refusal, never a faked assertion). Only the predicate is closed-vocabulary; arguments may be OOV. The pack is loaded explicitly, not default-mounted. wrong=0 bites: reader refuses non-template/negated/pack-absent surfaces; determine asserts only on direct entailment and excludes categorical predicates.
133 lines
6.4 KiB
Python
133 lines
6.4 KiB
Python
"""DETERMINE (roadmap Step 4) — reason over realized structure → the honest gear.
|
|
|
|
A question (a query-bearing ``Comprehension``) is answered ONLY from what the held
|
|
self has already REALIZED (R0/R1 structural recall) — never from the field, never
|
|
from an LLM, never from absence. The verdict is **as-told, never "verified"**: every
|
|
realizable record is SPECULATIVE, and ``ADMISSIBLE_AS_EVIDENCE = {COHERENT}``, so a
|
|
determination grounded in SPECULATIVE records carries ``basis="as_told"`` — "based on
|
|
what I was told (unverified)". Until COHERENT promotion exists (out of scope), D0
|
|
produces only ``as_told`` assertions or ``Undetermined`` refusals. No estimation, no
|
|
corpus mutation (teaching stays HITL proposal-only).
|
|
|
|
wrong=0 / soundness (open-world): D0 asserts an answer ONLY when the asked relation
|
|
is DIRECTLY entailed by a realized fact. Absence of a fact never refutes it
|
|
(open-world), so D0 never asserts an answer from missing knowledge — it refuses
|
|
(``Undetermined``). It asserts only ``answer=True`` on a direct hit; it never asserts
|
|
False.
|
|
|
|
Supported predicates are a CLOSED set for which DIRECT entailment is sound — a
|
|
realized ground fact ``p(subject, target)`` answers the asked ``p(subject, target)``:
|
|
the ``member`` relation (subsumption / "Is X a Y?") and the binary relational
|
|
predicates of ``en_core_relational_predicates_v1`` (``parent_of``, ``less_than``,
|
|
``left_of``, ``before_event`` …; see ``generate.meaning_graph.relational``). The
|
|
categorical (``subset``/``disjoint`` …) and propositional (``implies``/``or`` …)
|
|
predicates are deliberately EXCLUDED — their truth is not a stored-pair lookup, so
|
|
admitting them would be unsound. Negated questions, symmetric-converse questions, and
|
|
any predicate outside the closed set are an honest ``Undetermined`` — D0 ships no
|
|
entailment path it cannot exercise (no transitive/symmetric/rule inference).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
|
|
from generate.meaning_graph.reader import Comprehension, Refusal
|
|
from generate.meaning_graph.relational import RELATIONAL_PREDICATES
|
|
from generate.realize import RealizedRecord, recall_realized
|
|
from session.context import SessionContext
|
|
from teaching.epistemic import ADMISSIBLE_AS_EVIDENCE, EpistemicStatus
|
|
|
|
#: The CLOSED set of query predicates D0 has a SOUND direct-entailment path for:
|
|
#: ``member`` plus the ground binary relational predicates. Direct entailment is
|
|
#: "a realized fact ``p(s, t)`` directly answers the asked ``p(s, t)``" — sound for
|
|
#: these ground relations, unsound for categorical/propositional predicates (excluded).
|
|
_SUPPORTED_PREDICATES = frozenset({"member"}) | RELATIONAL_PREDICATES
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class Determined:
|
|
"""An answer reasoned from realized structure.
|
|
|
|
``basis`` is the epistemic standing of the grounding: ``"as_told"`` when the
|
|
grounds are SPECULATIVE (candidate memory — the only case today), ``"verified"``
|
|
only if every ground is admissible-as-evidence (COHERENT — not yet reachable).
|
|
``answer`` is the truth of the asked (possibly negated) question.
|
|
"""
|
|
|
|
answer: bool
|
|
basis: str
|
|
predicate: str
|
|
subject: str
|
|
object: str
|
|
grounds: tuple[RealizedRecord, ...]
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class Undetermined:
|
|
"""No honest answer (refusal). ``reason`` is for audit, not control."""
|
|
|
|
reason: str
|
|
|
|
|
|
def _basis(grounds: tuple[RealizedRecord, ...]) -> str:
|
|
"""Carry the grounds' epistemic standing forward — never overclaim "verified"."""
|
|
statuses = {EpistemicStatus(g.epistemic_status) for g in grounds}
|
|
return "verified" if statuses and statuses <= ADMISSIBLE_AS_EVIDENCE else "as_told"
|
|
|
|
|
|
def determine(
|
|
question: Comprehension | Refusal, ctx: SessionContext
|
|
) -> Determined | Undetermined:
|
|
"""Answer a membership-or-relational question from realized structure, or refuse.
|
|
|
|
Eligibility: a query-bearing ``Comprehension`` with exactly one binary,
|
|
non-negated query whose predicate is in the closed direct-entailment set
|
|
(``member`` or a relational pack predicate). The answer is asserted ONLY on direct
|
|
structural entailment by a realized fact of the SAME predicate; everything else is
|
|
a typed ``Undetermined`` (open-world: absence never asserts a positive answer).
|
|
"""
|
|
if isinstance(question, Refusal):
|
|
return Undetermined("refusal")
|
|
if not isinstance(question, Comprehension):
|
|
return Undetermined("not_a_comprehension")
|
|
if len(question.queries) != 1:
|
|
return Undetermined("not_single_query") # a determination answers one question
|
|
|
|
query = question.queries[0]
|
|
if query.predicate not in _SUPPORTED_PREDICATES:
|
|
return Undetermined("unsupported_query") # honest: closed direct-entailment set
|
|
if len(query.arguments) != 2:
|
|
return Undetermined("malformed_query") # member is binary by construction
|
|
if query.negated:
|
|
# Realized facts are all positive (R0/R1 refuse negated relations), so a
|
|
# negated question would only ever be answered from the positive's presence.
|
|
# D0 declines it explicitly rather than ship an entailment path the reader
|
|
# cannot exercise (it refuses negated membership questions upstream anyway).
|
|
return Undetermined("negated_query_unsupported")
|
|
|
|
predicate = query.predicate
|
|
subject, target = query.arguments[0], query.arguments[1]
|
|
|
|
# Structural recall: the realized facts of this predicate about this subject (R1a).
|
|
# Exact, deterministic, versor-collision-irrelevant — never a metric call.
|
|
facts = recall_realized(ctx, subject=subject, predicate=predicate)
|
|
if not facts:
|
|
return Undetermined("ungrounded") # nothing realized about the subject
|
|
|
|
# Direct entailment: a realized p(subject, target) holds as-told. Open-world:
|
|
# facts about the subject that do NOT match the asked target never refute it, so a
|
|
# miss is a refusal (``not_entailed``), never an asserted False. Symmetric relations
|
|
# (sibling_of, equal_to …) read only the stored direction here — the converse is a
|
|
# sound-but-incomplete ``not_entailed``, never a fabricated assertion.
|
|
grounding = next((f for f in facts if f.relation_arguments == (subject, target)), None)
|
|
if grounding is None:
|
|
return Undetermined("not_entailed")
|
|
|
|
return Determined(
|
|
answer=True,
|
|
basis=_basis((grounding,)),
|
|
predicate=predicate,
|
|
subject=subject,
|
|
object=target,
|
|
grounds=(grounding,),
|
|
)
|