all:
  children:
    zuul_unreachable:
      hosts: {}
  hosts:
    debian-bookworm:
      ansible_connection: ssh
      ansible_host: 2a13:1a81:8000:3124:f816:3eff:fe53:8cd3
      ansible_port: 22
      ansible_python_interpreter: auto
      ansible_user: zuul
      nodepool:
        az: nova
        cloud: regiocloud-a-ci
        external_id: e9a69c55-c68d-4b3f-bc0e-44098f06370f
        host_id: 7f2607eceb24f4583c6f9496c53c64b51afe50de5eacda4379b21c42
        interface_ip: 2a13:1a81:8000:3124:f816:3eff:fe53:8cd3
        label: debian-bookworm
        node_properties: {}
        private_ipv4: 10.128.7.54
        private_ipv6: null
        provider: regiocloud-a
        public_ipv4: 81.163.192.228
        public_ipv6: 2a13:1a81:8000:3124:f816:3eff:fe53:8cd3
        region: null
        slot: null
  vars:
    zuul:
      _inheritance_path:
      - '<Job base explicit: None implied: {MatchAny:{ImpliedBranchMatcher:main}}
        source: osism/zuul-config/zuul.d/jobs.yaml@main#2>'
      - '<Job python-black explicit: None implied: {MatchAny:{ImpliedBranchMatcher:main}}
        source: osism/zuul-jobs/.zuul.yaml@main#54>'
      - '<Job python-black explicit: None implied: None source: osism/python-osism/.zuul.yaml@main#143>'
      ansible_version: '9'
      attempts: 1
      branch: main
      build: 58588718dbc945e8aa62d8ce750778ab
      build_refs:
      - branch: main
        change: '2557'
        change_message: "Build the SNMP vault only when secrets exist\n\n`_add_snmp_configuration`
          built a `VaultLib` for **every** device before it\nlooked at whether that
          device had anything encrypted to decrypt.\n\n`get_vault()` needs two things
          that only exist inside a worker container: the\nkey file `/share/ansible_vault_password.key`,
          and the encrypted vault password\nstored in Redis. Where either is missing,
          the failure is logged rather than\nraised, three times per synced device:\n\n1.
          `get_ansible_vault_password()` fails to open the key file and logs\n   `Unable
          to get ansible vault password` before re-raising.\n2. The `FileNotFoundError`
          is not a `ValueError`, so it lands in `get_vault()`'s\n   generic handler,
          which logs `Unable to get vault secret: ...`\n3. ...and then `Dropping encrypted
          entries`.\n\nSo a SONiC sync outside a worker \u2014 local development,
          or any run against a\nNetBox with no vault configured \u2014 produces three
          ERROR-level records per\ndevice, for devices that carry no secrets at all.\n\n##
          The change\n\nVault construction is deferred until the device actually carries
          a non-empty\n`secrets` custom field:\n\n```python\nnode_secrets = device.custom_fields.get(\"secrets\",
          {})\nif node_secrets is None:\n    node_secrets = {}\nif node_secrets:\n
          \   deep_decrypt(node_secrets, get_vault())\n```\n\nDevices **with** encrypted
          secrets are decrypted exactly as before. Devices\nwithout them no longer
          touch the key file or Redis. Note that `deep_decrypt` on\nan empty dict
          was already a no-op, so nothing is lost by skipping it \u2014 the only\nbehavioural
          change is that the vault is not built.\n\n## Tests\n\nTwo cases added to
          the existing `test_config_generator_snmp.py`, pinning both\ndirections:\n\n-
          `test_add_snmp_configuration_no_secrets_skips_vault` \u2014 neither `get_vault`
          nor\n  `deep_decrypt` is called, for both a missing and an explicitly `None`
          custom\n  field. This fails without the fix.\n- `test_add_snmp_configuration_with_secrets_uses_vault`
          \u2014 both are still called\n  when secrets are present, so the preserved
          path is guarded too.\n\n## Provenance\n\nThis fell out of ongoing work on
          an end-to-end golden test for SONiC config\ngeneration, which generates
          config against a plain NetBox with no vault\nconfigured and treats any ERROR-level
          log record as a failure. The bug it\nsurfaced is independent of that work,
          so it is split out here on its own \u2014 the\nnoise it removes affects
          any non-worker environment, and the fix touches only\n`config_generator.py`.\n"
        change_url: https://github.com/osism/python-osism/pull/2557
        commit_id: a5009fe478ddd8f1f8f90db1fa647d7935416db1
        patchset: a5009fe478ddd8f1f8f90db1fa647d7935416db1
        project:
          canonical_hostname: github.com
          canonical_name: github.com/osism/python-osism
          name: osism/python-osism
          short_name: python-osism
        src_dir: src/github.com/osism/python-osism
        topic: null
      buildset: 499dc728b2cd4abc8bc8653eefb366c4
      buildset_refs:
      - branch: main
        change: '2557'
        change_message: "Build the SNMP vault only when secrets exist\n\n`_add_snmp_configuration`
          built a `VaultLib` for **every** device before it\nlooked at whether that
          device had anything encrypted to decrypt.\n\n`get_vault()` needs two things
          that only exist inside a worker container: the\nkey file `/share/ansible_vault_password.key`,
          and the encrypted vault password\nstored in Redis. Where either is missing,
          the failure is logged rather than\nraised, three times per synced device:\n\n1.
          `get_ansible_vault_password()` fails to open the key file and logs\n   `Unable
          to get ansible vault password` before re-raising.\n2. The `FileNotFoundError`
          is not a `ValueError`, so it lands in `get_vault()`'s\n   generic handler,
          which logs `Unable to get vault secret: ...`\n3. ...and then `Dropping encrypted
          entries`.\n\nSo a SONiC sync outside a worker \u2014 local development,
          or any run against a\nNetBox with no vault configured \u2014 produces three
          ERROR-level records per\ndevice, for devices that carry no secrets at all.\n\n##
          The change\n\nVault construction is deferred until the device actually carries
          a non-empty\n`secrets` custom field:\n\n```python\nnode_secrets = device.custom_fields.get(\"secrets\",
          {})\nif node_secrets is None:\n    node_secrets = {}\nif node_secrets:\n
          \   deep_decrypt(node_secrets, get_vault())\n```\n\nDevices **with** encrypted
          secrets are decrypted exactly as before. Devices\nwithout them no longer
          touch the key file or Redis. Note that `deep_decrypt` on\nan empty dict
          was already a no-op, so nothing is lost by skipping it \u2014 the only\nbehavioural
          change is that the vault is not built.\n\n## Tests\n\nTwo cases added to
          the existing `test_config_generator_snmp.py`, pinning both\ndirections:\n\n-
          `test_add_snmp_configuration_no_secrets_skips_vault` \u2014 neither `get_vault`
          nor\n  `deep_decrypt` is called, for both a missing and an explicitly `None`
          custom\n  field. This fails without the fix.\n- `test_add_snmp_configuration_with_secrets_uses_vault`
          \u2014 both are still called\n  when secrets are present, so the preserved
          path is guarded too.\n\n## Provenance\n\nThis fell out of ongoing work on
          an end-to-end golden test for SONiC config\ngeneration, which generates
          config against a plain NetBox with no vault\nconfigured and treats any ERROR-level
          log record as a failure. The bug it\nsurfaced is independent of that work,
          so it is split out here on its own \u2014 the\nnoise it removes affects
          any non-worker environment, and the fix touches only\n`config_generator.py`.\n"
        change_url: https://github.com/osism/python-osism/pull/2557
        commit_id: a5009fe478ddd8f1f8f90db1fa647d7935416db1
        patchset: a5009fe478ddd8f1f8f90db1fa647d7935416db1
        project:
          canonical_hostname: github.com
          canonical_name: github.com/osism/python-osism
          name: osism/python-osism
          short_name: python-osism
        src_dir: src/github.com/osism/python-osism
        topic: null
      change: '2557'
      change_message: "Build the SNMP vault only when secrets exist\n\n`_add_snmp_configuration`
        built a `VaultLib` for **every** device before it\nlooked at whether that
        device had anything encrypted to decrypt.\n\n`get_vault()` needs two things
        that only exist inside a worker container: the\nkey file `/share/ansible_vault_password.key`,
        and the encrypted vault password\nstored in Redis. Where either is missing,
        the failure is logged rather than\nraised, three times per synced device:\n\n1.
        `get_ansible_vault_password()` fails to open the key file and logs\n   `Unable
        to get ansible vault password` before re-raising.\n2. The `FileNotFoundError`
        is not a `ValueError`, so it lands in `get_vault()`'s\n   generic handler,
        which logs `Unable to get vault secret: ...`\n3. ...and then `Dropping encrypted
        entries`.\n\nSo a SONiC sync outside a worker \u2014 local development, or
        any run against a\nNetBox with no vault configured \u2014 produces three ERROR-level
        records per\ndevice, for devices that carry no secrets at all.\n\n## The change\n\nVault
        construction is deferred until the device actually carries a non-empty\n`secrets`
        custom field:\n\n```python\nnode_secrets = device.custom_fields.get(\"secrets\",
        {})\nif node_secrets is None:\n    node_secrets = {}\nif node_secrets:\n    deep_decrypt(node_secrets,
        get_vault())\n```\n\nDevices **with** encrypted secrets are decrypted exactly
        as before. Devices\nwithout them no longer touch the key file or Redis. Note
        that `deep_decrypt` on\nan empty dict was already a no-op, so nothing is lost
        by skipping it \u2014 the only\nbehavioural change is that the vault is not
        built.\n\n## Tests\n\nTwo cases added to the existing `test_config_generator_snmp.py`,
        pinning both\ndirections:\n\n- `test_add_snmp_configuration_no_secrets_skips_vault`
        \u2014 neither `get_vault` nor\n  `deep_decrypt` is called, for both a missing
        and an explicitly `None` custom\n  field. This fails without the fix.\n- `test_add_snmp_configuration_with_secrets_uses_vault`
        \u2014 both are still called\n  when secrets are present, so the preserved
        path is guarded too.\n\n## Provenance\n\nThis fell out of ongoing work on
        an end-to-end golden test for SONiC config\ngeneration, which generates config
        against a plain NetBox with no vault\nconfigured and treats any ERROR-level
        log record as a failure. The bug it\nsurfaced is independent of that work,
        so it is split out here on its own \u2014 the\nnoise it removes affects any
        non-worker environment, and the fix touches only\n`config_generator.py`.\n"
      change_url: https://github.com/osism/python-osism/pull/2557
      child_jobs: []
      commit_id: a5009fe478ddd8f1f8f90db1fa647d7935416db1
      event_id: 27a55860-9010-11f1-9262-e8fad0d61c5e
      executor:
        hostname: 521e9411259a
        inventory_file: /var/lib/zuul/builds/58588718dbc945e8aa62d8ce750778ab/ansible/inventory.yaml
        log_root: /var/lib/zuul/builds/58588718dbc945e8aa62d8ce750778ab/work/logs
        result_data_file: /var/lib/zuul/builds/58588718dbc945e8aa62d8ce750778ab/work/results.json
        src_root: /var/lib/zuul/builds/58588718dbc945e8aa62d8ce750778ab/work/src
        work_root: /var/lib/zuul/builds/58588718dbc945e8aa62d8ce750778ab/work
      include_vars: []
      items:
      - branch: main
        change: '2557'
        change_message: "Build the SNMP vault only when secrets exist\n\n`_add_snmp_configuration`
          built a `VaultLib` for **every** device before it\nlooked at whether that
          device had anything encrypted to decrypt.\n\n`get_vault()` needs two things
          that only exist inside a worker container: the\nkey file `/share/ansible_vault_password.key`,
          and the encrypted vault password\nstored in Redis. Where either is missing,
          the failure is logged rather than\nraised, three times per synced device:\n\n1.
          `get_ansible_vault_password()` fails to open the key file and logs\n   `Unable
          to get ansible vault password` before re-raising.\n2. The `FileNotFoundError`
          is not a `ValueError`, so it lands in `get_vault()`'s\n   generic handler,
          which logs `Unable to get vault secret: ...`\n3. ...and then `Dropping encrypted
          entries`.\n\nSo a SONiC sync outside a worker \u2014 local development,
          or any run against a\nNetBox with no vault configured \u2014 produces three
          ERROR-level records per\ndevice, for devices that carry no secrets at all.\n\n##
          The change\n\nVault construction is deferred until the device actually carries
          a non-empty\n`secrets` custom field:\n\n```python\nnode_secrets = device.custom_fields.get(\"secrets\",
          {})\nif node_secrets is None:\n    node_secrets = {}\nif node_secrets:\n
          \   deep_decrypt(node_secrets, get_vault())\n```\n\nDevices **with** encrypted
          secrets are decrypted exactly as before. Devices\nwithout them no longer
          touch the key file or Redis. Note that `deep_decrypt` on\nan empty dict
          was already a no-op, so nothing is lost by skipping it \u2014 the only\nbehavioural
          change is that the vault is not built.\n\n## Tests\n\nTwo cases added to
          the existing `test_config_generator_snmp.py`, pinning both\ndirections:\n\n-
          `test_add_snmp_configuration_no_secrets_skips_vault` \u2014 neither `get_vault`
          nor\n  `deep_decrypt` is called, for both a missing and an explicitly `None`
          custom\n  field. This fails without the fix.\n- `test_add_snmp_configuration_with_secrets_uses_vault`
          \u2014 both are still called\n  when secrets are present, so the preserved
          path is guarded too.\n\n## Provenance\n\nThis fell out of ongoing work on
          an end-to-end golden test for SONiC config\ngeneration, which generates
          config against a plain NetBox with no vault\nconfigured and treats any ERROR-level
          log record as a failure. The bug it\nsurfaced is independent of that work,
          so it is split out here on its own \u2014 the\nnoise it removes affects
          any non-worker environment, and the fix touches only\n`config_generator.py`.\n"
        change_url: https://github.com/osism/python-osism/pull/2557
        commit_id: a5009fe478ddd8f1f8f90db1fa647d7935416db1
        patchset: a5009fe478ddd8f1f8f90db1fa647d7935416db1
        project:
          canonical_hostname: github.com
          canonical_name: github.com/osism/python-osism
          name: osism/python-osism
          short_name: python-osism
          src_dir: src/github.com/osism/python-osism
        topic: null
      job: python-black
      jobtags: []
      max_attempts: 3
      message: QnVpbGQgdGhlIFNOTVAgdmF1bHQgb25seSB3aGVuIHNlY3JldHMgZXhpc3QKCmBfYWRkX3NubXBfY29uZmlndXJhdGlvbmAgYnVpbHQgYSBgVmF1bHRMaWJgIGZvciAqKmV2ZXJ5KiogZGV2aWNlIGJlZm9yZSBpdApsb29rZWQgYXQgd2hldGhlciB0aGF0IGRldmljZSBoYWQgYW55dGhpbmcgZW5jcnlwdGVkIHRvIGRlY3J5cHQuCgpgZ2V0X3ZhdWx0KClgIG5lZWRzIHR3byB0aGluZ3MgdGhhdCBvbmx5IGV4aXN0IGluc2lkZSBhIHdvcmtlciBjb250YWluZXI6IHRoZQprZXkgZmlsZSBgL3NoYXJlL2Fuc2libGVfdmF1bHRfcGFzc3dvcmQua2V5YCwgYW5kIHRoZSBlbmNyeXB0ZWQgdmF1bHQgcGFzc3dvcmQKc3RvcmVkIGluIFJlZGlzLiBXaGVyZSBlaXRoZXIgaXMgbWlzc2luZywgdGhlIGZhaWx1cmUgaXMgbG9nZ2VkIHJhdGhlciB0aGFuCnJhaXNlZCwgdGhyZWUgdGltZXMgcGVyIHN5bmNlZCBkZXZpY2U6CgoxLiBgZ2V0X2Fuc2libGVfdmF1bHRfcGFzc3dvcmQoKWAgZmFpbHMgdG8gb3BlbiB0aGUga2V5IGZpbGUgYW5kIGxvZ3MKICAgYFVuYWJsZSB0byBnZXQgYW5zaWJsZSB2YXVsdCBwYXNzd29yZGAgYmVmb3JlIHJlLXJhaXNpbmcuCjIuIFRoZSBgRmlsZU5vdEZvdW5kRXJyb3JgIGlzIG5vdCBhIGBWYWx1ZUVycm9yYCwgc28gaXQgbGFuZHMgaW4gYGdldF92YXVsdCgpYCdzCiAgIGdlbmVyaWMgaGFuZGxlciwgd2hpY2ggbG9ncyBgVW5hYmxlIHRvIGdldCB2YXVsdCBzZWNyZXQ6IC4uLmAKMy4gLi4uYW5kIHRoZW4gYERyb3BwaW5nIGVuY3J5cHRlZCBlbnRyaWVzYC4KClNvIGEgU09OaUMgc3luYyBvdXRzaWRlIGEgd29ya2VyIOKAlCBsb2NhbCBkZXZlbG9wbWVudCwgb3IgYW55IHJ1biBhZ2FpbnN0IGEKTmV0Qm94IHdpdGggbm8gdmF1bHQgY29uZmlndXJlZCDigJQgcHJvZHVjZXMgdGhyZWUgRVJST1ItbGV2ZWwgcmVjb3JkcyBwZXIKZGV2aWNlLCBmb3IgZGV2aWNlcyB0aGF0IGNhcnJ5IG5vIHNlY3JldHMgYXQgYWxsLgoKIyMgVGhlIGNoYW5nZQoKVmF1bHQgY29uc3RydWN0aW9uIGlzIGRlZmVycmVkIHVudGlsIHRoZSBkZXZpY2UgYWN0dWFsbHkgY2FycmllcyBhIG5vbi1lbXB0eQpgc2VjcmV0c2AgY3VzdG9tIGZpZWxkOgoKYGBgcHl0aG9uCm5vZGVfc2VjcmV0cyA9IGRldmljZS5jdXN0b21fZmllbGRzLmdldCgic2VjcmV0cyIsIHt9KQppZiBub2RlX3NlY3JldHMgaXMgTm9uZToKICAgIG5vZGVfc2VjcmV0cyA9IHt9CmlmIG5vZGVfc2VjcmV0czoKICAgIGRlZXBfZGVjcnlwdChub2RlX3NlY3JldHMsIGdldF92YXVsdCgpKQpgYGAKCkRldmljZXMgKip3aXRoKiogZW5jcnlwdGVkIHNlY3JldHMgYXJlIGRlY3J5cHRlZCBleGFjdGx5IGFzIGJlZm9yZS4gRGV2aWNlcwp3aXRob3V0IHRoZW0gbm8gbG9uZ2VyIHRvdWNoIHRoZSBrZXkgZmlsZSBvciBSZWRpcy4gTm90ZSB0aGF0IGBkZWVwX2RlY3J5cHRgIG9uCmFuIGVtcHR5IGRpY3Qgd2FzIGFscmVhZHkgYSBuby1vcCwgc28gbm90aGluZyBpcyBsb3N0IGJ5IHNraXBwaW5nIGl0IOKAlCB0aGUgb25seQpiZWhhdmlvdXJhbCBjaGFuZ2UgaXMgdGhhdCB0aGUgdmF1bHQgaXMgbm90IGJ1aWx0LgoKIyMgVGVzdHMKClR3byBjYXNlcyBhZGRlZCB0byB0aGUgZXhpc3RpbmcgYHRlc3RfY29uZmlnX2dlbmVyYXRvcl9zbm1wLnB5YCwgcGlubmluZyBib3RoCmRpcmVjdGlvbnM6CgotIGB0ZXN0X2FkZF9zbm1wX2NvbmZpZ3VyYXRpb25fbm9fc2VjcmV0c19za2lwc192YXVsdGAg4oCUIG5laXRoZXIgYGdldF92YXVsdGAgbm9yCiAgYGRlZXBfZGVjcnlwdGAgaXMgY2FsbGVkLCBmb3IgYm90aCBhIG1pc3NpbmcgYW5kIGFuIGV4cGxpY2l0bHkgYE5vbmVgIGN1c3RvbQogIGZpZWxkLiBUaGlzIGZhaWxzIHdpdGhvdXQgdGhlIGZpeC4KLSBgdGVzdF9hZGRfc25tcF9jb25maWd1cmF0aW9uX3dpdGhfc2VjcmV0c191c2VzX3ZhdWx0YCDigJQgYm90aCBhcmUgc3RpbGwgY2FsbGVkCiAgd2hlbiBzZWNyZXRzIGFyZSBwcmVzZW50LCBzbyB0aGUgcHJlc2VydmVkIHBhdGggaXMgZ3VhcmRlZCB0b28uCgojIyBQcm92ZW5hbmNlCgpUaGlzIGZlbGwgb3V0IG9mIG9uZ29pbmcgd29yayBvbiBhbiBlbmQtdG8tZW5kIGdvbGRlbiB0ZXN0IGZvciBTT05pQyBjb25maWcKZ2VuZXJhdGlvbiwgd2hpY2ggZ2VuZXJhdGVzIGNvbmZpZyBhZ2FpbnN0IGEgcGxhaW4gTmV0Qm94IHdpdGggbm8gdmF1bHQKY29uZmlndXJlZCBhbmQgdHJlYXRzIGFueSBFUlJPUi1sZXZlbCBsb2cgcmVjb3JkIGFzIGEgZmFpbHVyZS4gVGhlIGJ1ZyBpdApzdXJmYWNlZCBpcyBpbmRlcGVuZGVudCBvZiB0aGF0IHdvcmssIHNvIGl0IGlzIHNwbGl0IG91dCBoZXJlIG9uIGl0cyBvd24g4oCUIHRoZQpub2lzZSBpdCByZW1vdmVzIGFmZmVjdHMgYW55IG5vbi13b3JrZXIgZW52aXJvbm1lbnQsIGFuZCB0aGUgZml4IHRvdWNoZXMgb25seQpgY29uZmlnX2dlbmVyYXRvci5weWAuCg==
      patchset: a5009fe478ddd8f1f8f90db1fa647d7935416db1
      pipeline: check
      playbook_context:
        playbook_projects:
          trusted/project_0/github.com/osism/zuul-config:
            canonical_name: github.com/osism/zuul-config
            checkout: main
            commit: 71b711c422c10c242a8f785dc6d41ed9d12e9cd3
          trusted/project_1/github.com/osism/openinfra-zuul-jobs:
            canonical_name: github.com/osism/openinfra-zuul-jobs
            checkout: master
            commit: 242732586e2cba04d04867d3e302888c766bc231
          trusted/project_2/github.com/osism/zuul-jobs:
            canonical_name: github.com/osism/zuul-jobs
            checkout: main
            commit: dcb06ea8a3ad422cc9d98b376216617b2daa6a02
          untrusted/project_0/github.com/osism/zuul-jobs:
            canonical_name: github.com/osism/zuul-jobs
            checkout: main
            commit: dcb06ea8a3ad422cc9d98b376216617b2daa6a02
          untrusted/project_1/github.com/osism/zuul-config:
            canonical_name: github.com/osism/zuul-config
            checkout: main
            commit: 71b711c422c10c242a8f785dc6d41ed9d12e9cd3
          untrusted/project_2/github.com/osism/openinfra-zuul-jobs:
            canonical_name: github.com/osism/openinfra-zuul-jobs
            checkout: master
            commit: 242732586e2cba04d04867d3e302888c766bc231
        playbooks:
        - path: untrusted/project_0/github.com/osism/zuul-jobs/playbooks/python-black/run.yml
          roles:
          - checkout: main
            checkout_description: zuul branch
            link_name: ansible/playbook_0/role_0/zuul-config
            link_target: untrusted/project_1/github.com/osism/zuul-config
            role_path: ansible/playbook_0/role_0/zuul-config/roles
          - checkout: master
            checkout_description: project default branch
            link_name: ansible/playbook_0/role_1/openinfra-zuul-jobs
            link_target: untrusted/project_2/github.com/osism/openinfra-zuul-jobs
            role_path: ansible/playbook_0/role_1/openinfra-zuul-jobs/roles
          - checkout: main
            checkout_description: playbook branch
            link_name: ansible/playbook_0/role_2/zuul-jobs
            link_target: untrusted/project_0/github.com/osism/zuul-jobs
            role_path: ansible/playbook_0/role_2/zuul-jobs/roles
      post_review: false
      post_timeout: 1800
      pre_timeout: null
      project:
        canonical_hostname: github.com
        canonical_name: github.com/osism/python-osism
        name: osism/python-osism
        short_name: python-osism
        src_dir: src/github.com/osism/python-osism
      projects:
        github.com/osism/python-osism:
          canonical_hostname: github.com
          canonical_name: github.com/osism/python-osism
          checkout: main
          checkout_description: zuul branch
          commit: 70fa1f878d0f40feaf3422fc56b9aa6b88beb0e5
          name: osism/python-osism
          required: false
          short_name: python-osism
          src_dir: src/github.com/osism/python-osism
      ref: refs/pull/2557/head
      resources: {}
      tenant: osism
      timeout: 1800
      topic: null
      voting: true
