use super::super::*;
use super::jwt_guard_taxonomy;
#[test]
fn checksum_substance_guard_is_default_on() {
assert!(!rhh::is_disabled("checksum_substance_guard"));
}
#[test]
fn isbn_checksum_distinguishes_genuine_from_lookalikes() {
use finetype_core::checksum::isbn;
for v in [
"0306406152",
"043942089X",
"9780306406157",
"978-3-16-148410-0",
] {
assert!(isbn(v), "should be valid ISBN: {v}");
}
for v in ["5150000128", "6965100000", "7586000000", "1041000000"] {
assert!(!isbn(v), "should NOT be valid ISBN: {v}");
}
assert!(!isbn("-1617000000"));
}
#[test]
fn v15_upc_maps_to_upc_not_ean() {
assert_eq!(header_hint("upc"), Some("identity.commerce.upc"));
assert_eq!(header_hint("ean"), Some("identity.commerce.ean"));
assert_eq!(header_hint("barcode"), Some("identity.commerce.ean"));
}
#[test]
fn test_hs_code_float_parseability() {
let codes = [
"6204.62.40", "8471.30.10",
"8471.30", "6204.62",
];
let per_value: Vec<[f32; FEATURE_DIM]> = codes.iter().map(|s| extract_features(s)).collect();
let cf = aggregate_features(&per_value);
assert!(
cf.mean[feature_idx::IS_FLOAT] < 1.0,
"HS codes with 3-segment entries should have is_float < 1.0, got {}",
cf.mean[feature_idx::IS_FLOAT]
);
assert!(
cf.mean[feature_idx::DIGIT_RATIO] > 0.7,
"HS codes should have high digit ratio, got {}",
cf.mean[feature_idx::DIGIT_RATIO]
);
}
#[test]
fn test_r20_hs_code_gate_demotes_plain_decimals() {
let values: Vec<String> = vec![
"3.14", "0.887", "-12.5", "100.0", "0.003", "45.67", "1.23", "99.9",
]
.into_iter()
.map(String::from)
.collect();
let result = value_sharpen(&values, "geography.transportation.hs_code", 0.95, None);
assert!(result.is_some(), "R20 should fire on plain decimals");
let (label, rule) = result.unwrap();
assert_eq!(label, "representation.numeric.decimal_number");
assert!(rule.starts_with("hs_code_validation_gate"));
}
#[test]
fn test_r20_hs_code_gate_keeps_real_hs_codes() {
let values: Vec<String> = vec![
"8471.30",
"8471.30.00",
"6204.62",
"8517.12",
"0901.21",
"2204.10",
]
.into_iter()
.map(String::from)
.collect();
let result = value_sharpen(&values, "geography.transportation.hs_code", 0.95, None);
assert!(result.is_none(), "R20 should NOT fire on real HS codes");
}
#[test]
fn test_is_hs_code_format() {
assert!(is_hs_code_format("8471.30"));
assert!(is_hs_code_format("8471.30.00"));
assert!(is_hs_code_format("0901.21.00.10"));
assert!(is_hs_code_format("847130")); assert!(is_hs_code_format("84713000"));
assert!(!is_hs_code_format("3.14"));
assert!(!is_hs_code_format("0.887"));
assert!(!is_hs_code_format("-12.5"));
assert!(!is_hs_code_format("100.0"));
assert!(!is_hs_code_format("45.67"));
assert!(!is_hs_code_format("123"));
assert!(!is_hs_code_format("12.34"));
assert!(!is_hs_code_format("-8471.30"));
}
#[test]
fn test_r22_upc_gate_corrects_to_ean() {
let values: Vec<String> = vec![
"1794213764625",
"4293423898067",
"6324920385397",
"3683935437077",
"5078019484874",
"8706648142321",
]
.into_iter()
.map(String::from)
.collect();
let result = value_sharpen(&values, "identity.commerce.upc", 0.999, None);
assert!(result.is_some(), "R22 should fire for 13-digit values");
let (label, rule) = result.unwrap();
assert_eq!(label, "identity.commerce.ean");
assert!(rule.contains("upc_digit_count_gate"));
}
#[test]
fn test_r22_upc_gate_demotes_wrong_length() {
let values: Vec<String> = vec![
"1966662179",
"6579926978",
"2527909147",
"9953906342",
"2157414996",
"6989529491",
]
.into_iter()
.map(String::from)
.collect();
let result = value_sharpen(&values, "identity.commerce.upc", 0.94, None);
assert!(result.is_some(), "R22 should fire for non-12-digit values");
let (label, rule) = result.unwrap();
assert_eq!(label, "representation.identifier.numeric_code");
assert!(rule.contains("upc_digit_count_gate"));
}
#[test]
fn test_r22_upc_gate_keeps_real_upc() {
let values: Vec<String> = vec![
"012345678905",
"036000291452",
"070330507227",
"042100005264",
"040000000068",
"041570056103",
]
.into_iter()
.map(String::from)
.collect();
let result = value_sharpen(&values, "identity.commerce.upc", 0.99, None);
assert!(
result.is_none() || !result.as_ref().unwrap().1.contains("upc_digit_count_gate"),
"R22 should not fire for valid 12-digit UPC"
);
}
#[test]
fn test_r23_isin_gate_corrects_isrc() {
let values: Vec<String> = vec![
"US0378331005",
"GB0002634946",
"DE0007164600",
"JP3435000009",
"FR0000120271",
"CA0585861085",
]
.into_iter()
.map(String::from)
.collect();
let result = value_sharpen(&values, "identity.commerce.isrc", 0.97, None);
assert!(result.is_some(), "R23 should fire for ISIN-format values");
let (label, rule) = result.unwrap();
assert_eq!(label, "finance.securities.isin");
assert!(rule.contains("isin_format_gate"));
}
#[test]
fn test_r24_issn_gate_corrects_ein() {
let values: Vec<String> = vec![
"1781-2253",
"8371-5342",
"6910-7471",
"2908-3721",
"8987-7548",
"4149-8688",
]
.into_iter()
.map(String::from)
.collect();
let result = value_sharpen(&values, "identity.government.ein", 0.91, None);
assert!(result.is_some(), "R24 should fire for ISSN-format values");
let (label, rule) = result.unwrap();
assert_eq!(label, "identity.commerce.issn");
assert!(rule.contains("issn_format_gate"));
}
#[test]
fn test_is_isin_format() {
assert!(is_isin_format("US0378331005"));
assert!(is_isin_format("GB0002634946"));
assert!(is_isin_format("AU000000BHP4"));
assert!(is_isin_format("NL0011540547"));
assert!(!is_isin_format("SE3YX3859059")); assert!(!is_isin_format("NLEK47515013")); assert!(!is_isin_format("CAHRM7311593")); assert!(!is_isin_format("US-Z03-98-12345")); assert!(!is_isin_format("1234567890AB")); assert!(!is_isin_format("USABC")); assert!(!is_isin_format("us0378331005")); }
#[test]
fn test_is_issn_format() {
assert!(is_issn_format("1781-2253"));
assert!(is_issn_format("0317-839X")); assert!(is_issn_format("0000-0000"));
assert!(!is_issn_format("12-3456789"));
assert!(!is_issn_format("1234-567"));
assert!(!is_issn_format("12345-6789"));
assert!(!is_issn_format("12345678"));
}
#[test]
fn ac07b_r20_still_validates_hs_codes() {
let values: Vec<String> = vec![
"8471.30",
"8471.30.00",
"6204.62",
"8517.12",
"0901.21",
"2204.10",
]
.into_iter()
.map(String::from)
.collect();
let result = value_sharpen(&values, "geography.transportation.hs_code", 0.95, None);
assert!(
result.is_none(),
"R20 should keep valid hs_code predictions after F3 removal"
);
}
#[test]
fn ac07b_r20_still_demotes_false_hs_codes() {
let values: Vec<String> = vec![
"3.14", "0.887", "-12.5", "100.0", "0.003", "45.67", "1.23", "99.9",
]
.into_iter()
.map(String::from)
.collect();
let result = value_sharpen(&values, "geography.transportation.hs_code", 0.95, None);
assert!(result.is_some(), "R20 should still demote false hs_code");
let (label, _) = result.unwrap();
assert_eq!(label, "representation.numeric.decimal_number");
}
#[test]
fn isbn_header_recovery_promotes_checked_isbn() {
let yaml = r#"
identity.commerce.isbn:
title: ISBN
designation: universal
tier: [VARCHAR, commerce]
release_priority: 3
samples: ["0306406152"]
"#;
let mut tax = Taxonomy::from_yaml(yaml).unwrap();
tax.compile_validators();
let mut cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
cc.set_taxonomy(tax);
let isbns: Vec<String> = vec!["0306406152", "0140449132", "043942089X", "0201633612"]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense(
"Primary ISBN10",
&isbns,
"representation.identifier.numeric_code",
1.0,
)
.unwrap();
assert_eq!(r.label, "identity.commerce.isbn", "isbn recovery must fire");
}
#[test]
fn isbn_header_recovery_declines_failed_checksum_and_no_header() {
let mut cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
cc.set_taxonomy({
let mut t = Taxonomy::from_yaml(
"identity.commerce.isbn:\n title: ISBN\n designation: universal\n tier: [VARCHAR, commerce]\n samples: [\"0306406152\"]\n",
)
.unwrap();
t.compile_validators();
t
});
let bad: Vec<String> = vec!["5150000128", "5150000129", "5150000130"]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense(
"Primary ISBN10",
&bad,
"representation.numeric.integer_number",
1.0,
)
.unwrap();
assert_ne!(
r.label, "identity.commerce.isbn",
"must decline failed checksum"
);
let isbns: Vec<String> = vec!["0306406152", "0140449132", "043942089X"]
.into_iter()
.map(String::from)
.collect();
let r2 = cc
.compose_from_sense(
"book_code",
&isbns,
"representation.identifier.numeric_code",
1.0,
)
.unwrap();
assert_ne!(
r2.label, "identity.commerce.isbn",
"must decline without header"
);
}
#[test]
fn ceded_leaf_recovery_reasserts_uuid_over_relocated_label() {
let yaml = r#"
representation.identifier.uuid:
title: UUID
designation: universal
tier: [VARCHAR, identifier]
validation:
type: string
pattern: "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
samples: ["550e8400-e29b-41d4-a716-446655440000"]
"#;
let mut tax = Taxonomy::from_yaml(yaml).unwrap();
tax.compile_validators();
let mut cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
cc.set_taxonomy(tax);
let uuids: Vec<String> = vec![
"550e8400-e29b-41d4-a716-446655440000",
"6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"6ba7b811-9dad-11d1-80b4-00c04fd430c8",
]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense(
"token",
&uuids,
"representation.identifier.alphanumeric_id",
1.0,
)
.unwrap();
assert_eq!(
r.label, "representation.identifier.uuid",
"ceded_leaf_recovery must re-assert uuid from values"
);
}
#[test]
fn ceded_leaf_recovery_declines_non_validating_values() {
let yaml = r#"
representation.identifier.uuid:
title: UUID
designation: universal
tier: [VARCHAR, identifier]
validation:
type: string
pattern: "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
samples: ["550e8400-e29b-41d4-a716-446655440000"]
"#;
let mut tax = Taxonomy::from_yaml(yaml).unwrap();
tax.compile_validators();
let mut cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
cc.set_taxonomy(tax);
let words: Vec<String> = vec!["apple", "banana", "cherry", "date"]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense("fruit", &words, "representation.text.word", 1.0)
.unwrap();
assert_ne!(
r.label, "representation.identifier.uuid",
"ceded_leaf_recovery must not fire on non-validating values"
);
}
const ISIN_ISRC_YAML: &str = r#"
finance.securities.isin:
title: ISIN
designation: universal
tier: [VARCHAR, payment]
checksum: isin
validation:
type: string
pattern: "^[A-Z]{2}[A-Z0-9]{9}[0-9]$"
samples: ["US0378331005"]
identity.commerce.isrc:
title: ISRC
designation: universal
tier: [VARCHAR, code]
validation:
type: string
pattern: "^[A-Z]{2}[A-Z0-9]{3}\\d{7}$"
samples: ["USRC17607839"]
"#;
#[test]
fn isin_checksum_recovery_reasserts_isin_over_isrc() {
let mut tax = Taxonomy::from_yaml(ISIN_ISRC_YAML).unwrap();
tax.compile_validators();
let mut cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
cc.set_taxonomy(tax);
let isins: Vec<String> = vec![
"US0378331005",
"GB0002634946",
"JP3633400001",
"DE0007164600",
]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense(
"token",
&isins,
"representation.identifier.alphanumeric_id",
1.0,
)
.unwrap();
assert_eq!(
r.label, "finance.securities.isin",
"isin_checksum_recovery must correct a valid-ISIN column off isrc"
);
}
#[test]
fn isin_checksum_recovery_declines_bad_checksum() {
let mut tax = Taxonomy::from_yaml(ISIN_ISRC_YAML).unwrap();
tax.compile_validators();
let mut cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
cc.set_taxonomy(tax);
let bad: Vec<String> = vec![
"US0378331000",
"GB0002634940",
"JP3633400000",
"DE0007164601",
]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense(
"token",
&bad,
"representation.identifier.alphanumeric_id",
1.0,
)
.unwrap();
assert_ne!(
r.label, "finance.securities.isin",
"isin_checksum_recovery must not promote checksum-invalid values"
);
}
const CERTAINTY_LEAVES_YAML: &str = r#"
finance.securities.cusip:
title: CUSIP
designation: universal
tier: [VARCHAR, payment]
checksum: cusip
validation:
type: string
pattern: "^[A-Z0-9]{8}[0-9]$"
samples: ["037833100"]
finance.securities.sedol:
title: SEDOL
designation: universal
tier: [VARCHAR, payment]
checksum: sedol
validation:
type: string
pattern: "^[B-DF-HJ-NP-TV-Z0-9]{6}[0-9]$"
samples: ["0263494"]
identity.medical.dea_number:
title: DEA
designation: universal
tier: [VARCHAR, medical]
checksum: dea
validation:
type: string
pattern: "^[ABFMPRabfmpr][A-Za-z]\\d{7}$"
samples: ["AB1234563"]
identity.medical.cpt:
title: CPT
designation: universal
tier: [VARCHAR, medical]
validation:
type: string
pattern: "^\\d{5}$|^\\d{4}[FTU]$"
samples: ["99213"]
technology.code.imei:
title: IMEI
designation: universal
tier: [VARCHAR, code]
checksum: luhn
validation:
type: string
pattern: "^[0-9]{15}$"
samples: ["490154203237518"]
geography.transportation.hs_code:
title: HS code
designation: universal
tier: [VARCHAR, transportation]
validation:
type: string
pattern: "^\\d{4}\\.?\\d{2}(\\.?\\d{2}){0,2}$"
samples: ["8471.30"]
geography.transportation.unlocode:
title: UN/LOCODE
designation: universal
tier: [VARCHAR, transportation]
membership: unlocode
validation:
type: string
pattern: "^[A-Z]{2}[A-Z2-9]{3}$"
samples: ["USLAX"]
representation.format.color_rgb:
title: Color (RGB)
designation: universal
tier: [VARCHAR, text]
validation:
type: string
pattern: "^(?:rgb)?\\(?([0-9]{1,3}),\\s*([0-9]{1,3}),\\s*([0-9]{1,3})\\)?$"
samples: ["rgb(255, 0, 0)"]
"#;
fn certainty_cc() -> ColumnClassifier {
let mut tax = Taxonomy::from_yaml(CERTAINTY_LEAVES_YAML).unwrap();
tax.compile_validators();
let mut cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
cc.set_taxonomy(tax);
cc
}
fn v(items: &[&str]) -> Vec<String> {
items.iter().map(|s| s.to_string()).collect()
}
fn recovered_label(header: &str, values: &[&str], sense: &str) -> String {
certainty_cc()
.compose_from_sense(header, &v(values), sense, 1.0)
.unwrap()
.label
}
#[test]
fn cusip_checksum_recovery_promotes_valid_cusips() {
let l = recovered_label(
"id",
&["037833100", "17275R102", "594918104"],
"representation.text.word",
);
assert_eq!(l, "finance.securities.cusip");
}
#[test]
fn cusip_checksum_recovery_declines_bad_checksum() {
let l = recovered_label(
"id",
&["037833101", "17275R103", "594918105"],
"representation.text.word",
);
assert_ne!(l, "finance.securities.cusip");
}
#[test]
fn cusip_checksum_recovery_declines_constant_column() {
let l = recovered_label(
"phkey",
&["484158167", "484158167", "484158167", "484158167"],
"datetime.epoch.unix_seconds",
);
assert_ne!(l, "finance.securities.cusip");
}
#[test]
fn sedol_checksum_recovery_promotes_valid_sedols() {
let l = recovered_label(
"code",
&["0263494", "B0WNLY7", "3134865"],
"representation.identifier.numeric_code",
);
assert_eq!(l, "finance.securities.sedol");
}
#[test]
fn sedol_checksum_recovery_declines_plain_numeric_codes() {
let l = recovered_label(
"code",
&["1234567", "7654321", "1112223"],
"representation.identifier.numeric_code",
);
assert_ne!(l, "finance.securities.sedol");
}
#[test]
fn dea_checksum_recovery_promotes_valid_dea_numbers() {
let l = recovered_label(
"id",
&["AB1234563", "BS4567890", "FH1357905"],
"representation.identifier.alphanumeric_id",
);
assert_eq!(l, "identity.medical.dea_number");
}
#[test]
fn dea_checksum_recovery_declines_bad_checksum() {
let l = recovered_label(
"id",
&["AB1234564", "BS4567891", "FH1357906"],
"representation.identifier.alphanumeric_id",
);
assert_ne!(l, "identity.medical.dea_number");
}
#[test]
fn imei_checksum_recovery_promotes_with_header() {
let l = recovered_label(
"imei",
&["490154203237518", "352043068649148", "011245002151205"],
"representation.numeric.integer_number",
);
assert_eq!(l, "technology.code.imei");
}
#[test]
fn imei_checksum_recovery_requires_header() {
let l = recovered_label(
"device_serial",
&["490154203237518", "352043068649148", "011245002151205"],
"representation.numeric.integer_number",
);
assert_ne!(l, "technology.code.imei");
}
#[test]
fn imei_checksum_recovery_declines_amex_card_column() {
let l = recovered_label(
"card_number",
&["378282246310005", "371449635398431", "378734493671000"],
"representation.numeric.integer_number",
);
assert_ne!(l, "technology.code.imei");
}
#[test]
fn cpt_procedure_recovery_promotes_with_header() {
let l = recovered_label(
"cpt",
&["99213", "29580", "2029F", "0307T", "99214"],
"representation.text.word",
);
assert_eq!(l, "identity.medical.cpt");
}
#[test]
fn cpt_procedure_recovery_declines_generic_code_header() {
let l = recovered_label(
"code",
&["99213", "10001", "94103", "60601", "30301"],
"representation.identifier.numeric_code",
);
assert_ne!(l, "identity.medical.cpt");
}
#[test]
fn hs_code_header_recovery_promotes_with_header() {
let l = recovered_label(
"hs_code",
&[
"8471.30",
"6110.20.20",
"0901.11.00.10",
"8517.12",
"3004.90.92",
],
"representation.text.word",
);
assert_eq!(l, "geography.transportation.hs_code");
}
#[test]
fn hs_code_header_recovery_declines_year_column() {
let l = recovered_label(
"hs",
&["2019", "2020", "2021", "2022", "2023"],
"representation.numeric.integer_number",
);
assert_ne!(l, "geography.transportation.hs_code");
}
#[test]
fn unlocode_membership_recovery_promotes_members() {
let l = recovered_label(
"port",
&["USLAX", "GBLON", "DEHAM", "SGSIN", "NLRTM"],
"representation.text.word",
);
assert_eq!(l, "geography.transportation.unlocode");
}
#[test]
fn unlocode_membership_recovery_declines_non_members() {
let l = recovered_label(
"code",
&["ZZZZZ", "QQQQQ", "XKXKX", "VWVWV", "JKJKJ"],
"representation.text.word",
);
assert_ne!(l, "geography.transportation.unlocode");
}
#[test]
fn unlocode_membership_recovery_declines_constant_column() {
let l = recovered_label(
"symbol",
&["FRMUF", "FRMUF", "FRMUF", "FRMUF"],
"representation.text.entity_name",
);
assert_ne!(l, "geography.transportation.unlocode");
}
#[test]
fn ticker_membership_recovery_promotes_symbols() {
let l = recovered_label(
"ticker",
&["AAPL", "MSFT", "NVDA", "TSLA", "AMZN"],
"geography.location.state_code",
);
assert_eq!(l, "finance.securities.ticker");
}
#[test]
fn ticker_membership_recovery_requires_ticker_header() {
let l = recovered_label(
"state",
&["AAPL", "MSFT", "NVDA", "TSLA", "AMZN"],
"geography.location.state_code",
);
assert_ne!(l, "finance.securities.ticker");
}
#[test]
fn ticker_membership_recovery_declines_non_members() {
let l = recovered_label(
"ticker",
&["ZZZZZ", "QQQQXY", "NOTATCKR", "WResReW", "FooBarBz"],
"representation.text.word",
);
assert_ne!(l, "finance.securities.ticker");
}
#[test]
fn ticker_membership_recovery_declines_constant_column() {
let l = recovered_label(
"symbol",
&["AAPL", "AAPL", "AAPL", "AAPL"],
"representation.text.word",
);
assert_ne!(l, "finance.securities.ticker");
}
#[test]
fn org_name_geography_demotion_demotes_org_column() {
let l = recovered_label(
"name",
&[
"ICON STOCKBROKERS LIMITED",
"NIGERIAN BREWERIES PLC",
"Oakmark International Fund",
"Hutchin Hill Capital, LP",
"Vanguard Fiduciary Trust Company",
],
"geography.location.region",
);
assert_eq!(l, "representation.text.entity_name");
}
#[test]
fn org_name_geography_demotion_keeps_place_names() {
let l = recovered_label(
"region",
&[
"California",
"Texas",
"Florida",
"Illinois",
"Ohio",
"Virginia",
],
"geography.location.region",
);
assert_eq!(l, "geography.location.region");
}
#[test]
fn org_name_geography_demotion_keeps_bare_geo_codes() {
let state = recovered_label(
"state",
&["AB", "AB", "NV", "NV", "AB", "NV"],
"geography.location.state_code",
);
assert!(
state.starts_with("geography."),
"bare state codes must stay geographic, got {state}"
);
let country = recovered_label(
"country_code",
&["SE", "SE", "AG", "SE", "AG", "SE"],
"geography.location.country_code",
);
assert!(
country.starts_with("geography."),
"bare country codes must stay geographic, got {country}"
);
}
#[test]
fn org_name_geography_demotion_keeps_address_columns() {
for base in [
"geography.address.full_address",
"geography.address.street_name",
] {
let l = recovered_label(
"address1",
&[
"6143 - 4th Street SE",
"1331 Macleod Trail SE",
"Royal Trust Tower Suite 4500",
"725 11th Avenue Boulevard SE",
],
base,
);
assert!(
l.starts_with("geography.address."),
"address column carrying directional/building tokens must NOT be demoted (base {base}, got {l})"
);
}
}
#[test]
fn region_nonmembership_veto_demotes_catalog_codes() {
let l = recovered_label(
"net",
&["us", "ci", "nn", "hv", "uu", "uw", "ak", "tx"],
"geography.location.region",
);
assert_eq!(
l, "representation.text.word",
"seismic net codes must not be region"
);
}
#[test]
fn region_nonmembership_veto_keeps_cities_and_composites() {
for (hdr, vals) in [
(
"addrcity",
&["Austin", "Georgetown", "Dallas", "Houston"][..],
),
(
"placeLocation",
&[
"Myrtle Beach, South Carolina",
"Boston, Massachusetts",
"Reno, Nevada",
][..],
),
(
"location",
&[
"Linn County (Iowa)",
"Cedar Falls (Iowa)",
"Scott County (Iowa)",
][..],
),
] {
let l = recovered_label(hdr, vals, "geography.location.region");
assert!(
l.starts_with("geography."),
"real place column ({hdr}) must stay geographic, got {l}"
);
}
}
#[test]
fn region_nonmembership_veto_keeps_bare_state_codes() {
let l = recovered_label(
"geoState",
&["CA", "NV", "CA", "TX"],
"geography.location.region",
);
assert!(
l.starts_with("geography."),
"a state-code column must stay geographic, got {l}"
);
}
#[test]
fn region_nonmembership_veto_demotes_enum_words() {
for (hdr, vals) in [
("category", &["GENERAL", "FUND", "GENERAL", "BRANCH"][..]),
(
"checkouttype",
&["Horizon", "OverDrive", "Freegal", "Hoopla"][..],
),
] {
let l = recovered_label(hdr, vals, "geography.location.region");
assert_eq!(
l, "representation.text.word",
"{hdr} enum must not be region"
);
}
}
#[test]
fn region_nonmembership_veto_keeps_real_region_names() {
let l = recovered_label(
"area",
&[
"California",
"Texas",
"Florida",
"Ontario",
"Bavaria",
"Scotland",
],
"geography.location.region",
);
assert_eq!(
l, "geography.location.region",
"real region names must stay region"
);
}
#[test]
fn region_nonmembership_veto_keeps_iso_region_codes() {
let l = recovered_label(
"code",
&["US-TX", "US-CA", "CA-ON", "BR-SP", "US-FL", "US-TX"],
"geography.location.region",
);
assert!(
l.starts_with("geography."),
"ISO-3166-2 region codes must stay geographic, got {l}"
);
}
#[test]
fn region_nonmembership_veto_respects_region_header() {
let l = recovered_label(
"province",
&["Zzland", "Qqvia", "Xxmark", "Yytania"],
"geography.location.region",
);
assert_eq!(
l, "geography.location.region",
"a strong region header must veto the veto"
);
}
#[test]
fn tld_geography_recovery_promotes_tlds() {
let l = recovered_label(
"TLD",
&["com", "org", "net", "edu", "gov", "uk", "io"],
"geography.location.continent",
);
assert_eq!(l, "technology.internet.top_level_domain");
}
#[test]
fn tld_geography_recovery_requires_tld_header() {
let l = recovered_label(
"country",
&["uk", "de", "fr", "jp", "cn", "it"],
"geography.location.continent",
);
assert_ne!(l, "technology.internet.top_level_domain");
}
#[test]
fn color_rgb_recovery_promotes_anchored_rgb() {
let l = recovered_label(
"colour",
&[
"rgb(255, 0, 0)",
"rgb(0, 255, 0)",
"rgba(0, 0, 255, 0.5)",
"rgb(128, 128, 128)",
],
"representation.text.word",
);
assert_eq!(l, "representation.format.color_rgb");
}
#[test]
fn color_rgb_recovery_declines_bare_triples() {
let l = recovered_label(
"colour",
&["255, 0, 0", "0, 255, 0", "128, 128, 128", "12, 45, 90"],
"representation.text.word",
);
assert_ne!(l, "representation.format.color_rgb");
}
#[test]
fn unlocode_format_veto_demotes_contradicting_values() {
let yaml = r#"
geography.transportation.unlocode:
title: UN/LOCODE
designation: universal
tier: [VARCHAR, transportation]
samples: ["USNYC"]
validation:
type: string
pattern: '^[A-Z]{2}[A-Z2-9]{3}$'
"#;
let mut tax = Taxonomy::from_yaml(yaml).unwrap();
tax.compile_validators();
let mut cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
cc.set_taxonomy(tax);
let postcodes: Vec<String> = vec!["CM13 3GF", "SW1A 1AA", "EC1A 1BB"]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense("loc", &postcodes, "geography.transportation.unlocode", 0.97)
.unwrap();
assert_ne!(
r.label, "geography.transportation.unlocode",
"contradicting values must demote the unlocode overcall"
);
}
#[test]
fn unlocode_format_veto_keeps_valid_unlocodes() {
let yaml = r#"
geography.transportation.unlocode:
title: UN/LOCODE
designation: universal
tier: [VARCHAR, transportation]
samples: ["USNYC"]
validation:
type: string
pattern: '^[A-Z]{2}[A-Z2-9]{3}$'
"#;
let mut tax = Taxonomy::from_yaml(yaml).unwrap();
tax.compile_validators();
let mut cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
cc.set_taxonomy(tax);
let codes: Vec<String> = vec!["USNYC", "DEHAM", "NLRTM", "GBLON"]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense("loc", &codes, "geography.transportation.unlocode", 0.97)
.unwrap();
assert_eq!(r.label, "geography.transportation.unlocode");
}
#[test]
fn membership_substance_guard_is_default_on() {
assert!(!rhh::is_disabled("membership_substance_guard"));
}
#[test]
fn membership_guard_demotes_tickers_off_icao() {
let yaml = r#"
geography.transportation.icao_code:
title: ICAO Airport Code
designation: universal
tier: [VARCHAR, transportation]
samples: ["KJFK"]
validation:
type: string
pattern: '^[A-Z]{4}$'
membership: icao_airports
"#;
let mut tax = Taxonomy::from_yaml(yaml).unwrap();
tax.compile_validators();
let mut cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
cc.set_taxonomy(tax);
let tickers: Vec<String> = vec![
"AAPL", "MSFT", "TSLA", "NVDA", "AMZN", "META", "NFLX", "ORCL", "ADBE", "INTC",
]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense(
"ident",
&tickers,
"geography.transportation.icao_code",
0.93,
)
.unwrap();
assert_ne!(
r.label, "geography.transportation.icao_code",
"non-member tickers must demote the icao overcall"
);
assert_eq!(
r.disambiguation_rule.as_deref(),
Some("membership_substance_guard:geography.transportation.icao_code")
);
}
#[test]
fn jwt_substance_guard_is_default_on() {
assert!(!rhh::is_disabled("jwt_substance_guard"));
}
#[test]
fn jwt_guard_demotes_nonjwt_dotted_strings() {
let mut cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
cc.set_taxonomy(jwt_guard_taxonomy());
let vals: Vec<String> = vec![
"tok_aaaa1.pay_bbbb2.sig_cccc3",
"tok_dddd4.pay_eeee5.sig_ffff6",
"tok_gggg7.pay_hhhh8.sig_iiii9",
"tok_jjjj0.pay_kkkk1.sig_llll2",
"tok_mmmm3.pay_nnnn4.sig_oooo5",
]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense("token", &vals, "technology.cryptographic.jwt", 0.9)
.unwrap();
assert_ne!(
r.label, "technology.cryptographic.jwt",
"non-JWT dotted strings must demote off jwt"
);
assert_eq!(
r.disambiguation_rule.as_deref(),
Some("jwt_substance_guard")
);
}
#[test]
fn jwt_guard_keeps_real_tokens() {
let mut cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
cc.set_taxonomy(jwt_guard_taxonomy());
let vals: Vec<String> = vec![
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoLmV4YW1wbGUuY29tIn0.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk",
"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIyIn0.aaaa",
"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIzIn0.bbbb",
]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense("token", &vals, "technology.cryptographic.jwt", 0.9)
.unwrap();
assert_eq!(
r.label, "technology.cryptographic.jwt",
"genuine JWTs must be kept"
);
}
#[test]
fn membership_guard_keeps_real_airport_codes() {
let yaml = r#"
geography.transportation.icao_code:
title: ICAO Airport Code
designation: universal
tier: [VARCHAR, transportation]
samples: ["KJFK"]
validation:
type: string
pattern: '^[A-Z]{4}$'
membership: icao_airports
"#;
let mut tax = Taxonomy::from_yaml(yaml).unwrap();
tax.compile_validators();
let mut cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
cc.set_taxonomy(tax);
let codes: Vec<String> = vec!["KJFK", "KLAX", "LFPG", "EGLL", "RJTT", "YSSY"]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense(
"airport",
&codes,
"geography.transportation.icao_code",
0.93,
)
.unwrap();
assert_eq!(r.label, "geography.transportation.icao_code");
}
#[test]
fn membership_guard_demotes_tickers_off_unlocode() {
let yaml = r#"
geography.transportation.unlocode:
title: UN/LOCODE
designation: universal
tier: [VARCHAR, transportation]
samples: ["USLAX"]
validation:
type: string
pattern: '^[A-Z]{2}[A-Z2-9]{3}$'
membership: unlocode
"#;
let mut tax = Taxonomy::from_yaml(yaml).unwrap();
tax.compile_validators();
let mut cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
cc.set_taxonomy(tax);
let tickers: Vec<String> = vec![
"GOOGL", "BRKAX", "AMZNX", "ZVZZT", "VTSAX", "FXAIX", "SWPPX", "VFIAX", "VBIAX", "QQQQY",
]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense(
"ticker",
&tickers,
"geography.transportation.unlocode",
0.90,
)
.unwrap();
assert_ne!(
r.label, "geography.transportation.unlocode",
"non-member tickers must demote the unlocode overcall"
);
assert_eq!(
r.disambiguation_rule.as_deref(),
Some("membership_substance_guard:geography.transportation.unlocode")
);
}
#[test]
fn membership_guard_keeps_real_unlocodes() {
let yaml = r#"
geography.transportation.unlocode:
title: UN/LOCODE
designation: universal
tier: [VARCHAR, transportation]
samples: ["USLAX"]
validation:
type: string
pattern: '^[A-Z]{2}[A-Z2-9]{3}$'
membership: unlocode
"#;
let mut tax = Taxonomy::from_yaml(yaml).unwrap();
tax.compile_validators();
let mut cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
cc.set_taxonomy(tax);
let codes: Vec<String> = vec!["USLAX", "GBLON", "DEHAM", "SGSIN", "NLRTM", "USNYC"]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense("port", &codes, "geography.transportation.unlocode", 0.93)
.unwrap();
assert_eq!(r.label, "geography.transportation.unlocode");
}
#[test]
fn membership_guard_demotes_nonmember_codes_off_iata() {
let yaml = r#"
geography.transportation.iata_code:
title: IATA Airport Code
designation: universal
tier: [VARCHAR, transportation]
samples: ["JFK"]
validation:
type: string
pattern: '^[A-Z]{3}$'
membership: iata_airports
"#;
let mut tax = Taxonomy::from_yaml(yaml).unwrap();
tax.compile_validators();
let mut cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
cc.set_taxonomy(tax);
let codes: Vec<String> = vec![
"USD", "EUR", "NZD", "INR", "RUB", "NKE", "PFE", "CVX", "XOM",
]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense("code", &codes, "geography.transportation.iata_code", 0.9)
.unwrap();
assert_ne!(
r.label, "geography.transportation.iata_code",
"non-member codes must demote the iata overcall"
);
}
#[test]
fn entity_prose_override_demotes_prose_to_plain_text() {
let values: Vec<String> = vec![
"Type 2 diabetes mellitus without complications",
"Provides consulting and advisory services to businesses",
"Chronic obstructive pulmonary disease unspecified",
"Offers cloud software for enterprise resource planning",
"Alcohol dependence uncomplicated with related disorders",
]
.into_iter()
.map(String::from)
.collect();
let result = value_sharpen(&values, "representation.text.entity_name", 0.93, None);
let (label, rule) = result.expect("prose should demote off entity_name");
assert_eq!(label, "representation.text.plain_text");
assert!(rule.starts_with("entity_prose_override:"));
}
#[test]
fn entity_prose_override_keeps_org_names_with_connectors() {
let values: Vec<String> = vec![
"Bank of America Corporation",
"McKinsey & Company",
"Fidelity Advisor Leveraged Company Stock Fund",
"University of California Press",
"Museum of Modern Art",
"Procter & Gamble Co",
]
.into_iter()
.map(String::from)
.collect();
let result = value_sharpen(&values, "representation.text.entity_name", 0.93, None);
assert!(
result.is_none(),
"org names with lowercase connectors must not demote off entity_name"
);
}
#[test]
fn entity_prose_override_keeps_species_binomials() {
let values: Vec<String> = vec![
"Homo sapiens",
"Mus musculus",
"Rattus norvegicus",
"Danio rerio",
]
.into_iter()
.map(String::from)
.collect();
let result = value_sharpen(&values, "representation.text.entity_name", 0.93, None);
assert!(result.is_none(), "species binomials must stay entity_name");
}
#[test]
fn numeric_code_recovery_restores_naics_and_cik() {
let yaml = r#"
representation.identifier.numeric_code:
title: "Numeric Code"
validation:
type: string
pattern: '^[0-9]+$'
tier: [VARCHAR, identifier]
release_priority: 4
samples: ["00120"]
"#;
let mut tax = Taxonomy::from_yaml(yaml).unwrap();
tax.compile_validators();
let mut cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
cc.set_taxonomy(tax);
let ciks: Vec<String> = vec![
"320193", "1652044", "789019", "1018724", "1318605", "320193", "789019", "1067983",
"1652044", "1318605", "320193", "104169",
]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense("cik", &ciks, "representation.numeric.integer_number", 0.8)
.unwrap();
assert_eq!(
r.label, "representation.identifier.numeric_code",
"rule was {:?}",
r.disambiguation_rule
);
assert!(r
.disambiguation_rule
.as_deref()
.unwrap_or("")
.starts_with("numeric_code_header_recovery:"));
}
#[test]
fn numeric_code_recovery_leaves_quantities_and_postal_alone() {
let cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
let counts: Vec<String> = vec!["1200", "845", "23000", "410"]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense(
"employees",
&counts,
"representation.numeric.integer_number",
0.8,
)
.unwrap();
assert_eq!(r.label, "representation.numeric.integer_number");
let zips: Vec<String> = vec!["90210", "10001", "60601", "94102"]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense(
"zip_code",
&zips,
"representation.numeric.integer_number",
0.8,
)
.unwrap();
assert_ne!(r.label, "representation.identifier.numeric_code");
assert!(!r
.disambiguation_rule
.as_deref()
.unwrap_or("")
.starts_with("numeric_code_header_recovery:"));
}
#[test]
fn test_schema_fail_demotion_names_off_swift_bic() {
let values: Vec<String> = (0..30)
.map(|i| format!("ACME HOLDINGS INTERNATIONAL {}", i))
.collect();
let yaml = r#"
finance.banking.swift_bic:
title: "SWIFT/BIC"
validation:
type: string
pattern: "^[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}([A-Z0-9]{3})?$"
tier: [VARCHAR, banking]
release_priority: 3
samples: ["DEUTDEFF"]
"#;
let taxonomy = Taxonomy::from_yaml(yaml).unwrap();
let result = value_sharpen(&values, "finance.banking.swift_bic", 0.9, Some(&taxonomy));
let (label, rule) = result.expect("name strings should demote off swift_bic");
assert_eq!(label, "representation.identifier.alphanumeric_id");
assert!(rule.starts_with("schema_fail_demotion:"));
}
#[test]
fn test_schema_fail_demotion_keeps_real_swift_bic() {
let values: Vec<String> = vec![
"DEUTDEFF",
"CHASUS33",
"BARCGB22",
"BNPAFRPP",
"CITIUS33XXX",
"HSBCHKHH",
]
.into_iter()
.map(String::from)
.collect();
let yaml = r#"
finance.banking.swift_bic:
title: "SWIFT/BIC"
validation:
type: string
pattern: "^[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}([A-Z0-9]{3})?$"
tier: [VARCHAR, banking]
release_priority: 3
samples: ["DEUTDEFF"]
"#;
let taxonomy = Taxonomy::from_yaml(yaml).unwrap();
let result = value_sharpen(&values, "finance.banking.swift_bic", 0.9, Some(&taxonomy));
assert!(
result.is_none(),
"real BIC values must not be demoted off swift_bic"
);
}
#[test]
fn naics_recovery_is_default_on() {
assert!(!rhh::is_disabled("naics_industry_recovery"));
}
#[test]
fn naics_recovery_promotes_naics_headed_member_columns() {
let cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
let naics: Vec<String> = vec![
"541511", "236220", "722511", "621111", "445110", "541511", "722511", "236220", "541512",
"928120",
]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense(
"NAICS Code",
&naics,
"representation.numeric.integer_number",
0.7,
)
.unwrap();
assert_eq!(
r.label, "identity.industry.naics",
"rule was {:?}",
r.disambiguation_rule
);
}
#[test]
fn naics_recovery_requires_the_header_gate() {
let cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
let vals: Vec<String> = vec!["11", "21", "23", "31", "42", "44", "11", "21"]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense(
"team_size",
&vals,
"representation.numeric.integer_number",
0.7,
)
.unwrap();
assert_ne!(r.label, "identity.industry.naics");
}
#[test]
fn naics_recovery_requires_membership() {
let cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
let vals: Vec<String> = vec!["100000", "999999", "050000", "130000", "990000"]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense(
"naics_code",
&vals,
"representation.numeric.integer_number",
0.7,
)
.unwrap();
assert_ne!(r.label, "identity.industry.naics");
}
#[test]
fn s_expression_recovery_is_default_on() {
assert!(!rhh::is_disabled("s_expression_recovery"));
}
#[test]
fn s_expression_recovery_promotes_parse_trees() {
let cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
let trees: Vec<String> = vec![
"(ROOT (S (NP (NN dog)) (VP (VBZ runs))))",
"(ROOT (FRAG (INTJ (UH uh)) (, ,) (NP (NN yeah))))",
"(S (NP (PRP I)) (VP (VBP think) (SBAR (S (NP (PRP it))))))",
"(ROOT (SINV (ADVP (RB so)) (, ,) (SBARQ (WHNP (WP what)))))",
"(program (call (id print) (string hi)))",
]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense("parse_tree", &trees, "container.array.comma_separated", 0.8)
.unwrap();
assert_eq!(
r.label, "container.object.s_expression",
"rule was {:?}",
r.disambiguation_rule
);
}
#[test]
fn s_expression_recovery_declines_genuine_comma_lists() {
let cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
let lists: Vec<String> = vec!["apple,banana,cherry", "red,green,blue", "1,2,3,4"]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense("tags", &lists, "container.array.comma_separated", 0.8)
.unwrap();
assert_ne!(r.label, "container.object.s_expression");
}
#[test]
fn s_expression_recovery_tolerates_truncated_trees() {
let cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
let trees: Vec<String> = vec![
"(ROOT (SINV (ADVP (RB so)) (, ,) (SBARQ (INTJ (UH uh",
"(ROOT (S (NP (NP (DT the) (NN cat)) (PP (IN on) (NP (DT the",
"(S (INTJ (UH Uh)) (, ,) (NP-SBJ (PRP I)) (VP (VBP think) (SBAR",
]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense("trees", &trees, "container.array.comma_separated", 0.8)
.unwrap();
assert_eq!(
r.label, "container.object.s_expression",
"rule was {:?}",
r.disambiguation_rule
);
}
#[test]
fn naics_recovery_admits_bare_code_header_for_long_codes() {
let cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
let vals: Vec<String> = vec![
"541511", "236220", "722511", "621111", "445110", "541512", "722511", "236220",
]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense("code", &vals, "representation.numeric.integer_number", 0.7)
.unwrap();
assert_eq!(
r.label, "identity.industry.naics",
"rule was {:?}",
r.disambiguation_rule
);
}
#[test]
fn naics_recovery_rejects_bare_code_header_for_sector_length_values() {
let cc =
ColumnClassifier::with_defaults(Box::new(crate::inference::MockClassifier::new("unknown")));
let vals: Vec<String> = vec!["11", "22", "31", "44", "55", "62", "72", "81", "11", "44"]
.into_iter()
.map(String::from)
.collect();
let r = cc
.compose_from_sense("code", &vals, "representation.numeric.integer_number", 0.7)
.unwrap();
assert_ne!(r.label, "identity.industry.naics");
}