{
  "generated_at": "2026-09-11T02:21:19Z",
  "lane": {
    "target": "spinel",
    "runner": "each test file compiled to its own native binary by spinel, then run"
  },
  "campfire": {
    "repo": "basecamp/once-campfire",
    "pinned": true,
    "path": "/home/rubys/once-campfire",
    "sha": "94a48aacb65af0fe25c7b850d4ced055e27077a7"
  },
  "roundhouse": {
    "sha": "2bc2cb242777dce8430aec211fe9af9ddca4c608",
    "dirty": false
  },
  "ruby": {
    "version": "4.0.5"
  },
  "spinel": {
    "version": "spinel a4b7238e78f8 (unreleased) [cc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0]",
    "sha": "a4b7238e78f8"
  },
  "emit": {
    "errors": 0,
    "warnings": 893,
    "by_kind": {
      "gradual_untyped": 372,
      "unresolved_type": 281,
      "lower_residue": 150,
      "unsupported": 53,
      "blank_unlowered": 36,
      "missing_preload": 1
    },
    "files": 1157
  },
  "stubs": {
    "spliced": false
  },
  "attribution": {
    "per_test": true,
    "note": "Each unpassed test carries its own message; a file that never ran contributes its whole count against its load error."
  },
  "tests": {
    "total": 288,
    "passed": 148,
    "failed": 140
  },
  "files": {
    "total": 54,
    "green": 17,
    "aborted": 9,
    "unbuilt": 9
  },
  "scope": {
    "note": "Every test file campfire's own suite declares, read from the emitted Makefile's SPINEL_TESTS rather than restated here — a `find test -name '*_test.rb'` would also sweep in the scaffold's own tests, which are not campfire's."
  },
  "causes": [
    {
      "slug": "silent-divergence",
      "title": "The emit ran and answered differently",
      "owner": "unknown",
      "failures": 16,
      "share": 0.1143,
      "note": "NOT a root cause — the bucket of tests that still need one. Nothing raised: the emitted code ran to completion and produced a different answer, so each of these has to be followed down its own chain. This is the most valuable cluster on the page and the most expensive: a missing method names itself, a wrong answer does not.",
      "stale_rule": false,
      "at_zero": null,
      "stubbed_zero": false,
      "examples": [
        {
          "example": "test/message_attachment_test · Message::AttachmentTest#test_creating_a_blank_message_with_attachment_will_use_filename_as_plain_text_body",
          "error": "assert_equal failed"
        },
        {
          "example": "test/message_searchable_test · Message::SearchableTest#test_message_body_is_indexed_and_searchable",
          "error": "assert_equal failed"
        },
        {
          "example": "test/message_searchable_test · Message::SearchableTest#test_search_results_are_returned_in_message_order",
          "error": "assert_equal failed"
        },
        {
          "example": "test/message_searchable_test · Message::SearchableTest#test_rich_text_body_is_converted_to_plain_text_for_indexing",
          "error": "assert_equal failed"
        },
        {
          "example": "test/message_test · MessageTest#test_mentionees",
          "error": "assert_equal failed"
        }
      ]
    },
    {
      "slug": "arity-divergence",
      "title": "An emitted method's arity does not match its caller",
      "owner": "compiler",
      "failures": 4,
      "share": 0.0286,
      "note": "The receiver exists and the name resolves; the shape does not. Usually a lowering that dropped or added a parameter — kwargs folded into a positional, a block-form helper emitted in its non-block shape. Each needs the emitted definition read against its call site.",
      "stale_rule": false,
      "at_zero": null,
      "stubbed_zero": false,
      "examples": [
        {
          "example": "test/push_subscription_test · Push::SubscriptionTest#test_delivery_is_skipped_when_the_endpoint_no_longer_resolves_to_a_public_ip",
          "error": "wrong number of arguments (given 1, expected 8)"
        },
        {
          "example": "test/push_subscription_test · Push::SubscriptionTest#test_delivery_is_skipped_for_a_non_permitted_host_even_when_it_resolves_publicly",
          "error": "wrong number of arguments (given 1, expected 8)"
        },
        {
          "example": "test/push_subscription_test · Push::SubscriptionTest#test_delivery_is_skipped_for_a_permitted_host_on_a_non_default_port",
          "error": "wrong number of arguments (given 1, expected 8)"
        },
        {
          "example": "test/webhook_test · WebhookTest#test_delivery_with_ok_attachment_reply",
          "error": "wrong number of arguments (given 1, expected 3)"
        }
      ]
    },
    {
      "slug": "allow-browser",
      "title": "`allow_browser` — the modern-browser gate",
      "owner": "compiler",
      "failures": 1,
      "share": 0.0071,
      "note": "campfire's own concern calls `allow_browser versions: VERSIONS, block: -> { render template: \"sessions/incompatible_browser\" }`, so the version FLOOR is the app's (`{ safari: 17.2, chrome: 120, … }`) and what is missing is ours: the macro, its `block:` fallback, and parsing a User-Agent into a browser plus version. Rails reads that last part from the `useragent` gem's rule table — PORT the table, do not derive it. The file is 7/8 on this one test.",
      "stale_rule": false,
      "at_zero": null,
      "stubbed_zero": false,
      "examples": [
        {
          "example": "test/sessions_controller_test · SessionsControllerTest#test_new_denied_with_incompatible_browser",
          "error": "expected \"h1\" in response body"
        }
      ]
    },
    {
      "slug": "params-hash-in-path",
      "title": "A params hash interpolated into the request PATH",
      "owner": "compiler",
      "failures": 0,
      "share": 0.0,
      "note": "The request went out as `POST /users/{params: {push_subscription: {…}}}` — the params object rendered into the path instead of being sent as the body. Bracket-nested query parameters are the shape behind it: the test writes `params: { push_subscription: { endpoint: …, keys: { … } } }` and nothing splits the nesting into a body. Reads as a routing error, which is why it sat untriaged.",
      "stale_rule": true,
      "at_zero": null,
      "stubbed_zero": false,
      "examples": []
    },
    {
      "slug": "id-zero-sentinel",
      "title": "An unsaved `id` is 0, not nil — and a lookup used it",
      "owner": "compiler",
      "failures": 0,
      "share": 0.0,
      "note": "A deliberate divergence, ledgered in docs/pipeline/runtime.md: `ActiveRecord::Base#initialize` seeds `@id = 0` so ids stay plain machine integers across every target, where Rails answers nil. This is where that choice becomes visible — a code path that would have skipped a nil lookup instead performs one for id 0.",
      "stale_rule": false,
      "at_zero": "zero is the intended reading. This is a deliberate divergence rather than a gap, and the rule exists to catch the day it becomes visible again.",
      "stubbed_zero": false,
      "examples": []
    },
    {
      "slug": "pagination",
      "title": "geared_pagination's controller surface",
      "owner": "compiler",
      "failures": 0,
      "share": 0.0,
      "note": "campfire paginates with geared_pagination — not pagy — whose concern injects `set_page_and_extract_portion_from` into the controller. It answers from a Base reopen in runtime/ruby/action_controller/pagination.rb, so the question underneath it (carry the gem, or lower pagination ourselves) was settled by lowering it.",
      "stale_rule": false,
      "at_zero": "landed in 0ef8fb79; the rule stays as a regression tripwire.",
      "stubbed_zero": false,
      "examples": []
    },
    {
      "slug": "out-of-scope-gems",
      "title": "A gem the emit does not carry",
      "owner": "gem",
      "failures": 0,
      "share": 0.0,
      "note": "web push, concurrent-ruby, and sentry-ruby. The RQRCode arm of this rule matches nothing now that qr_code_controller_test is green. Each is a decision about gem fate rather than modeling debt — shim the surface the app calls, or declare it out of scope and ledger it. None of them is on the path to more coverage than the tests naming it.",
      "stale_rule": true,
      "at_zero": null,
      "stubbed_zero": false,
      "examples": []
    },
    {
      "slug": "route-helper-takes-a-record",
      "title": "A route helper interpolated a record instead of its id",
      "owner": "compiler",
      "failures": 0,
      "share": 0.0,
      "note": "`room_path(room)` rendered `#<Room:0x…>` into the path. Route helpers project to `.id` only where the SEGMENT holds one (8b4258e5); these are the sites that projection does not reach yet. Visible only as a wrong string, which is why they surface as redirect assertions rather than exceptions.",
      "stale_rule": true,
      "at_zero": null,
      "stubbed_zero": false,
      "examples": []
    },
    {
      "slug": "conditional-get",
      "title": "`fresh_when` / `stale?` — conditional GET",
      "owner": "compiler",
      "failures": 0,
      "share": 0.0,
      "note": "ETag/Last-Modified handling on the controller. Small in surface and shared by every target once the response object carries the headers; the tests behind it assert 304s, so they are only reachable after it lands.",
      "stale_rule": false,
      "at_zero": "`fresh_when` / `stale?` landed in 7ea262e2; the rule stays as a regression tripwire.",
      "stubbed_zero": false,
      "examples": []
    },
    {
      "slug": "active-storage-attachments",
      "title": "Active Storage — the attachment scopes and the bytes",
      "owner": "compiler",
      "failures": 0,
      "share": 0.0,
      "note": "The metadata half answers (205c3031). What is left is the macro-generated preload scopes (`with_attached_*`, `with_rich_text_*`) and everything variant-shaped: `ActiveStorage::VariantWithRecord`, `representation` and `preview` on an `Attached`, and the bytes. Avatars and logos reach it now that the fixture-file helpers in front of them answer — clearing a wall ahead of this cause moves tests INTO it, which is what just happened.",
      "stale_rule": true,
      "at_zero": null,
      "stubbed_zero": false,
      "examples": []
    },
    {
      "slug": "belongs-to-autosave",
      "title": "`belongs_to` autosave — an unsaved target saved with its owner",
      "owner": "compiler",
      "failures": 0,
      "share": 0.0,
      "note": "Assigning an unsaved record and saving the owner saves the target first in Rails. The emit reads `value.id` (0) and the presence validation fails. Carries a stub entry in scripts/campfire-walk-stubs.rb, so the count here is what the stub does NOT cover.",
      "stale_rule": false,
      "at_zero": null,
      "stubbed_zero": true,
      "examples": []
    },
    {
      "slug": "view-helper-in-helper-module",
      "title": "A view helper called from a helper MODULE",
      "owner": "compiler",
      "failures": 0,
      "share": 0.0,
      "note": "Inside a template these expand at transpile time. Inside a helper module the expansion has no template to splice into, so the call survives to runtime and lands on a bare module. Already the shape behind several closed findings (`button_to` with a block, `link_to` with a block); the remaining ones are the same wall a method away from the template.",
      "stale_rule": true,
      "at_zero": null,
      "stubbed_zero": false,
      "examples": []
    },
    {
      "slug": "broadcast-assertions",
      "title": "Broadcast assertions over a queue that is a log",
      "owner": "compiler",
      "failures": 0,
      "share": 0.0,
      "note": "The emit records broadcasts into `Broadcasts.log` rather than delivering them through a cable adapter, so the app's own `assert_broadcasts` counts a different thing than it was written against. Ties into the cable work — the dispatch half, not the streaming half.",
      "stale_rule": true,
      "at_zero": null,
      "stubbed_zero": false,
      "examples": []
    },
    {
      "slug": "turbo-streams-channel",
      "title": "`Turbo::StreamsChannel` as a constant the app can name",
      "owner": "compiler",
      "failures": 0,
      "share": 0.0,
      "note": "Broadcasts lower to `Broadcasts.record`, which is the portable shape; the app also names the channel class directly to broadcast or to assert. The constant has no emitted counterpart, so those tests stop before reaching the broadcast at all.",
      "stale_rule": false,
      "at_zero": "the constant landed in fd1a3259; the rule stays as a regression tripwire.",
      "stubbed_zero": false,
      "examples": []
    },
    {
      "slug": "rails-module-facade",
      "title": "`Rails.configuration` and the routes object",
      "owner": "compiler",
      "failures": 0,
      "share": 0.0,
      "note": "The emitted `Rails` module answers a small surface; the app reaches past it for configuration and for the application's route set (to build URLs outside a request). Each addition here is a decision about what part of Rails' global state the port models at all, rather than a missing method.",
      "stale_rule": true,
      "at_zero": null,
      "stubbed_zero": false,
      "examples": []
    },
    {
      "slug": "globalid-sgid",
      "title": "Global IDs — minting and dereferencing an sgid",
      "owner": "compiler",
      "failures": 0,
      "share": 0.0,
      "note": "docs/pipeline/runtime.md now carries the split: `attachable_ids(\"User\")` verifies an sgid and `lower::attachables_grep` rewrites `body.attachables.grep(User)` into a query over the ids, so a caller that NAMES its class resolves. What is left is MINTING — `to_gid_param` on a record — and the name-keyed class dispatch a bare `attachables` would need to answer anything but `[]`. Mint plus resolve plus that map is a body of work of its own, not a method.",
      "stale_rule": true,
      "at_zero": null,
      "stubbed_zero": false,
      "examples": []
    },
    {
      "slug": "actiontext-attachment-from-node",
      "title": "`ActionText::Attachment.from_node` — building an attachment from a parsed node",
      "owner": "compiler",
      "failures": 0,
      "share": 0.0,
      "note": "Named in docs/pipeline/runtime.md's \"What is left\" for attachments, alongside `ActionText::Attachables::MissingAttachable`. The PARSE already works — `#attachments` returns every node with every attribute it carried — so this is the constructor that turns one of those nodes back into an attachment object, plus the missing-attachable case a stale sgid should land in.",
      "stale_rule": true,
      "at_zero": null,
      "stubbed_zero": false,
      "examples": []
    },
    {
      "slug": "relation-vs-array",
      "title": "A relation answering as an Array, or an Array asked for relation methods",
      "owner": "compiler",
      "failures": 0,
      "share": 0.0,
      "note": "Both directions of one gap: a query lowered to an Array is then asked for `find_by`/`new`/a dynamic finder, or a Relation is asked for an Enumerable method the shim does not carry. `Model.where(...)` is a relation, not an array of records (eb57882f) — this is the residue of that same distinction.",
      "stale_rule": true,
      "at_zero": null,
      "stubbed_zero": false,
      "examples": []
    },
    {
      "slug": "params-object-representation",
      "title": "A params object read as a Hash",
      "owner": "compiler",
      "failures": 0,
      "share": 0.0,
      "note": "The emit gives each permitted set its own type (`RoomParams`), and the app then indexes it, deletes from it, or hands it somewhere expecting a Hash. Both directions are the same modeling question — what a params object IS — and it is the one the indifferent-access design addresses.",
      "stale_rule": true,
      "at_zero": null,
      "stubbed_zero": false,
      "examples": []
    },
    {
      "slug": "sti-becomes",
      "title": "`becomes!` — recasting a record to an STI sibling",
      "owner": "compiler",
      "failures": 0,
      "share": 0.0,
      "note": "campfire opens and closes rooms by recasting: `room.becomes!(Rooms::Open)` rewrites the type column and returns the record as the sibling class. The STI read and write halves landed first (7aad7ba7, 7245435a); the recast followed in f2d42854, where the copy went into the LOWERER.",
      "stale_rule": false,
      "at_zero": "`becomes!` landed in f2d42854; the rule stays as a regression tripwire.",
      "stubbed_zero": false,
      "examples": []
    },
    {
      "slug": "fixture-accessors",
      "title": "A fixture accessor the emitted loader never defined",
      "owner": "compiler",
      "failures": 0,
      "share": 0.0,
      "note": "`users(:david)`-style accessors are generated per fixture file. Where one is missing the test cannot name its own data, so nothing behind it has been seen. The name comes from the app's own fixtures rather than from Rails, which is what separates this from the emitted test base class's own surface.",
      "stale_rule": true,
      "at_zero": null,
      "stubbed_zero": false,
      "examples": []
    },
    {
      "slug": "test-harness-surface",
      "title": "The emitted test base class is missing Rails' test surface",
      "owner": "compiler",
      "failures": 0,
      "share": 0.0,
      "note": "Not the app's code failing — the scaffolding around it. `file_fixture` and `fixture_file_upload` read from test/fixtures/files, `response` is the integration-test response object, and the bare `assert` family comes from Minitest itself. Every one of these is a method the emitted TestBase would have to answer before the assertion behind it is even reached, so this cluster hides an unknown number of further walls.",
      "stale_rule": false,
      "at_zero": "the family landed over several commits, `fixture_file_upload` last in f86ac0b6; the rule stays as a regression tripwire.",
      "stubbed_zero": false,
      "examples": []
    },
    {
      "slug": "unclassified",
      "title": "Not yet triaged",
      "owner": "unknown",
      "failures": 119,
      "share": 0.85,
      "note": "No rule in bench/campfire/suite-causes.json matches these. Triage, then add a rule.",
      "stale_rule": false,
      "examples": [
        {
          "example": "test/account_test · (file did not run)",
          "error": "runtime/active_storage.rb:201: error: incompatible types when assigning to type ‘sp_RbVal’ from type ‘sp_int’ {aka ‘long int’}"
        },
        {
          "example": "test/accounts_bots_controller_test · Accounts::BotsControllerTest#test_update",
          "error": "no implicit conversion of User into Integer"
        },
        {
          "example": "test/accounts_logos_controller_test · (file did not run)",
          "error": "spinel: test/accounts_logos_controller_test.rb:67: unsupported call: node 132636 (CallNode `new_from_buffer`) recv=ConstantPathNode/ty49 argc=2 arg0ty6"
        },
        {
          "example": "test/action_text_attachment_test · (file did not run)",
          "error": "spinel: test/action_text_attachment_test.rb:25: unsupported call: node 132495 (CallNode `from_node`) recv=ConstantPathNode/ty49 argc=1 arg0ty50"
        },
        {
          "example": "test/first_runs_controller_test · FirstRunsControllerTest#test_create_is_not_vulnerable_to_race_conditions",
          "error": "uninitialized constant CyclicBarrier"
        },
        {
          "example": "test/membership_test · MembershipTest#test_removing_a_membership_resets_the_user_s_connections",
          "error": "undefined method 'expects' for an instance of User"
        },
        {
          "example": "test/message_attachment_test · Message::AttachmentTest#test_creating_a_message_creates_image_thumbnail",
          "error": "undefined method 'image' for unknown"
        },
        {
          "example": "test/message_attachment_test · Message::AttachmentTest#test_creating_a_message_creates_video_preview",
          "error": "undefined method 'attached?' for unknown"
        },
        {
          "example": "test/messages_boosts_by_bots_controller_test · Messages::Boosts::ByBotsControllerTest#test_create_adds_a_boost_to_the_message_and_returns_it",
          "error": "undefined method 'rewind' for an instance of String"
        },
        {
          "example": "test/messages_boosts_by_bots_controller_test · Messages::Boosts::ByBotsControllerTest#test_create_with_text_content",
          "error": "undefined method 'rewind' for an instance of String"
        },
        {
          "example": "test/messages_boosts_by_bots_controller_test · Messages::Boosts::ByBotsControllerTest#test_create_broadcasts_the_boost",
          "error": "undefined method 'rewind' for an instance of String"
        },
        {
          "example": "test/messages_boosts_by_bots_controller_test · Messages::Boosts::ByBotsControllerTest#test_create_without_content",
          "error": "undefined method 'rewind' for an instance of String"
        }
      ]
    }
  ],
  "by_file": [
    {
      "file": "test/messages_by_bots_controller_test",
      "status": "build",
      "tests": 23,
      "passed": 0,
      "failed": 23,
      "first_error": "runtime/cgi_io.rb:206: error: incompatible types when assigning to type ‘sp_int’ {aka ‘long int’} from type ‘sp_RbVal’",
      "aborted": true
    },
    {
      "file": "test/opengraph_fetch_test",
      "status": "build",
      "tests": 11,
      "passed": 0,
      "failed": 11,
      "first_error": "spinel: test/opengraph_fetch_test.rb:139: unsupported equality: node 133105 (CallNode `!=`) recv=StringNode/ty6 argc=1 arg0ty1",
      "aborted": true
    },
    {
      "file": "test/opengraph_metadata_test",
      "status": "fail",
      "tests": 10,
      "passed": 0,
      "failed": 10,
      "first_error": "FAIL Opengraph::MetadataTest#test_successful_fetch: gem facade: Nokogiri.HTML is stubbed (write-path only; see runtime/gem_facades.rb)"
    },
    {
      "file": "test/push_subscription_test",
      "status": "fail",
      "tests": 17,
      "passed": 10,
      "failed": 7,
      "first_error": "FAIL Push::SubscriptionTest#test_rejects_endpoint_whose_host_resolves_to_nothing_without_raising: mocha: Resolv.stubs(:getaddresses) with 1 chained link(s) is n"
    },
    {
      "file": "test/accounts_logos_controller_test",
      "status": "build",
      "tests": 6,
      "passed": 0,
      "failed": 6,
      "first_error": "spinel: test/accounts_logos_controller_test.rb:67: unsupported call: node 132636 (CallNode `new_from_buffer`) recv=ConstantPathNode/ty49 argc=2 arg0ty6",
      "aborted": true
    },
    {
      "file": "test/users_push_subscriptions_controller_test",
      "status": "build",
      "tests": 6,
      "passed": 0,
      "failed": 6,
      "first_error": "test/users_push_subscriptions_controller_test.rb:35: error: cannot convert to a pointer type",
      "aborted": true
    },
    {
      "file": "test/opengraph_location_test",
      "status": "fail",
      "tests": 7,
      "passed": 2,
      "failed": 5,
      "first_error": "FAIL Opengraph::LocationTest#test_url_validations: assertion failed"
    },
    {
      "file": "test/room_push_test",
      "status": "fail",
      "tests": 5,
      "passed": 0,
      "failed": 5,
      "first_error": "FAIL Room::PushTest#test_deliver_new_message_to_other_room_users_with_push_subscriptions: uninitialized constant ThreadPoolExecutor"
    },
    {
      "file": "test/users_bans_controller_test",
      "status": "fail",
      "tests": 7,
      "passed": 2,
      "failed": 5,
      "first_error": "FAIL Users::BansControllerTest#test_create_bans_user_and_creates_ban_records_from_sessions: undefined method 'each' for unknown"
    },
    {
      "file": "test/account_test",
      "status": "build",
      "tests": 4,
      "passed": 0,
      "failed": 4,
      "first_error": "runtime/active_storage.rb:201: error: incompatible types when assigning to type ‘sp_RbVal’ from type ‘sp_int’ {aka ‘long int’}",
      "aborted": true
    },
    {
      "file": "test/messages_boosts_by_bots_controller_test",
      "status": "fail",
      "tests": 12,
      "passed": 8,
      "failed": 4,
      "first_error": "FAIL Messages::Boosts::ByBotsControllerTest#test_create_adds_a_boost_to_the_message_and_returns_it: undefined method 'rewind' for an instance of String"
    },
    {
      "file": "test/unfurl_links_controller_test",
      "status": "fail",
      "tests": 5,
      "passed": 1,
      "failed": 4,
      "first_error": "FAIL UnfurlLinksControllerTest#test_create: gem facade: Nokogiri.HTML is stubbed (write-path only; see runtime/gem_facades.rb)"
    },
    {
      "file": "test/action_text_attachment_test",
      "status": "build",
      "tests": 3,
      "passed": 0,
      "failed": 3,
      "first_error": "spinel: test/action_text_attachment_test.rb:25: unsupported call: node 132495 (CallNode `from_node`) recv=ConstantPathNode/ty49 argc=1 arg0ty50",
      "aborted": true
    },
    {
      "file": "test/message_attachment_test",
      "status": "fail",
      "tests": 3,
      "passed": 0,
      "failed": 3,
      "first_error": "FAIL Message::AttachmentTest#test_creating_a_message_creates_image_thumbnail: undefined method 'image' for unknown"
    },
    {
      "file": "test/message_searchable_test",
      "status": "fail",
      "tests": 3,
      "passed": 0,
      "failed": 3,
      "first_error": "FAIL Message::SearchableTest#test_message_body_is_indexed_and_searchable: assert_equal failed"
    },
    {
      "file": "test/messages_controller_test",
      "status": "fail",
      "tests": 15,
      "passed": 12,
      "failed": 3,
      "first_error": "FAIL MessagesControllerTest#test_index_returns_a_page_before_the_specified_message: undefined method 'id' for unknown"
    },
    {
      "file": "test/opengraph_document_test",
      "status": "fail",
      "tests": 3,
      "passed": 0,
      "failed": 3,
      "first_error": "FAIL Opengraph::DocumentTest#test_extract_opengraph_tags_using_property_attribute: gem facade: Nokogiri.HTML is stubbed (write-path only; see runtime/gem_facade"
    },
    {
      "file": "test/rooms_controller_test",
      "status": "fail",
      "tests": 5,
      "passed": 2,
      "failed": 3,
      "first_error": "FAIL RoomsControllerTest#test_show: undefined method 'presence' for unknown"
    },
    {
      "file": "test/rooms_direct_test",
      "status": "build",
      "tests": 3,
      "passed": 0,
      "failed": 3,
      "first_error": "test/rooms_direct_test.rb:23: error: initialization of ‘sp_Relation *’ {aka ‘struct sp_Relation_s *’} from incompatible pointer type ‘sp_PolyArray *’ [-Werror=i",
      "aborted": true
    },
    {
      "file": "test/searches_controller_test",
      "status": "fail",
      "tests": 5,
      "passed": 2,
      "failed": 3,
      "first_error": "FAIL SearchesControllerTest#test_index_initial_view: expected \".message\" in response body"
    },
    {
      "file": "test/user_avatar_test",
      "status": "build",
      "tests": 3,
      "passed": 0,
      "failed": 3,
      "first_error": "runtime/active_storage.rb:201: error: incompatible types when assigning to type ‘sp_RbVal’ from type ‘sp_int’ {aka ‘long int’}",
      "aborted": true
    },
    {
      "file": "test/users_sidebars_controller_test",
      "status": "fail",
      "tests": 3,
      "passed": 0,
      "failed": 3,
      "first_error": "FAIL Users::SidebarsControllerTest#test_show: assert_match failed: expected \"<!DOCTYPE html>\\n<html>\\n  <head>\\n    <title>Campfire</title>\\n\\n    <meta name=\\\"",
      "aborted": false
    },
    {
      "file": "test/webhook_test",
      "status": "fail",
      "tests": 6,
      "passed": 3,
      "failed": 3,
      "first_error": "FAIL WebhookTest#test_payload: undefined method 'with' for unknown"
    },
    {
      "file": "test/rooms_open_test",
      "status": "build",
      "tests": 2,
      "passed": 0,
      "failed": 2,
      "first_error": "runtime/active_record/connection.rb:143: error: invalid initializer",
      "aborted": true
    },
    {
      "file": "test/sessions_controller_test",
      "status": "fail",
      "tests": 8,
      "passed": 6,
      "failed": 2,
      "first_error": "FAIL SessionsControllerTest#test_new_denied_with_incompatible_browser: expected \"h1\" in response body"
    },
    {
      "file": "test/user_bot_test",
      "status": "fail",
      "tests": 4,
      "passed": 2,
      "failed": 2,
      "first_error": "FAIL User::BotTest#test_create_bot: mocha: SecureRandom.stubs(:alphanumeric) with 1 chained link(s) is not a stub shape this target serves"
    },
    {
      "file": "test/accounts_bots_controller_test",
      "status": "fail",
      "tests": 5,
      "passed": 4,
      "failed": 1,
      "first_error": "FAIL Accounts::BotsControllerTest#test_update: no implicit conversion of User into Integer"
    },
    {
      "file": "test/first_runs_controller_test",
      "status": "fail",
      "tests": 4,
      "passed": 3,
      "failed": 1,
      "first_error": "FAIL FirstRunsControllerTest#test_create_is_not_vulnerable_to_race_conditions: uninitialized constant CyclicBarrier"
    },
    {
      "file": "test/membership_test",
      "status": "fail",
      "tests": 9,
      "passed": 8,
      "failed": 1,
      "first_error": "FAIL MembershipTest#test_removing_a_membership_resets_the_user_s_connections: undefined method 'expects' for an instance of User"
    },
    {
      "file": "test/message_test",
      "status": "fail",
      "tests": 3,
      "passed": 2,
      "failed": 1,
      "first_error": "FAIL MessageTest#test_mentionees: assert_equal failed"
    },
    {
      "file": "test/qr_code_controller_test",
      "status": "fail",
      "tests": 1,
      "passed": 0,
      "failed": 1,
      "first_error": "FAIL QrCodeControllerTest#test_show_renders_a_qr_code_as_a_cacheable_svg_image: gem facade: RQRCode::QRCode.new is stubbed (write-path only; see runtime/gem_fac"
    },
    {
      "file": "test/room_test",
      "status": "fail",
      "tests": 6,
      "passed": 5,
      "failed": 1,
      "first_error": "FAIL RoomTest#test_revise_memberships: undefined method 'present?' for an instance of User"
    },
    {
      "file": "test/rooms_closeds_controller_test",
      "status": "fail",
      "tests": 9,
      "passed": 8,
      "failed": 1,
      "first_error": "FAIL Rooms::ClosedsControllerTest#test_remove_yourself: no implicit conversion of Hash into String"
    },
    {
      "file": "test/rooms_opens_controller_test",
      "status": "fail",
      "tests": 9,
      "passed": 8,
      "failed": 1,
      "first_error": "FAIL Rooms::OpensControllerTest#test_create: assert_equal failed"
    },
    {
      "file": "test/user_test",
      "status": "fail",
      "tests": 4,
      "passed": 3,
      "failed": 1,
      "first_error": "FAIL UserTest#test_deactivating_a_user_deletes_push_subscriptions_searches_memberships_for_non_direct_rooms_and_changes_their_email_address: mocha: SecureRandom"
    },
    {
      "file": "test/users_avatars_controller_test",
      "status": "fail",
      "tests": 4,
      "passed": 3,
      "failed": 1,
      "first_error": "FAIL Users::AvatarsControllerTest#test_show_image: assert_equal failed"
    },
    {
      "file": "test/users_profiles_controller_test",
      "status": "fail",
      "tests": 3,
      "passed": 2,
      "failed": 1,
      "first_error": "FAIL Users::ProfilesControllerTest#test_show: undefined method 'presence' for unknown"
    },
    {
      "file": "test/account_joinable_test",
      "status": "pass",
      "tests": 2,
      "passed": 2,
      "failed": 0,
      "first_error": ""
    },
    {
      "file": "test/accounts_bots_keys_controller_test",
      "status": "pass",
      "tests": 1,
      "passed": 1,
      "failed": 0,
      "first_error": ""
    },
    {
      "file": "test/accounts_controller_test",
      "status": "pass",
      "tests": 4,
      "passed": 4,
      "failed": 0,
      "first_error": ""
    },
    {
      "file": "test/accounts_custom_styles_controller_test",
      "status": "pass",
      "tests": 3,
      "passed": 3,
      "failed": 0,
      "first_error": ""
    },
    {
      "file": "test/accounts_join_codes_controller_test",
      "status": "pass",
      "tests": 2,
      "passed": 2,
      "failed": 0,
      "first_error": ""
    },
    {
      "file": "test/accounts_users_controller_test",
      "status": "pass",
      "tests": 3,
      "passed": 3,
      "failed": 0,
      "first_error": ""
    },
    {
      "file": "test/autocompletable_users_controller_test",
      "status": "pass",
      "tests": 4,
      "passed": 4,
      "failed": 0,
      "first_error": ""
    },
    {
      "file": "test/block_banned_requests_test",
      "status": "pass",
      "tests": 3,
      "passed": 3,
      "failed": 0,
      "first_error": ""
    },
    {
      "file": "test/first_run_test",
      "status": "pass",
      "tests": 3,
      "passed": 3,
      "failed": 0,
      "first_error": ""
    },
    {
      "file": "test/messages_boosts_controller_test",
      "status": "pass",
      "tests": 2,
      "passed": 2,
      "failed": 0,
      "first_error": ""
    },
    {
      "file": "test/rooms_directs_controller_test",
      "status": "pass",
      "tests": 6,
      "passed": 6,
      "failed": 0,
      "first_error": ""
    },
    {
      "file": "test/rooms_involvements_controller_test",
      "status": "pass",
      "tests": 5,
      "passed": 5,
      "failed": 0,
      "first_error": ""
    },
    {
      "file": "test/rooms_refreshes_controller_test",
      "status": "pass",
      "tests": 1,
      "passed": 1,
      "failed": 0,
      "first_error": ""
    },
    {
      "file": "test/sessions_transfers_controller_test",
      "status": "pass",
      "tests": 2,
      "passed": 2,
      "failed": 0,
      "first_error": ""
    },
    {
      "file": "test/user_role_test",
      "status": "pass",
      "tests": 3,
      "passed": 3,
      "failed": 0,
      "first_error": ""
    },
    {
      "file": "test/users_controller_test",
      "status": "pass",
      "tests": 6,
      "passed": 6,
      "failed": 0,
      "first_error": ""
    },
    {
      "file": "test/welcome_controller_test",
      "status": "pass",
      "tests": 2,
      "passed": 2,
      "failed": 0,
      "first_error": ""
    }
  ]
}