tariffwise / engine.py
Mussez's picture
Upload 6 files
f4dcb85 verified
Raw
History Blame Contribute Delete
18.6 kB
"""TariffWise engine. Deterministic walk of the Chapter 64 tree.
The walk descends from a heading to a ten digit leaf. At each node the
children are evaluated in schedule order. A child matches, fails, or needs
a fact. A needed fact stops the walk and names the gap. An unparsed
condition stops the walk for review. The path taken is the rationale.
"""
import json
import re
NODES = json.load(open("tree.json"))
BYID = {n["id"]: n for n in NODES}
ROOTS = [n for n in NODES if n["parent"] is None]
# ---------------------------------------------------------------------
# Fact schema. Every key the schedule's splits can turn on.
# ---------------------------------------------------------------------
FACT_KEYS = {
"sole_material": "outer sole constituent material, rubber_plastics, leather, composition_leather, or other",
"upper_material": "upper constituent material by greatest external surface area, rubber_plastics, leather, composition_leather, textile, or other",
"upper_textile_kind": "when the upper is textile, vegetable_fibers, wool_felt, or other_textile",
"waterproof_molded": "true when soles and uppers are rubber or plastics and the upper is neither fixed to the sole nor assembled by stitching, riveting, nailing, screwing, plugging or similar",
"protective": "true when the footwear protects against water, oil, grease, chemicals, cold or inclement weather",
"metal_toe_cap": "true when a protective metal toe cap is present",
"covers_ankle": "true when the footwear covers the ankle",
"covers_knee": "true when the footwear covers the knee",
"sports_spikes": "true when designed for a sport with spikes, sprigs, stops, clips, bars or provision for them, or ski, skating, snowboard, wrestling, boxing or cycling boots",
"ski_boot": "true for ski boots, cross country ski footwear and snowboard boots",
"athletic_like": "true for tennis shoes, basketball shoes, gym shoes, training shoes and the like",
"leather_esa_over_50":"true when over 50 percent of the upper external surface area is leather including accessories added back",
"value_per_pair": "customs value in US dollars per pair",
"gender_age": "men, women, youths_boys, misses, children, infants, or unisex",
"house_slipper": "true for house slippers",
"work_footwear": "true for work footwear",
"welt": "true for welt construction footwear",
"zori": "true for zoris, one piece molded rubber or plastic thong sandals",
"upper_esa_rubber_plastics_over_90": "true when over 90 percent of the upper external surface area including accessories is rubber or plastics",
"foxing_band": "true when the footwear has a foxing or foxing like band applied or molded at the sole and overlapping the upper",
"open_toe_or_heel": "true when the footwear has an open toe or open heel",
"slip_on": "true when the footwear is of the slip on type without laces, buckles or fasteners",
"sole_attach_stitch": "true when the sole is affixed to the upper mainly by stitching",
"vulcanized_construction": "true for footwear made by vulcanization or similar one piece processes",
"textile_sole_contact":"true when textile material has the greatest surface area in contact with the ground",
"leather_strap_instep_big_toe": "true when the upper consists of leather straps across the instep and around the big toe",
"wood_platform": "true when the footwear is made on a base or platform of wood",
"inner_sole": "true when the footwear has an inner sole",
"rp_weight_under_10": "true when the footwear is less than 10 percent by weight of rubber and plastics",
"turned_construction": "true for turn or turned footwear, sewn wrong side out to a leather sole then turned",
"golf_shoes": "true for golf shoes",
}
# ---------------------------------------------------------------------
# Condition matchers. Each returns True, False, or a needed fact key.
# UNPARSED marks text no rule recognizes.
# ---------------------------------------------------------------------
UNPARSED = "UNPARSED"
def need(facts, key):
return facts[key] if key in facts else key
COMPOUND_MARKERS = ("which consist", "straps", "provided", "except as", "in which")
def match_condition(desc, facts):
ov = facts.get("_overrides", {})
if desc in ov:
return bool(ov[desc])
d = desc.lower().rstrip(":").strip()
# residual buckets always match once earlier siblings failed
if d in ("other", "other footwear", "other:"):
return True
# leather strap sandal type of 6403.20
if "leather straps across the instep and around the big toe" in d:
t = need(facts, "leather_strap_instep_big_toe")
return t if t == "leather_strap_instep_big_toe" else bool(facts["leather_strap_instep_big_toe"])
# sole grouping rows under 6403 and 6404
if d.startswith("footwear with outer soles of rubber or plastics"):
s = need(facts, "sole_material")
return s if s == "sole_material" else facts["sole_material"] == "rubber_plastics"
if d.startswith("footwear with outer soles of leather or composition leather"):
s = need(facts, "sole_material")
return s if s == "sole_material" else facts["sole_material"] in ("leather","composition_leather")
# open toe or heel and slip on lines, honoring the except clauses
if d.startswith("footwear with open toes or open heels"):
if "foxing" in d:
f = need(facts, "foxing_band")
if f == "foxing_band": return f
if facts["foxing_band"]: return False
if "6404.19.20" in d:
p = need(facts, "protective")
if p == "protective": return p
if facts["protective"]: return False
o = need(facts, "open_toe_or_heel")
if o == "open_toe_or_heel": return o
if facts["open_toe_or_heel"]: return True
if "slip-on" in d or "slip on" in d:
sl = need(facts, "slip_on")
return sl if sl == "slip_on" else bool(facts["slip_on"])
return False
# weight of rubber or plastics split under 6404.19
if "less than 10 percent by weight of rubber or plastics" in d:
w = need(facts, "rp_weight_under_10")
return w if w == "rp_weight_under_10" else bool(facts["rp_weight_under_10"])
if "10 percent or more by weight of rubber or plastics" in d:
w = need(facts, "rp_weight_under_10")
return w if w == "rp_weight_under_10" else not facts["rp_weight_under_10"]
# turned construction and golf shoes
if d.startswith("turn or turned footwear"):
t = need(facts, "turned_construction")
return t if t == "turned_construction" else bool(facts["turned_construction"])
if d == "golf shoes":
g = need(facts, "golf_shoes")
return g if g == "golf_shoes" else bool(facts["golf_shoes"])
# compound conditions no simple rule should decide
if any(m in d for m in COMPOUND_MARKERS):
return UNPARSED
# value bands
m = re.search(r"valued not over \$?([\d.]+)", d)
if m:
v = need(facts, "value_per_pair")
if v == "value_per_pair": return v
return float(facts["value_per_pair"]) <= float(m.group(1))
m = re.search(r"valued over \$?([\d.]+)(?:/pair)? but not over \$?([\d.]+)", d)
if m:
v = need(facts, "value_per_pair")
if v == "value_per_pair": return v
return float(m.group(1)) < float(facts["value_per_pair"]) <= float(m.group(2))
m = re.search(r"valued over \$?([\d.]+)", d)
if m:
v = need(facts, "value_per_pair")
if v == "value_per_pair": return v
return float(facts["value_per_pair"]) > float(m.group(1))
# gender and age lines
g = need(facts, "gender_age")
gmap = {
"for men": "men", "men's": "men",
"for women": "women", "women's": "women",
"for youths and boys": "youths_boys",
"for misses": "misses", "for children": "children", "for infants": "infants",
"for men, youths and boys": ("men","youths_boys"),
"for other persons": None,
"for children and infants": ("children","infants"),
"for misses, children and infants": ("misses","children","infants"),
}
for text, val in gmap.items():
if d == text or d.startswith(text + " "):
if g == "gender_age": return g
if val is None:
return facts["gender_age"] not in ("men","youths_boys")
if isinstance(val, tuple):
return facts["gender_age"] in val
return facts["gender_age"] == val
# ankle and knee
if "covering the ankle but not covering the knee" in d:
a = need(facts, "covers_ankle")
if a == "covers_ankle": return a
if not facts["covers_ankle"]: return False
k = need(facts, "covers_knee")
return k if k == "covers_knee" else not facts["covers_knee"]
if "not covering the knee" not in d and "covering the knee" in d:
k = need(facts, "covers_knee")
return k if k == "covers_knee" else bool(facts["covers_knee"])
if "not covering the ankle" in d:
a = need(facts, "covers_ankle")
return a if a == "covers_ankle" else not facts["covers_ankle"]
if "covering the ankle" in d:
a = need(facts, "covers_ankle")
if a == "covers_ankle": return a
if not facts["covers_ankle"]: return False
if "but not covering the knee" in d:
k = need(facts, "covers_knee")
return k if k == "covers_knee" else not facts["covers_knee"]
return True
# sports and athletic
if d.startswith("sports footwear"):
s = need(facts, "sports_spikes")
if s == "sports_spikes": return s
if facts["sports_spikes"]: return True
if "tennis shoes, basketball shoes, gym shoes" in d:
a = need(facts, "athletic_like")
return a if a == "athletic_like" else bool(facts["athletic_like"])
return False
if "ski-boots" in d or "ski boots" in d or "snowboard" in d:
s = need(facts, "ski_boot")
return s if s == "ski_boot" else bool(facts["ski_boot"])
if "tennis shoes, basketball shoes, gym shoes" in d:
a = need(facts, "athletic_like")
return a if a == "athletic_like" else bool(facts["athletic_like"])
# wood platform line of 6403.59.10
if "base or platform of wood" in d:
w = need(facts, "wood_platform")
if w == "wood_platform": return w
if not facts["wood_platform"]: return False
t = need(facts, "metal_toe_cap")
if t == "metal_toe_cap": return t
if facts["metal_toe_cap"]: return False
i = need(facts, "inner_sole")
return i if i == "inner_sole" else not facts["inner_sole"]
# toe cap and protection, only when the line is about the toe cap itself
if ("protective metal toe-cap" in d or "protective metal toe cap" in d) and d.startswith(("incorporating", "other footwear, incorporating", "footwear incorporating", "not incorporating")):
t = need(facts, "metal_toe_cap")
if t == "metal_toe_cap": return t
if "not " in d.split("incorporating")[0]:
return not facts["metal_toe_cap"]
return bool(facts["metal_toe_cap"])
if "protection against water, oil, grease or chemicals or cold or inclement weather" in d:
p = need(facts, "protective")
if p == "protective": return p
if d.startswith("footwear designed to be worn over"):
return bool(facts["protective"])
return bool(facts["protective"])
if d.startswith("other footwear, not designed to be") or "not designed to be worn over" in d:
p = need(facts, "protective")
return p if p == "protective" else not facts["protective"]
# upper leather share
if "over 50 percent of the external surface area" in d and "leather" in d:
l = need(facts, "leather_esa_over_50")
return l if l == "leather_esa_over_50" else bool(facts["leather_esa_over_50"])
# rubber plastics share over 90
if "over 90 percent of the external surface area" in d:
r = need(facts, "upper_esa_rubber_plastics_over_90")
if r == "upper_esa_rubber_plastics_over_90": return r
val = bool(facts["upper_esa_rubber_plastics_over_90"])
if "foxing" in d:
f = need(facts, "foxing_band")
if f == "foxing_band": return f
return val and not facts["foxing_band"]
return val
# upper material lines
if "uppers of vegetable fibers" in d or "of vegetable fibers" in d:
u = need(facts, "upper_textile_kind")
return u if u == "upper_textile_kind" else facts["upper_textile_kind"] == "vegetable_fibers"
if "soles and uppers of wool felt" in d:
u = need(facts, "upper_textile_kind")
return u if u == "upper_textile_kind" else facts["upper_textile_kind"] == "wool_felt"
if "uppers of leather or composition leather" in d:
u = need(facts, "upper_material")
return u if u == "upper_material" else facts["upper_material"] in ("leather","composition_leather")
if "uppers of textile materials" in d or "uppers of textile material" in d:
u = need(facts, "upper_material")
return u if u == "upper_material" else facts["upper_material"] == "textile"
if d.startswith("of leather"):
u = need(facts, "upper_material")
return u if u == "upper_material" else facts["upper_material"] == "leather"
if d.startswith("of textile materials"):
u = need(facts, "upper_material")
return u if u == "upper_material" else facts["upper_material"] == "textile"
# sole lines
if "outer soles of leather" in d:
s = need(facts, "sole_material")
return s if s == "sole_material" else facts["sole_material"] == "leather"
if "outer soles of rubber, plastics, leather or composition leather" in d:
return True
if "outer soles and uppers of rubber or plastics" in d:
s = need(facts, "sole_material"); u = need(facts, "upper_material")
if s == "sole_material": return s
if u == "upper_material": return u
return facts["sole_material"] == "rubber_plastics" and facts["upper_material"] == "rubber_plastics"
# construction and type lines
if "welt footwear" in d:
w = need(facts, "welt")
return w if w == "welt" else bool(facts["welt"])
if "house slippers" in d:
h = need(facts, "house_slipper")
return h if h == "house_slipper" else bool(facts["house_slipper"])
if "work footwear" in d:
w = need(facts, "work_footwear")
return w if w == "work_footwear" else bool(facts["work_footwear"])
if "zoris" in d:
z = need(facts, "zori")
return z if z == "zori" else bool(facts["zori"])
return UNPARSED
# ---------------------------------------------------------------------
# The walk.
# ---------------------------------------------------------------------
def walk(facts, start=None):
"""Walk to a leaf. Returns a dict with status, code or gap, and the path."""
path = []
def effective_rate(node):
cur = node
while cur is not None:
if cur["general"].strip():
return cur["general"].strip()
cur = BYID[cur["parent"]] if cur["parent"] is not None else None
return ""
def descend(node):
if not node["children"]:
return {"status": "code", "code": node["htsno"], "general": effective_rate(node), "path": path}
kids = [BYID[c] for c in node["children"]]
for kid in kids:
r = match_condition(kid["desc"], facts)
if r is True:
path.append({"htsno": kid["htsno"], "desc": kid["desc"]})
return descend(kid)
if r is False:
continue
if r == UNPARSED:
return {"status": "review", "reason": "condition needs judgment",
"at": kid["desc"], "path": path}
return {"status": "need_fact", "fact": r, "question_about": FACT_KEYS[r],
"at": kid["desc"], "path": path}
return {"status": "review", "reason": "no child matched", "at": node["desc"], "path": path}
if start is None:
# heading selection from the top
for root in ROOTS:
r = heading_match(root, facts)
if r is True:
path.append({"htsno": root["htsno"], "desc": root["desc"]})
return descend(root)
if r is False:
continue
if isinstance(r, str):
return {"status": "need_fact", "fact": r, "question_about": FACT_KEYS[r],
"at": root["desc"], "path": path}
return {"status": "review", "reason": "no heading matched", "path": path}
return descend(start)
def heading_match(root, facts):
h = root["htsno"]
s = facts.get("sole_material"); u = facts.get("upper_material")
if h == "6401":
if s is not None and s != "rubber_plastics": return False
if u is not None and u != "rubber_plastics": return False
for k in ("sole_material","upper_material","waterproof_molded"):
if k not in facts: return k
return bool(facts["waterproof_molded"])
if h == "6402":
if s is not None and s != "rubber_plastics": return False
if u is not None and u != "rubber_plastics": return False
for k in ("sole_material","upper_material"):
if k not in facts: return k
if "waterproof_molded" not in facts: return "waterproof_molded"
return not facts["waterproof_molded"]
if h == "6403":
for k in ("sole_material","upper_material"):
if k not in facts: return k
return (s in ("rubber_plastics","leather","composition_leather")
and u in ("leather",))
if h == "6404":
for k in ("sole_material","upper_material"):
if k not in facts: return k
return (s in ("rubber_plastics","leather","composition_leather")
and u == "textile")
if h == "6405":
return True
return False
def rationale(result, facts):
lines = []
for i, step in enumerate(result.get("path", []), 1):
num = step["htsno"] or "grouping"
lines.append(f"{i}. {num} {step['desc']}")
return lines
if __name__ == "__main__":
print("engine loaded", len(NODES), "nodes")