chore(derivation): clean Inc3 diff hygiene
This commit is contained in:
parent
3fc81f66a4
commit
64eaf43cd8
3 changed files with 97 additions and 257 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
# CORE Problem-Solving Capability Roadmap v2 — 2026-06-17
|
# CORE Problem-Solving Capability Roadmap v2 — 2026-06-17
|
||||||
|
|
||||||
**Status:** Living document (docs-only update)
|
**Status:** Living document (docs-only update)
|
||||||
**Date:** 2026-06-17
|
**Date:** 2026-06-17
|
||||||
**Context:** Post PR #797 (rate injection) + #798; preparing Inc3 rate follow-up before Gate A1 comparative injection.
|
**Context:** Post PR #797 (rate injection) + #798; preparing Inc3 rate follow-up before Gate A1 comparative injection.
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
# GSM8K Workstream A Increment 3 — rate followup (post-#797) ratification
|
# GSM8K Workstream A Increment 3 — rate followup (post-#797) ratification
|
||||||
|
|
||||||
**Date:** 2026-06-17
|
**Date:** 2026-06-17
|
||||||
**Workstream:** A
|
**Workstream:** A
|
||||||
**Increment:** 3 — post-#797 rate frontier evidence loop closure (narrow)
|
**Increment:** 3 — post-#797 rate frontier evidence loop closure (narrow)
|
||||||
**Status:** Ratified for implementation (BEFORE code changes)
|
**Status:** Ratified for implementation (BEFORE code changes)
|
||||||
**Scope lock:** Bounded to making the rate "recognized_no_injection" bucket produce actionable evidence by resolving the explicit remaining connector blocker left open in #797. One smallest change only.
|
**Scope lock:** Bounded to making the rate "recognized_no_injection" bucket produce actionable evidence by resolving the explicit remaining connector blocker left open in #797. One smallest change only.
|
||||||
|
|
||||||
## 1. Which exact refusal bucket is being attacked?
|
## 1. Which exact refusal bucket is being attacked?
|
||||||
|
|
|
||||||
|
|
@ -57,214 +57,91 @@ from generate.math_problem_graph import Comparison, Operation, Quantity, Rate
|
||||||
|
|
||||||
# Surface verbs that grammatically place the actor as the *gainer* of the
|
# Surface verbs that grammatically place the actor as the *gainer* of the
|
||||||
# operand quantity. Past tense and present tense both registered.
|
# operand quantity. Past tense and present tense both registered.
|
||||||
ADD_VERBS: Final[frozenset[str]] = frozenset(
|
ADD_VERBS: Final[frozenset[str]] = frozenset({
|
||||||
{
|
# acquisition
|
||||||
# acquisition
|
"buy", "buys", "bought",
|
||||||
"buy",
|
"get", "gets", "got",
|
||||||
"buys",
|
"find", "finds", "found",
|
||||||
"bought",
|
"receive", "receives", "received",
|
||||||
"get",
|
"earn", "earns", "earned",
|
||||||
"gets",
|
"add", "adds", "added",
|
||||||
"got",
|
"pick", "picks", "picked", # "picks up N"
|
||||||
"find",
|
"collect", "collects", "collected",
|
||||||
"finds",
|
"gather", "gathers", "gathered",
|
||||||
"found",
|
"catch", "catches", "caught",
|
||||||
"receive",
|
"save", "saves", "saved",
|
||||||
"receives",
|
# production (actor creates instances of the unit)
|
||||||
"received",
|
"bake", "bakes", "baked",
|
||||||
"earn",
|
"make", "makes", "made",
|
||||||
"earns",
|
"cook", "cooks", "cooked",
|
||||||
"earned",
|
"slice", "slices", "sliced",
|
||||||
"add",
|
"pack", "packs", "packed",
|
||||||
"adds",
|
"build", "builds", "built",
|
||||||
"added",
|
"grow", "grows", "grew",
|
||||||
"pick",
|
})
|
||||||
"picks",
|
|
||||||
"picked", # "picks up N"
|
|
||||||
"collect",
|
|
||||||
"collects",
|
|
||||||
"collected",
|
|
||||||
"gather",
|
|
||||||
"gathers",
|
|
||||||
"gathered",
|
|
||||||
"catch",
|
|
||||||
"catches",
|
|
||||||
"caught",
|
|
||||||
"save",
|
|
||||||
"saves",
|
|
||||||
"saved",
|
|
||||||
# production (actor creates instances of the unit)
|
|
||||||
"bake",
|
|
||||||
"bakes",
|
|
||||||
"baked",
|
|
||||||
"make",
|
|
||||||
"makes",
|
|
||||||
"made",
|
|
||||||
"cook",
|
|
||||||
"cooks",
|
|
||||||
"cooked",
|
|
||||||
"slice",
|
|
||||||
"slices",
|
|
||||||
"sliced",
|
|
||||||
"pack",
|
|
||||||
"packs",
|
|
||||||
"packed",
|
|
||||||
"build",
|
|
||||||
"builds",
|
|
||||||
"built",
|
|
||||||
"grow",
|
|
||||||
"grows",
|
|
||||||
"grew",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Surface verbs that grammatically place the actor as the *loser* of the
|
# Surface verbs that grammatically place the actor as the *loser* of the
|
||||||
# operand quantity.
|
# operand quantity.
|
||||||
SUBTRACT_VERBS: Final[frozenset[str]] = frozenset(
|
SUBTRACT_VERBS: Final[frozenset[str]] = frozenset({
|
||||||
{
|
"eat", "eats", "ate",
|
||||||
"eat",
|
"lose", "loses", "lost",
|
||||||
"eats",
|
"sell", "sells", "sold",
|
||||||
"ate",
|
"donate", "donates", "donated",
|
||||||
"lose",
|
"use", "uses", "used",
|
||||||
"loses",
|
"spend", "spends", "spent",
|
||||||
"lost",
|
"drop", "drops", "dropped",
|
||||||
"sell",
|
"remove", "removes", "removed",
|
||||||
"sells",
|
"break", "breaks", "broke",
|
||||||
"sold",
|
"destroy", "destroys", "destroyed",
|
||||||
"donate",
|
"throw", "throws", "threw", # "throws out N"
|
||||||
"donates",
|
"discard", "discards", "discarded",
|
||||||
"donated",
|
"return", "returns", "returned", # ambiguous — see TRANSFER_VERBS
|
||||||
"use",
|
"consume", "consumes", "consumed",
|
||||||
"uses",
|
"give", "gives", "gave", # ambiguous — see TRANSFER_VERBS
|
||||||
"used",
|
"send", "sends", "sent", # ambiguous — see TRANSFER_VERBS
|
||||||
"spend",
|
})
|
||||||
"spends",
|
|
||||||
"spent",
|
|
||||||
"drop",
|
|
||||||
"drops",
|
|
||||||
"dropped",
|
|
||||||
"remove",
|
|
||||||
"removes",
|
|
||||||
"removed",
|
|
||||||
"break",
|
|
||||||
"breaks",
|
|
||||||
"broke",
|
|
||||||
"destroy",
|
|
||||||
"destroys",
|
|
||||||
"destroyed",
|
|
||||||
"throw",
|
|
||||||
"throws",
|
|
||||||
"threw", # "throws out N"
|
|
||||||
"discard",
|
|
||||||
"discards",
|
|
||||||
"discarded",
|
|
||||||
"return",
|
|
||||||
"returns",
|
|
||||||
"returned", # ambiguous — see TRANSFER_VERBS
|
|
||||||
"consume",
|
|
||||||
"consumes",
|
|
||||||
"consumed",
|
|
||||||
"give",
|
|
||||||
"gives",
|
|
||||||
"gave", # ambiguous — see TRANSFER_VERBS
|
|
||||||
"send",
|
|
||||||
"sends",
|
|
||||||
"sent", # ambiguous — see TRANSFER_VERBS
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Surface verbs that grammatically place the actor as the *sender* and a
|
# Surface verbs that grammatically place the actor as the *sender* and a
|
||||||
# named target as the *receiver*. These verbs ALSO appear in SUBTRACT_VERBS
|
# named target as the *receiver*. These verbs ALSO appear in SUBTRACT_VERBS
|
||||||
# because the same surface token can take a transfer reading (with target)
|
# because the same surface token can take a transfer reading (with target)
|
||||||
# or a subtract reading (without target) — both candidates fire and the
|
# or a subtract reading (without target) — both candidates fire and the
|
||||||
# decision rule picks based on whether a target slot was grounded.
|
# decision rule picks based on whether a target slot was grounded.
|
||||||
TRANSFER_VERBS: Final[frozenset[str]] = frozenset(
|
TRANSFER_VERBS: Final[frozenset[str]] = frozenset({
|
||||||
{
|
"give", "gives", "gave",
|
||||||
"give",
|
"send", "sends", "sent",
|
||||||
"gives",
|
"hand", "hands", "handed",
|
||||||
"gave",
|
"pass", "passes", "passed",
|
||||||
"send",
|
"mail", "mails", "mailed",
|
||||||
"sends",
|
"deliver", "delivers", "delivered",
|
||||||
"sent",
|
"return", "returns", "returned",
|
||||||
"hand",
|
})
|
||||||
"hands",
|
|
||||||
"handed",
|
|
||||||
"pass",
|
|
||||||
"passes",
|
|
||||||
"passed",
|
|
||||||
"mail",
|
|
||||||
"mails",
|
|
||||||
"mailed",
|
|
||||||
"deliver",
|
|
||||||
"delivers",
|
|
||||||
"delivered",
|
|
||||||
"return",
|
|
||||||
"returns",
|
|
||||||
"returned",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
MULTIPLY_VERBS: Final[frozenset[str]] = frozenset(
|
MULTIPLY_VERBS: Final[frozenset[str]] = frozenset({
|
||||||
{
|
"double", "doubles", "doubled",
|
||||||
"double",
|
"triple", "triples", "tripled",
|
||||||
"doubles",
|
"quadruple", "quadruples", "quadrupled",
|
||||||
"doubled",
|
"multiply", "multiplies", "multiplied",
|
||||||
"triple",
|
})
|
||||||
"triples",
|
|
||||||
"tripled",
|
|
||||||
"quadruple",
|
|
||||||
"quadruples",
|
|
||||||
"quadrupled",
|
|
||||||
"multiply",
|
|
||||||
"multiplies",
|
|
||||||
"multiplied",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
DIVIDE_VERBS: Final[frozenset[str]] = frozenset(
|
DIVIDE_VERBS: Final[frozenset[str]] = frozenset({
|
||||||
{
|
"halve", "halves", "halved",
|
||||||
"halve",
|
"split", "splits", "split",
|
||||||
"halves",
|
"divide", "divides", "divided",
|
||||||
"halved",
|
"share", "shares", "shared",
|
||||||
"split",
|
})
|
||||||
"splits",
|
|
||||||
"split",
|
|
||||||
"divide",
|
|
||||||
"divides",
|
|
||||||
"divided",
|
|
||||||
"share",
|
|
||||||
"shares",
|
|
||||||
"shared",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Comparison "verbs" — the surface anchor for compare_additive /
|
# Comparison "verbs" — the surface anchor for compare_additive /
|
||||||
# compare_multiplicative is usually 'has'/'have' + comparator phrase
|
# compare_multiplicative is usually 'has'/'have' + comparator phrase
|
||||||
# ('N more than', 'twice as many as', etc.). The matched_verb slot for
|
# ('N more than', 'twice as many as', etc.). The matched_verb slot for
|
||||||
# comparison candidates carries the comparator phrase head ('more',
|
# comparison candidates carries the comparator phrase head ('more',
|
||||||
# 'fewer', 'twice', 'times', 'half').
|
# 'fewer', 'twice', 'times', 'half').
|
||||||
COMPARE_ADDITIVE_ANCHORS: Final[frozenset[str]] = frozenset(
|
COMPARE_ADDITIVE_ANCHORS: Final[frozenset[str]] = frozenset({
|
||||||
{
|
"more", "fewer", "less", "additional", "extra",
|
||||||
"more",
|
})
|
||||||
"fewer",
|
COMPARE_MULTIPLICATIVE_ANCHORS: Final[frozenset[str]] = frozenset({
|
||||||
"less",
|
"twice", "thrice", "times", "half", "double", "triple",
|
||||||
"additional",
|
"quadruple", "third", "quarter",
|
||||||
"extra",
|
})
|
||||||
}
|
|
||||||
)
|
|
||||||
COMPARE_MULTIPLICATIVE_ANCHORS: Final[frozenset[str]] = frozenset(
|
|
||||||
{
|
|
||||||
"twice",
|
|
||||||
"thrice",
|
|
||||||
"times",
|
|
||||||
"half",
|
|
||||||
"double",
|
|
||||||
"triple",
|
|
||||||
"quadruple",
|
|
||||||
"third",
|
|
||||||
"quarter",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Rate anchors (ADR-0122): "per", "each", "every", "a"/"an" (when followed
|
# Rate anchors (ADR-0122): "per", "each", "every", "a"/"an" (when followed
|
||||||
# by a unit in a rate surface such as "$18 an hour" or "$2 a cup").
|
# by a unit in a rate surface such as "$18 an hour" or "$2 a cup").
|
||||||
|
|
@ -272,16 +149,9 @@ COMPARE_MULTIPLICATIVE_ANCHORS: Final[frozenset[str]] = frozenset(
|
||||||
# so that roundtrip_admissible / CandidateOperation post-init grounding
|
# so that roundtrip_admissible / CandidateOperation post-init grounding
|
||||||
# succeeds. "a"/"an" were documented in the comment but missing from the
|
# succeeds. "a"/"an" were documented in the comment but missing from the
|
||||||
# set; added here (Inc 2) with corresponding injector tests.
|
# set; added here (Inc 2) with corresponding injector tests.
|
||||||
RATE_ANCHORS: Final[frozenset[str]] = frozenset(
|
RATE_ANCHORS: Final[frozenset[str]] = frozenset({
|
||||||
{
|
"per", "each", "every", "a", "an", "one",
|
||||||
"per",
|
})
|
||||||
"each",
|
|
||||||
"every",
|
|
||||||
"a",
|
|
||||||
"an",
|
|
||||||
"one",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
KIND_TO_VERBS: Final[Mapping[str, frozenset[str]]] = {
|
KIND_TO_VERBS: Final[Mapping[str, frozenset[str]]] = {
|
||||||
|
|
@ -302,40 +172,15 @@ KIND_TO_VERBS: Final[Mapping[str, frozenset[str]]] = {
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
WORD_NUMBERS: Final[Mapping[str, int]] = {
|
WORD_NUMBERS: Final[Mapping[str, int]] = {
|
||||||
"zero": 0,
|
"zero": 0, "one": 1, "two": 2, "three": 3, "four": 4,
|
||||||
"one": 1,
|
"five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9,
|
||||||
"two": 2,
|
"ten": 10, "eleven": 11, "twelve": 12, "thirteen": 13,
|
||||||
"three": 3,
|
"fourteen": 14, "fifteen": 15, "sixteen": 16, "seventeen": 17,
|
||||||
"four": 4,
|
"eighteen": 18, "nineteen": 19, "twenty": 20, "thirty": 30,
|
||||||
"five": 5,
|
"forty": 40, "fifty": 50, "sixty": 60, "seventy": 70,
|
||||||
"six": 6,
|
"eighty": 80, "ninety": 90, "hundred": 100, "thousand": 1000,
|
||||||
"seven": 7,
|
|
||||||
"eight": 8,
|
|
||||||
"nine": 9,
|
|
||||||
"ten": 10,
|
|
||||||
"eleven": 11,
|
|
||||||
"twelve": 12,
|
|
||||||
"thirteen": 13,
|
|
||||||
"fourteen": 14,
|
|
||||||
"fifteen": 15,
|
|
||||||
"sixteen": 16,
|
|
||||||
"seventeen": 17,
|
|
||||||
"eighteen": 18,
|
|
||||||
"nineteen": 19,
|
|
||||||
"twenty": 20,
|
|
||||||
"thirty": 30,
|
|
||||||
"forty": 40,
|
|
||||||
"fifty": 50,
|
|
||||||
"sixty": 60,
|
|
||||||
"seventy": 70,
|
|
||||||
"eighty": 80,
|
|
||||||
"ninety": 90,
|
|
||||||
"hundred": 100,
|
|
||||||
"thousand": 1000,
|
|
||||||
# ordinals as factor-bearing forms ("a third", "a quarter")
|
# ordinals as factor-bearing forms ("a third", "a quarter")
|
||||||
"half": 2,
|
"half": 2, "third": 3, "quarter": 4,
|
||||||
"third": 3,
|
|
||||||
"quarter": 4,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -343,7 +188,6 @@ WORD_NUMBERS: Final[Mapping[str, int]] = {
|
||||||
# Public dataclass — what the candidate-graph parser will emit per match.
|
# Public dataclass — what the candidate-graph parser will emit per match.
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True, slots=True)
|
@dataclass(frozen=True, slots=True)
|
||||||
class CandidateOperation:
|
class CandidateOperation:
|
||||||
"""An Operation candidate plus the source-span provenance proving it.
|
"""An Operation candidate plus the source-span provenance proving it.
|
||||||
|
|
@ -389,26 +233,29 @@ class CandidateOperation:
|
||||||
raise ValueError("CandidateOperation.source_span must be non-empty")
|
raise ValueError("CandidateOperation.source_span must be non-empty")
|
||||||
if not isinstance(self.matched_verb, str) or not self.matched_verb:
|
if not isinstance(self.matched_verb, str) or not self.matched_verb:
|
||||||
raise ValueError("CandidateOperation.matched_verb must be non-empty")
|
raise ValueError("CandidateOperation.matched_verb must be non-empty")
|
||||||
if (
|
if not isinstance(self.matched_actor_token, str) or not self.matched_actor_token:
|
||||||
not isinstance(self.matched_actor_token, str)
|
raise ValueError(
|
||||||
or not self.matched_actor_token
|
"CandidateOperation.matched_actor_token must be non-empty"
|
||||||
):
|
)
|
||||||
raise ValueError("CandidateOperation.matched_actor_token must be non-empty")
|
|
||||||
if self.op.kind == "transfer":
|
if self.op.kind == "transfer":
|
||||||
if not self.matched_target_token:
|
if not self.matched_target_token:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"matched_target_token required when op.kind='transfer'"
|
"matched_target_token required when op.kind='transfer'"
|
||||||
)
|
)
|
||||||
elif self.matched_target_token is not None:
|
elif self.matched_target_token is not None:
|
||||||
raise ValueError("matched_target_token only valid when op.kind='transfer'")
|
raise ValueError(
|
||||||
|
"matched_target_token only valid when op.kind='transfer'"
|
||||||
|
)
|
||||||
if isinstance(self.op.operand, Comparison):
|
if isinstance(self.op.operand, Comparison):
|
||||||
if not self.matched_reference_actor_token:
|
if not self.matched_reference_actor_token:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"matched_reference_actor_token required when operand is Comparison"
|
"matched_reference_actor_token required when operand is "
|
||||||
|
"Comparison"
|
||||||
)
|
)
|
||||||
elif self.matched_reference_actor_token is not None:
|
elif self.matched_reference_actor_token is not None:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"matched_reference_actor_token only valid when operand is Comparison"
|
"matched_reference_actor_token only valid when operand is "
|
||||||
|
"Comparison"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -531,7 +378,6 @@ def _value_grounds(value_token: str, haystack_tokens: frozenset[str]) -> bool:
|
||||||
if "-" in value_token and not value_token[0].isdigit():
|
if "-" in value_token and not value_token[0].isdigit():
|
||||||
try:
|
try:
|
||||||
from language_packs.numerics_loader import parse_compound_cardinal
|
from language_packs.numerics_loader import parse_compound_cardinal
|
||||||
|
|
||||||
parsed = parse_compound_cardinal(value_token)
|
parsed = parse_compound_cardinal(value_token)
|
||||||
if parsed is not None:
|
if parsed is not None:
|
||||||
components = [c for c in value_token.lower().split("-") if c]
|
components = [c for c in value_token.lower().split("-") if c]
|
||||||
|
|
@ -551,7 +397,6 @@ def _value_grounds(value_token: str, haystack_tokens: frozenset[str]) -> bool:
|
||||||
# through to the hard-coded table.
|
# through to the hard-coded table.
|
||||||
try:
|
try:
|
||||||
from language_packs.loader import lookup_cardinal
|
from language_packs.loader import lookup_cardinal
|
||||||
|
|
||||||
entry = lookup_cardinal(lowered)
|
entry = lookup_cardinal(lowered)
|
||||||
if entry is not None:
|
if entry is not None:
|
||||||
digit = str(entry.numeric_value)
|
digit = str(entry.numeric_value)
|
||||||
|
|
@ -576,7 +421,6 @@ def _value_grounds(value_token: str, haystack_tokens: frozenset[str]) -> bool:
|
||||||
# Pack-backed reverse lookup: digit -> cardinal surface in haystack
|
# Pack-backed reverse lookup: digit -> cardinal surface in haystack
|
||||||
try:
|
try:
|
||||||
from language_packs.loader import lookup_cardinal
|
from language_packs.loader import lookup_cardinal
|
||||||
|
|
||||||
for tok in haystack_tokens:
|
for tok in haystack_tokens:
|
||||||
entry = lookup_cardinal(tok)
|
entry = lookup_cardinal(tok)
|
||||||
if entry is not None and entry.numeric_value == n:
|
if entry is not None and entry.numeric_value == n:
|
||||||
|
|
@ -590,7 +434,6 @@ def _value_grounds(value_token: str, haystack_tokens: frozenset[str]) -> bool:
|
||||||
# The load-bearing primitive.
|
# The load-bearing primitive.
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def roundtrip_admissible(c: CandidateOperation) -> bool:
|
def roundtrip_admissible(c: CandidateOperation) -> bool:
|
||||||
"""True iff every content slot in ``c`` grounds in ``c.source_span``
|
"""True iff every content slot in ``c`` grounds in ``c.source_span``
|
||||||
AND the matched verb is registered for the operation kind.
|
AND the matched verb is registered for the operation kind.
|
||||||
|
|
@ -619,10 +462,7 @@ def roundtrip_admissible(c: CandidateOperation) -> bool:
|
||||||
# Skipped only for multiplicative comparison anchors that carry
|
# Skipped only for multiplicative comparison anchors that carry
|
||||||
# the factor implicitly ("twice", "half", "thrice") — those use
|
# the factor implicitly ("twice", "half", "thrice") — those use
|
||||||
# the anchor itself as the value token and pass via step (2).
|
# the anchor itself as the value token and pass via step (2).
|
||||||
if (
|
if c.op.kind == "compare_multiplicative" and c.matched_value_token == c.matched_verb:
|
||||||
c.op.kind == "compare_multiplicative"
|
|
||||||
and c.matched_value_token == c.matched_verb
|
|
||||||
):
|
|
||||||
pass # anchor already grounded by verb check
|
pass # anchor already grounded by verb check
|
||||||
elif not _value_grounds(c.matched_value_token, haystack):
|
elif not _value_grounds(c.matched_value_token, haystack):
|
||||||
return False
|
return False
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue