Increment 2 for ADR-0252 Track B. Extends Increment 1's structure-mapping slice with pure-family canonicals S2–S4, overlapping-waves selector, and a structure-mapping-owned pure-S1 text extract that recovers four real holdout cases the serving reader misses (0148, 0228, 0234, 0441). Bar results (command-backed via scripts/measure_trackb_inc2.py): - generalization ratio S1 = 9.0 (9 holdout cases / 1 template) - coverage gain organ 5 → trackb 9, wrong=0 - selector routes S1/S2/S3; refuses empty; surface≠structure Off-serving: no organ retirement, serving reader untouched. S2–S4 holdout ratios are 0 (parser frontier). S3/S4 emit refuses at multi-register scope without weakening the three-gate wrong=0 path. [Verification]: Smoke suite passed locally (~132s, 176 passed); trackb unit tests 35 passed; measure_trackb_inc2 all modes green.
119 lines
3.6 KiB
Python
119 lines
3.6 KiB
Python
"""Canonical role-predicate skeletons (expert schema library).
|
||
|
||
Track B Increment 2: S1–S4. Each is a typed role skeleton with abstract
|
||
``var`` terms only — no surface literals as schema identity.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass
|
||
|
||
from generate.structure_mapping.role_predicate import RolePredicate, RoleTerm
|
||
|
||
|
||
@dataclass(frozen=True, slots=True)
|
||
class CanonicalStructure:
|
||
"""A named schema with abstract role variables (not surface attributes)."""
|
||
|
||
structure_id: str
|
||
"""Stable id for the schema (e.g. ``S1``). Library key only — never read
|
||
from gold labels at match time."""
|
||
|
||
description: str
|
||
predicates: tuple[RolePredicate, ...]
|
||
"""Abstract skeleton; terms are ``var`` roles only."""
|
||
|
||
|
||
def _var(name: str) -> RoleTerm:
|
||
return RoleTerm(kind="var", name=name)
|
||
|
||
|
||
# S1: "b is k× a; find a+b"
|
||
# compare(b, a, k) ∧ contain(a, a_qty) ∧ total(a, b, sum)
|
||
# (seed may equivalently be on b; mapper recovers a_value = b_value/k)
|
||
S1_CANONICAL: CanonicalStructure = CanonicalStructure(
|
||
structure_id="S1",
|
||
description=(
|
||
"compare-multiplicative-then-total: b = k×a; query a+b. "
|
||
"Roles: a=reference quantity entity, b=scaled entity, k=factor."
|
||
),
|
||
predicates=(
|
||
RolePredicate(
|
||
kind="contain",
|
||
args=(_var("a"), _var("a_qty")),
|
||
),
|
||
RolePredicate(
|
||
kind="compare",
|
||
args=(_var("b"), _var("a"), _var("k")),
|
||
),
|
||
RolePredicate(
|
||
kind="total",
|
||
args=(_var("a"), _var("b"), _var("sum")),
|
||
),
|
||
),
|
||
)
|
||
|
||
# S2: transfer-then-query — contain(src), contain(dst), transfer(src→dst, qty);
|
||
# query one endpoint after the transfer.
|
||
S2_CANONICAL: CanonicalStructure = CanonicalStructure(
|
||
structure_id="S2",
|
||
description=(
|
||
"transfer-then-query: src and dst seeded; qty moves src→dst; "
|
||
"query one endpoint's post-transfer amount."
|
||
),
|
||
predicates=(
|
||
RolePredicate(kind="contain", args=(_var("src"), _var("src_qty"))),
|
||
RolePredicate(kind="contain", args=(_var("dst"), _var("dst_qty"))),
|
||
RolePredicate(
|
||
kind="transfer",
|
||
args=(_var("src"), _var("dst"), _var("xfer_qty")),
|
||
),
|
||
),
|
||
)
|
||
|
||
# S3: rate-application — rate × count → total (or invert).
|
||
S3_CANONICAL: CanonicalStructure = CanonicalStructure(
|
||
structure_id="S3",
|
||
description=(
|
||
"rate-application: per_unit rate applied over count yields total. "
|
||
"Roles: rate_value, count, total_slot."
|
||
),
|
||
predicates=(
|
||
RolePredicate(
|
||
kind="rate",
|
||
args=(_var("rate_value"), _var("count"), _var("total_slot")),
|
||
),
|
||
),
|
||
)
|
||
|
||
# S4: additive-comparison-then-total — b = a + delta; query a+b.
|
||
# Uses compare_add (additive twin of multiplicative compare).
|
||
S4_CANONICAL: CanonicalStructure = CanonicalStructure(
|
||
structure_id="S4",
|
||
description=(
|
||
"additive-comparison-then-total: b = a + delta; query a+b. "
|
||
"Roles: a=reference, b=offset entity, delta=additive gap."
|
||
),
|
||
predicates=(
|
||
RolePredicate(kind="contain", args=(_var("a"), _var("a_qty"))),
|
||
RolePredicate(
|
||
kind="compare_add",
|
||
args=(_var("b"), _var("a"), _var("delta")),
|
||
),
|
||
RolePredicate(
|
||
kind="total",
|
||
args=(_var("a"), _var("b"), _var("sum")),
|
||
),
|
||
),
|
||
)
|
||
|
||
CANONICAL_LIBRARY: tuple[CanonicalStructure, ...] = (
|
||
S1_CANONICAL,
|
||
S2_CANONICAL,
|
||
S3_CANONICAL,
|
||
S4_CANONICAL,
|
||
)
|
||
|
||
CANONICAL_BY_ID: dict[str, CanonicalStructure] = {
|
||
c.structure_id: c for c in CANONICAL_LIBRARY
|
||
}
|