Skip to content

Solargraph strong: typecheck test files in batches - #462

Open
apiology wants to merge 25 commits into
mainfrom
cursor/6c0a00d9
Open

Solargraph strong: typecheck test files in batches#462
apiology wants to merge 25 commits into
mainfrom
cursor/6c0a00d9

Conversation

@apiology

@apiology apiology commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

  • Bring essentially all unit tests into Solargraph strong typecheck (only test/unit/test_helper.rb remains excluded).
  • Replace blanket test/**/* exclude with a single helper exclude.
  • Add Mocha/let_mock/MyOpenStruct stubs in config/annotations_misc.rb.
  • Minimize @sg-ignore usage (904 → 286, -68%) using Solargraph 0.60's YARD @!macro support for DSL methods (let_mock/let_single_mock/Forwardable#def_delegators), plus an attr_reader :mocks fix for the @mocks ivar-across-inheritance gap macros can't cover. Remaining ignores are legitimate Mocha-mock-vs-concrete-class type mismatches or narrow, pre-existing Solargraph inference limits.

Test plan

  • direnv exec . make solargraph-strong — 0 problems
  • RuboCop clean on touched test paths
  • CI build + quality green

Test Test added 2 commits July 12, 2026 21:09
Add Mocha/test-helper annotations and replace the blanket test exclude with a per-file list so cleared helpers and unit tests stay in the gate.
Expand the strong gate to CLI/view/workspaces helpers and internal timing/event-filter tests with YARD and targeted ignores.
@apiology apiology changed the title Solargraph strong: typecheck first 10 test files Solargraph strong: typecheck test files in batches Jul 13, 2026
Test Test and others added 4 commits July 12, 2026 21:41
Cover selectors, portfolios, tags, timelines, custom fields, and mv/view subcommand tests with YARD and targeted ignores.
Include projects/sections/tasks/selectors/timing tests; keep only test_helper.rb excluded from the strong gate.
…_delegators

Solargraph 0.60 added YARD @!macro support for DSL-style methods, which lets
a single macro declaration synthesize method pins at every call site instead
of annotating each one individually:

- let_mock/let_single_mock (test_helper.rb) now carry a macro so Solargraph
  resolves the dynamically-defined mock accessors it generates via
  define_method, up to the widest call in the suite (22 args).
- Forwardable#def_delegators gets the same treatment for the
  def_delegators(:@Mocks, ...) delegation pattern.
- @Mocks[...] access doesn't benefit from macros (it's an ivar-inheritance
  gap, not a missing-pin gap: added attr_reader :mocks to ClassTest and the
  four CLI test classes, and switched call sites to the accessor so the type
  resolves across subclasses.
- A handful of get_test_object overrides were added/corrected so the
  production object under test types accurately instead of generically.

Together these cut @sg-ignore comments in test/unit from 904 to 286 (-68%)
while keeping Caching YARD and RBS collection pins for gem activesupport:8.1.3
Caching YARD and RBS collection pins for gem bundler:4.0.16
Caching YARD and RBS collection pins for gem cache_method:0.2.7
Caching YARD and RBS collection pins for gem cgi:0.5.2
Caching YARD and RBS collection pins for gem concurrent-ruby:1.3.8
Caching YARD and RBS collection pins for gem erb:6.0.6
Caching YARD and RBS collection pins for gem json:2.21.1
Caching YARD and RBS collection pins for gem mime-types-data:3.2026.0701
Caching YARD and RBS collection pins for gem minitest:6.0.6
Caching YARD and RBS collection pins for gem pp:0.6.4
Caching YARD and RBS collection pins for gem sorbet-runtime:0.6.13341
Caching YARD and RBS collection pins for gem uri:1.1.1
/Users/broz/.cursor/worktrees/checkoff/0tb5/config/annotations_asana.rb:33: Unresolved return type Asana::HttpClient::Response for Asana::Client#get
/Users/broz/.cursor/worktrees/checkoff/0tb5/config/annotations_asana.rb:237: Unresolved return type Asana::Resources::UserTaskList for Asana::ProxiedResourceClasses::UserTaskList#get_user_task_list_for_user
/Users/broz/.cursor/worktrees/checkoff/0tb5/config/annotations_asana.rb:273: Unresolved return type Asana::Resources::User for Asana::ProxiedResourceClasses::User#me
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/attachments.rb:63: Unresolved return type Asana::Resources::Attachment for Checkoff::Attachments#create_attachment_from_url!
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/attachments.rb:128: Unresolved return type Asana::Resources::Attachment for Checkoff::Attachments#create_attachment_from_downloaded_url!
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/attachments.rb:149: Unresolved return type Asana::Resources::Attachment for Checkoff::Attachments#create_attachment_from_url_alone!
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/attachments.rb:158: Too many arguments to BasicObject.new
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/attachments.rb:158: Unresolved call to post on Asana::Client
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/attachments.rb:173: Unresolved type Asana::HttpClient::Response for response param on Checkoff::Attachments#parse
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/attachments.rb:174: Unresolved call to body
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/attachments.rb:177: Unresolved call to body
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/cli.rb:113: Unresolved call to add_project on Asana::Resources::Task
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/custom_fields.rb:57: Unresolved return type Asana::Resources::CustomField, nil for Checkoff::CustomFields#custom_field
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/custom_fields.rb:60: Unresolved call to name
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/custom_fields.rb:76: Unresolved call to custom_fields on Asana::Resources::Project, Asana::Resources::Task
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/custom_fields.rb:76: Unresolved call to gid on Asana::Resources::Project, Asana::Resources::Task
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/custom_fields.rb:101: Variable type could not be inferred for custom_fields
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/custom_fields.rb:101: Unresolved call to custom_fields on Asana::Resources::Task, Asana::Resources::Project
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/custom_fields.rb:118: Unresolved call to gid on Asana::Resources::Task, Asana::Resources::Project
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/custom_fields.rb:118: Unresolved call to custom_fields on Asana::Resources::Task, Asana::Resources::Project
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/custom_fields.rb:129: Unresolved call to custom_fields on Asana::Resources::Project, Asana::Resources::Task
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/custom_fields.rb:129: Variable type could not be inferred for custom_fields
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/custom_fields.rb:138: Unresolved call to gid on Asana::Resources::Project, Asana::Resources::Task
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/asana_event_enrichment.rb:148: Declared type String does not match inferred type String, generic<X> for variable resource_type
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/asana_event_enrichment.rb:150: Declared type String does not match inferred type String, generic<X> for variable gid
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/asana_event_enrichment.rb:164: Declared type String does not match inferred type String, generic<X> for variable resource_type
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/asana_event_enrichment.rb:167: Declared type String does not match inferred type String, generic<X> for variable gid
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/asana_event_filter.rb:103: Unresolved call to parent
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/asana_event_filter.rb:109: Unresolved call to completed_at
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/asana_event_filter.rb:110: Unresolved call to ==
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/asana_event_filter.rb:125: Declared type String does not match inferred type String, generic<X> for variable resource_type
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/asana_event_filter.rb:134: Wrong argument type for Asana::ProxiedResourceClasses::Task#find_by_id: id expected String, received String, generic<X>
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/project_hashes.rb:18: Unresolved call to to_h on Asana::Resources::Project
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/project_timing.rb:26: Unresolved call to start_on on Asana::Resources::Project
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/project_timing.rb:26: Unresolved call to start_on on Asana::Resources::Project
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/project_timing.rb:35: Unresolved call to due_on on Asana::Resources::Project
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/project_timing.rb:35: Unresolved call to due_on on Asana::Resources::Project
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/search_url/custom_field_param_converter.rb:67: Unresolved call to length
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/search_url/custom_field_variant.rb:40: Declared type Array<String> does not match inferred type Array<String>, generic<X> for variable param_values
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/search_url/date_param_converter.rb:139: Unresolved call to length
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/search_url/date_param_converter.rb:141: Unresolved call to []
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/search_url/date_param_converter.rb:157: Unresolved call to ==
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/search_url/simple_param_converter.rb:272: Declared type Class<Checkoff::Internal::SearchUrl::SimpleParam::SimpleParam> does not match inferred type Class<Checkoff::Internal::SearchUrl::SimpleParam::SimpleParam>, generic<X> for variable clazz
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/selector_classes/common.rb:244: Unneeded @sg-ignore comment
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/selector_classes/project.rb:21: Unneeded @sg-ignore comment
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/selector_classes/project.rb:61: Unresolved call to workspace on Asana::Resources::Project
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/selector_classes/section.rb:23: Unresolved call to gid on Asana::Resources::Section
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/selector_classes/task.rb:27: Declared type Hash{String => Hash} does not match inferred type Hash, generic<X> for variable unwrapped
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/selector_classes/task.rb:29: Variable type could not be inferred for projects
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/selector_classes/task.rb:137: Unresolved call to tags on Asana::Resources::Task
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/selector_classes/task.rb:237: Variable type could not be inferred for stories
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/selector_classes/task.rb:237: Unresolved call to stories on Asana::Resources::Task
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/selector_classes/task.rb:239: Unneeded @sg-ignore comment
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/selector_classes/task.rb:245: Unneeded @sg-ignore comment
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/selector_classes/task.rb:264: Unresolved call to start_on on Asana::Resources::Task
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/selector_classes/task.rb:264: Unresolved call to start_on on Asana::Resources::Task
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/selector_classes/task.rb:366: Unneeded @sg-ignore comment
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/selector_evaluator.rb:63: Wrong argument type for Checkoff::SelectorClasses::FunctionEvaluator#evaluate: _task expected Asana::Resources::Task, received Asana::Resources::Resource
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/task_hashes.rb:13: Variable type could not be inferred for task_hash
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/task_hashes.rb:13: Unresolved call to to_h on Asana::Resources::Task
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/task_hashes.rb:29: Too many arguments to BasicObject.new
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/task_timing.rb:23: Unneeded @sg-ignore comment
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/task_timing.rb:30: Unneeded @sg-ignore comment
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/task_timing.rb:41: Unresolved call to start_on on Asana::Resources::Task
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/task_timing.rb:41: Unresolved call to start_on on Asana::Resources::Task
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/task_timing.rb:61: Unresolved call to modified_at on Asana::Resources::Task
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/internal/task_timing.rb:61: Unresolved call to modified_at on Asana::Resources::Task
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/my_tasks.rb:46: Unresolved call to gid on Asana::Resources::Project
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/portfolios.rb:67: Unresolved call to gid
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/portfolios.rb:69: Unresolved call to name on Asana::Resources::Portfolio
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/portfolios.rb:107: Unresolved call to gid on Asana::Resources::Portfolio
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/projects.rb:114: Unresolved call to gid on Asana::Resources::Project
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/projects.rb:149: Unresolved call to completed_at on Asana::Resources::Task
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/projects.rb:162: Unresolved call to gid on Asana::Resources::Project
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/projects.rb:265: Unresolved call to gid
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/sections.rb:65: Unresolved call to gid
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/sections.rb:134: Unresolved call to gid
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/sections.rb:187: Unresolved call to project on Asana::Resources::Section
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/sections.rb:193: Unresolved call to gid on Asana::Resources::Section
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/sections.rb:206: Too many arguments to BasicObject.new
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/sections.rb:239: Unresolved type Asana::HttpClient::Response for response param on Checkoff::Sections#parse
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/sections.rb:240: Unresolved call to body
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/sections.rb:243: Unresolved call to body
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/sections.rb:263: Unresolved call to gid on Asana::Resources::Project
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/sections.rb:299: Unneeded @sg-ignore comment
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/subtasks.rb:61: Unresolved call to gid on Asana::Resources::Task
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/tags.rb:56: Unresolved call to gid
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/tags.rb:68: Checkoff::Tags#tasks_by_tag_gid return type could not be inferred
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/tags.rb:72: Unresolved constant Asana::Resources::Collection
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/tags.rb:96: Unresolved return type Asana::Resources::Tag, nil for Checkoff::Tags#tag
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/tags.rb:99: Unresolved call to name
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/tags.rb:127: Unresolved type Asana::HttpClient::Response for response param on Checkoff::Tags#parse
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/tags.rb:128: Unresolved call to body
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/tags.rb:129: Unresolved call to body
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/task_searches.rb:31: Unresolved constant Asana::Resources::ResponseHelper
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/task_searches.rb:51: Variable type could not be inferred for asana_resources_collection_class
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/task_searches.rb:51: Unresolved constant Asana::Resources::Collection
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/task_searches.rb:125: Checkoff::TaskSearches#api_task_search_request return type could not be inferred
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/task_searches.rb:128: Unresolved call to new
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/task_searches.rb:175: Unresolved call to created_at
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/tasks.rb:151: Unresolved call to gid
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/tasks.rb:185: Unneeded @sg-ignore comment
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/tasks.rb:199: Unresolved call to gid on Asana::Resources::Task
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/tasks.rb:232: Unresolved call to completed_at
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/tasks.rb:302: Variable type could not be inferred for workspace_name
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/tasks.rb:302: Unresolved call to name on Asana::Resources::Workspace
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/tasks.rb:307: Unresolved call to gid on Asana::Resources::Project
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/tasks.rb:319: Unresolved call to name on Asana::Resources::Workspace
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/tasks.rb:319: Variable type could not be inferred for workspace_name
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/timelines.rb:57: Declared type Hash{String => String} does not match inferred type Hash{String => String}, generic<X> for variable section_data
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/timelines.rb:59: Wrong argument type for Checkoff::Sections#section_by_gid: gid expected String, received String, generic<X>
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/timelines.rb:70: Unresolved call to name on Asana::Resources::Workspace
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/timelines.rb:82: Declared type Hash{String => Object} does not match inferred type Object, generic<X> for variable project_data
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/timelines.rb:84: Wrong argument type for Array#include?: object expected BasicObject, received Object, generic<X>
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/timelines.rb:87: Declared type Hash{String => Object} does not match inferred type Object, generic<X> for variable section_data
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/timelines.rb:90: Wrong argument type for Checkoff::Timelines#last_milestone_in_section: section_gid expected String, received Object, generic<X>
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/timelines.rb:94: Unresolved call to gid
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/timelines.rb:108: Unresolved call to name on Asana::Resources::Workspace
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/timelines.rb:120: Declared type Hash{String => Object} does not match inferred type Object, generic<X> for variable project_data
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/timelines.rb:122: Wrong argument type for Array#include?: object expected BasicObject, received Object, generic<X>
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/timelines.rb:164: Unresolved call to gid
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/timelines.rb:171: Unresolved call to gid
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/workspaces.rb:41: Unresolved call to name on Asana::Resources::Workspace
/Users/broz/.cursor/worktrees/checkoff/0tb5/lib/checkoff/workspaces.rb:48: Unneeded @sg-ignore comment
/Users/broz/.cursor/worktrees/checkoff/0tb5/test/unit/test_subtasks.rb:193: Unresolved constant Asana::Resources::Collection
/Users/broz/.cursor/worktrees/checkoff/0tb5/test/unit/test_tags.rb:117: Unresolved constant Asana::Resources::Collection
/Users/broz/.cursor/worktrees/checkoff/0tb5/test/unit/test_task_searches.rb:196: Unresolved constant Asana::Resources::Collection
Typecheck finished in 18.0138850000003 seconds.
127 problems found in 32 of 125 files., RuboCop, and the full
unit suite green throughout.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcDLhXhKuZ5eCxz7RC1N7p
EOF
)
Converting @Mocks[...] ivar access to the mocks accessor (needed for
Solargraph to resolve its type across ClassTest subclasses) adds one
extra method call per site, pushing 4 already-excluded test methods in
test_task_selectors.rb slightly further over the AbcSize threshold.
Ratchets the tracked offense count from 26 to 30 to match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcDLhXhKuZ5eCxz7RC1N7p
Comment thread .rubocop_todo.yml Outdated
Comment thread test/unit/test_view_subcommand.rb
Comment thread test/unit/test_timing.rb
Comment thread test/unit/internal/test_project_hashes.rb Outdated
Comment thread test/unit/test_mv_subcommand.rb Outdated
Comment thread test/unit/test_mv_subcommand.rb Outdated
- test_task_selectors.rb: extract stub_custom_fields/stub_tasks helpers
  to dedupe 31 identical mock-setup call sites. Drops the file's AbcSize
  offenses from 12 to 0 (fully off the rubocop_todo.yml exclude list) and
  cuts its @sg-ignore count from 103 to 74, restoring the ratchet's
  tracked AbcSize count from 30 to 18 (better than the requested <=26).
- test_view_subcommand.rb: type create_object's clazz param as
  Class<Checkoff::ViewSubcommand>, resolving two generic sg-ignores in
  favor of one precise, still-genuine one.
- Confirmed the def_delegators YARD macro fully resolves "Unresolved
  call to <delegated method>" ignores; found and fixed three more stale
  instances it had already made redundant (test_timing.rb, test_sections.rb,
  test_tags.rb).
- test_project_hashes.rb, test_task_hashes.rb, test_events.rb,
  test_clients.rb: the reported "let_mock compatibility" issue was
  actually a missing @!parse override for get_test_object's return
  type (same pattern used throughout the suite already) - not a
  let_mock/macro limitation. Adding it resolved most ignores outright;
  remaining ones are precise, precedented Mocha-mock-vs-concrete-class
  ignores.
- test_mv_subcommand.rb: replaced blanket [Object] param/return/attr
  types with the types actually used at call sites (String, Symbol,
  Mocha::Mock unions), removing two generic sg-ignores in favor of one
  precise, still-genuine one.

Net: @sg-ignore count 286 -> 253 (-12%, -72% from the original 904).
solargraph typecheck --level strong: 0 problems. make rubocop-ratchet:
clean. 285/285 unit tests passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcDLhXhKuZ5eCxz7RC1N7p
Comment thread test/unit/test_timing.rb
timing = get_test_object

# @sg-ignore Unresolved call to in_period?
refute(timing.in_period?(nil, :saturday))

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we set a type for output of get_test_object here and elsewhere to resolve these sorts of things?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Posted by Claude, not Vince — acting on his behalf via his GitHub credentials.

Yes — that's exactly the @!parse override pattern from the thread above, now applied to every file. One file (test_view_subcommand.rb) achieves the same result more directly by overriding create_object itself with a real return type, rather than faking it via @!parse — left that as-is since it's arguably the better approach where a class already overrides create_object. Commit bcb6b2f.

Test Test and others added 3 commits July 29, 2026 23:10
…sks)

[Object] was used as a fast universal-safe default during the original
bulk strong-typecheck-enablement pass rather than a deliberate typing
choice - it satisfies Solargraph without describing what's actually
passed. Traced call sites and replaced with the real types (mostly
String/Symbol/Boolean/Mocha::Mock/Array<...> unions).

- test_sections.rb: added missing @!parse override for get_test_object
  (same root cause as the earlier test_project_hashes.rb/test_task_hashes.rb/
  test_events.rb/test_clients.rb fixes) which resolved most stale
  "Unresolved call to X" ignores outright; retyped all 34 [Object]
  params/returns; fixed two methods wrongly typed [void] despite
  returning Hash values.
- test_tasks.rb: found the same pattern - most of its "Unresolved call
  to X" ignores were stale despite already having @!parse (never
  cleaned up after it was added); retyped all 24 [Object] params;
  fixed default_fields/fields_including's incorrect [void] returns;
  added the real, missing Mocha::Expectation#at_least_once to the
  shared annotations_misc.rb stub (config/annotations_misc.rb) rather
  than working around its absence.

solargraph typecheck --level strong: 0 problems. make rubocop-ratchet
clean. Full suite: 285/285 tests passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcDLhXhKuZ5eCxz7RC1N7p
…ags)

Continuing the [Object] cleanup: traced call sites and replaced generic
types with what is actually passed.

- test_cli_view.rb: retyped all 18 [Object] params (mostly
  String/NilClass for due_on/due_at, String for task names, Mocha::Mock
  for task mocks); also collapsed a redundant [String, nil, NilClass]
  union to [String, NilClass].
- test_timelines.rb, test_tags.rb: both already had (or gained)
  @!parse overrides for get_test_object, which unmasked several stale
  "Unresolved call to X" ignores left over from before those overrides
  existed - removed those and retyped the real [Object] params
  underneath.

solargraph typecheck --level strong: 0 problems on all three files.
RuboCop clean. Full suite: 285/285 tests passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcDLhXhKuZ5eCxz7RC1N7p
Finishes the [Object] cleanup across the test suite. Traced remaining
call sites in test_custom_fields.rb, test_subtasks.rb, test_projects.rb,
test_attachments.rb, test_task_searches.rb, test_portfolios.rb, and
test_asana_event_filter.rb; replaced generic types with what is
actually passed (mostly String/Boolean/Array<Mocha::Mock>/Mocha::Mock).

test_custom_fields.rb and test_projects.rb needed the same treatment
as earlier files: added/confirmed a @!parse override for
get_test_object, which unmasked stale "Unresolved call to X" ignores
underneath.

A side effect of the earlier Mocha::Expectation#at_least_once fix
(config/annotations_misc.rb) also unmasked 3 stale ignores in
test_project_timing.rb - removed those.

class_test.rb's two remaining [Object] annotations are left as-is:
they're the base ClassTest#get_test_object/#create_object factory
methods, which are genuinely polymorphic (subclasses narrow the
return type per-file via @!parse) rather than a lazy default.

solargraph typecheck --level strong: 0 problems across all 125 files.
make rubocop-ratchet: clean, no todo drift. Full suite: 285/285 tests
passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcDLhXhKuZ5eCxz7RC1N7p
Test Test and others added 2 commits July 30, 2026 07:54
Every "@sg-ignore ... expected <RealClass>, received Mocha::Mock" is
the same root cause: a Mocha::Mock configured via
responds_like_instance_of(RealClass) duck-types correctly at runtime
but Solargraph can't verify it statically, and there's no type syntax
to express it precisely (see filed upstream bug: RBS intersection
types parse but are translated to union semantics, not intersection
semantics). Reference that issue on all 139 such ignores across the
suite so the reasoning is traceable and the ignores can be revisited
if/when upstream fixes it.

solargraph typecheck --level strong: 0 problems. make rubocop-ratchet
clean, no todo drift. 285/285 tests passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcDLhXhKuZ5eCxz7RC1N7p
Reviewer asked to apply the @!parse get_test_object pattern
throughout, not just the files it happened to be added to already.
Audited every ClassTest/BaseAsana subclass and added the override to
the 7 that were missing it: test_project_timing.rb, test_task_timing.rb,
test_attachments.rb, test_portfolios.rb, test_subtasks.rb,
test_task_searches.rb, test_workspaces.rb.

Same effect as before in each: resolved stale "Unresolved call to X"
ignores outright, revealing the real (precedented) Mocha-mock-vs-real-class
diagnostics underneath, each now tagged with the solargraph#1229
reference per the established convention.

(test_view_subcommand.rb was already covered via a real polymorphic
create_object override rather than the @!parse fakeout - confirmed
clean, no change needed.)

solargraph typecheck --level strong: 0 problems across all 125 files.
make rubocop-ratchet: clean, no todo drift. 285/285 tests passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcDLhXhKuZ5eCxz7RC1N7p
Comment thread test/unit/test_project_selectors.rb
Test Test and others added 8 commits July 30, 2026 13:09
Reviewer asked to explore a typed let_mock macro so Solargraph catches
type errors from mocked domain objects directly, and pointed at
solargraph PR 1231 (their own open PR giving RBS A & B real
intersection semantics, fixing the union-collapse bug behind
solargraph issue 1229). Pin the Gemfile at that branch and build on it.

- Gemfile: point solargraph at apiology/solargraph fix-1229-intersection-types
  branch instead of the released gem, matching the existing github/branch
  pin pattern already used for parlour/sord/yard in this same block.
- config/annotations_misc.rb: added a typed_mock macro
  (return type Mocha::Mock & $2) and a typed_let_mock macro with the
  same shape.
- test_helper.rb: typed_let_mock(mock_sym, type) - identical to
  typed_mock, but does not call responds_like_instance_of at runtime.
  Needed because Mocha responds_like_instance_of allocates the
  responder class via Class#allocate (bypassing initialize), and
  ruby-asana Asana::Resources::Resource respond_to_missing? assumes
  an initialized attributes hash - allocating an Asana::Resources::Task
  or Project and letting Mocha query respond_to? against it crashes
  with a NoMethodError from inside ruby-asana itself. typed_let_mock
  gets the static intersection type without touching that runtime path;
  typed_mock stays as-is for types safe to allocate (e.g. Hash, already
  used in test_sections.rb).
- Rolled out typed_let_mock to test_project_selectors.rb, test_sections.rb,
  test_task_selectors.rb, test_tasks.rb, test_timelines.rb wherever a
  let_mock symbol maps 1:1 to a real Asana resource class throughout
  the file - eliminates the sg-ignore/solargraph-1229 pattern entirely
  for those mocks (verified: passing the mock where the real class is
  expected now type-checks clean, and passing something of the wrong
  type still correctly fails).

solargraph typecheck --level strong: 0 problems across all 125 files.
make rubocop-ratchet: clean, no todo drift. Full suite: 285/285 tests
passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcDLhXhKuZ5eCxz7RC1N7p
Routine freshness update from make build-typecheck, unrelated to the
solargraph fork pin - ruby/gem_rbs_collection moved forward upstream.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcDLhXhKuZ5eCxz7RC1N7p
CI's build job re-runs make build-typecheck and fails if
rbs_collection.lock.yaml does not exactly match a fresh regeneration.
ruby/gem_rbs_collection, an upstream git-tracked dependency not
pinned to a tag, moved forward again between the prior commit and
CI's run - unrelated to the solargraph fork pin. Re-synced.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcDLhXhKuZ5eCxz7RC1N7p
Continues the typed_let_mock rollout: test_project_hashes.rb,
test_task_hashes.rb, test_project_timing.rb, test_task_timing.rb,
test_attachments.rb, test_projects.rb wherever a let_mock symbol maps
1:1 to a real Asana resource class (Project, Task, Resource).

Also converted the plain-String-typed mocks: workspace_name,
tag_name, custom_field_name, portfolio_name, portfolio_gid, url
across test_custom_fields.rb, test_tags.rb, test_portfolios.rb,
test_task_searches.rb, and test_workspaces.rb.

Several conversions revealed a second layer of masking: an sg-ignore
suppresses every diagnostic on its line, not just the one it names, so
converting one mock's type sometimes left the SAME ignore comment
still technically needed because a second, different mock on the same
line was still an untyped Mocha::Mock underneath (e.g. workspace_name
resolving cleanly but portfolio_name/tag_name/url on the same call
still masked). Stripped ignores and re-typechecked per file to find
these, converting the newly-revealed mocks too rather than leaving a
stale-looking but still-needed ignore in place.

sg-ignore count: 226 -> 85.

solargraph typecheck --level strong: 0 problems across all 125 files.
make rubocop-ratchet: clean, no todo drift. Full suite: 285/285 tests
passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcDLhXhKuZ5eCxz7RC1N7p
Continues the audit: type the highest-value def_delegators-based
constructor collaborators (client in test_project_selectors.rb and
test_tasks.rb, each with several call sites) by replacing their
Forwardable delegation with an explicit real accessor method carrying
a Mocha::Mock & RealClass return type, instead of leaving them as
plain untyped Mocha::Mock via the generic def_delegators macro.

def_delegators itself can't carry per-symbol type info through its
own call signature (it's Ruby's real Forwardable API), so this uses a
real method with a real (if trivial) body instead of another YARD
macro - the pattern only pays off where a symbol has enough call
sites to offset the two @sg-ignores each accessor needs (one for the
method's own declared-vs-inferred mismatch, one for the mocks.foo
call itself); skipped four single-occurrence files where it would be
a net wash.

Also found and fixed:
- A real, if latent, bug in test_project_selectors.rb: it used the
  risky typed_mock (which calls responds_like_instance_of, unsafe for
  ruby-asana's dynamic-attribute Resource classes) instead of
  typed_let_mock for an Asana::Resources::Project mock. It happened
  not to crash only because none of its 9 tests exercised an
  unstubbed method call on that mock - not provably safe. Switched to
  typed_let_mock.
- test_section_selectors.rb: section -> Asana::Resources::Section was
  a missed conversion; its four sg-ignores were entirely stale.
- test_timing.rb: two stale-looking "Unresolved call to in_period?"
  ignores were masking a real, narrow nil-vs-NilClass mismatch;
  replaced with the precise message.
- test_asana_event_filter.rb: an "Unresolved call to matches?" ignore
  was masking a genuine (if functionally harmless) type mismatch -
  the test passed an Array where the method expects a Hash, only
  working because @filters.nil? short-circuits before the argument
  is ever touched. Fixed the test to pass {} like its sibling test.

Also documented (not fixed - reported upstream instead): an
order-dependent bug in the intersection-types fork where a real
method definition placed after a typed_let_mock/typed_mock call in
the same class corrupts that macro's pin resolution. Worked around by
always declaring typed_let_mock/typed_mock calls before any real
method definitions in the same class.

sg-ignore count: 85 -> 80.

solargraph typecheck --level strong: 0 problems across all 125 files.
make rubocop-ratchet: clean, no todo drift. Full suite: 285/285 tests
passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcDLhXhKuZ5eCxz7RC1N7p
Continues the typed_let_mock rollout to base_asana.rb (the shared
BaseAsana fixture used by test_sections/test_tasks/test_projects/
test_workspaces) plus test_clients.rb, test_workspaces.rb,
test_view_subcommand.rb, test_mv_subcommand.rb, test_section_selectors.rb,
and test_task_selectors.rb, wherever a mock symbol maps 1:1 to a real
Asana resource class, Asana::Client, or plain String/Hash value confirmed
by its actual .expects()/argument usage in the file (not by name alone -
e.g. custom_field in test_task_selectors.rb is used like a Hash via
.fetch/.[], not an Asana::Resources::CustomField).

Left as plain let_mock: Asana API collection objects (workspaces, tasks,
sections as returned by client.workspaces/client.tasks) since they don't
map to a single Asana::Resources class, base_asana's :projects (means
Checkoff::Projects in some subclasses but a raw Asana collection in
test_projects.rb - not safe to type once for all inheritors), and several
symbols in base_asana.rb (my_tasks_in_workspace, my_time, b_gid, c_gid,
section_one, a_completed_at, b_completed_at) that are declared but never
referenced by any subclass.

Converting a_name/a_gid/project_a/task_a etc. in base_asana.rb turned
several sg-ignore comments in test_sections.rb and test_projects.rb into
unneeded ones (the underlying Mocha::Mock-vs-real-type mismatch they
suppressed is now resolved); stripped those and re-typechecked to confirm.

sg-ignore count (test/): 80 -> 66.
solargraph typecheck --level strong: 0 problems across all 125 files.
Full suite: 285/285 tests, 0 failures.
…ction mocks

Removes 7 let_mock symbols from base_asana.rb (my_tasks_in_workspace,
my_time, b_gid, c_gid, section_one, a_completed_at, b_completed_at, and
the inherited :tasks) confirmed dead: not referenced by name anywhere
outside their own declaration, or (for :tasks) always shadowed by a
same-named redeclaration in every subclass that touches it
(test_projects.rb, test_sections.rb) or only ever used as a local
variable, never as the inherited mock method (test_tasks.rb).

Renames base_asana's :projects mock to :asana_projects. It meant two
different things depending on the subclass: in test_sections.rb and
test_tasks.rb it was always shadowed by their own def projects (returning
a real Checkoff::Projects instance), while in test_projects.rb it was the
live inherited mock representing the raw Asana::Client#projects
collection proxy - the same identifier resolving to unrelated things
depending on call site (inside a projects = get_test_object block vs.
inside a helper method with no local var in scope). Updated
test_projects.rb's setup_projects_pulled/setup_projects_queried/
mock_project_my_tasks to reference asana_projects explicitly.

Types the API collection mocks (asana_projects, and the ones left plain
in the prior commit: test_workspaces.rb's workspaces,
test_section_selectors.rb's tasks) using the
Asana::ProxiedResourceClasses::{Project,Workspace,Task} stubs already
declared in config/annotations_asana.rb for
Asana::Client#projects/workspaces/tasks's real per-resource return shape
(find_by_workspace/find_by_id, find_all, get_tasks - all already covered,
no new stub methods needed there). That @!parse block is YARD-comment-only
and never defines the constants at runtime, so typed_let_mock (which
evaluates its type argument as real Ruby) would NameError; added minimal
real empty classes for Task/Workspace/Project/Section under
Asana::ProxiedResourceClasses in test_helper.rb for the @!parse
annotations to attach to.

solargraph typecheck --level strong: 0 problems across all 125 files.
RuboCop clean. Full suite: 285/285 tests, 0 failures.
…hments, subtasks

Continues the typed_let_mock rollout to test_events.rb, test_cli_quickadd.rb,
test_cli_view.rb, test_cli_help.rb, test_cli_mv.rb, test_custom_fields.rb,
test_attachments.rb, test_subtasks.rb.

Removes dead mock symbols found along the way (test_cli_quickadd.rb/
test_cli_view.rb/test_cli_help.rb's unused workspace/workspace_gid/
task_a/b/c, test_subtasks.rb's is_rendered_as_separator - only ever used
as a Mocha symbol argument or string literal, never as the bare mock).

Adds the remaining Asana::ProxiedResourceClasses backing classes (Tag,
UserTaskList, Portfolio, User, CustomField) to test_helper.rb alongside
the four from the prior commit, matching the full stub set already
declared in config/annotations_asana.rb, for use by later files in this
same conversion pass.

solargraph typecheck --level strong: 0 problems across all 125 files.
RuboCop clean. Full suite: 285/285 tests, 0 failures.
Continues the typed_let_mock rollout to test_tags.rb, test_task_searches.rb,
test_portfolios.rb, using the Asana::ProxiedResourceClasses::{Tag,Portfolio,
User} stubs added in the prior commit for the client.tags/portfolios/users
collection proxies, plus Asana::Resources::Collection and
Asana::HttpClient::Response (both real gem classes) for the raw-response
wrapping helpers.

Removes dead symbols found along the way: test_tags.rb's parsed_data
(never referenced past its declaration), test_task_searches.rb's
workspace_gid (every call site hardcodes the literal 'abc' instead) and
body (always shadowed by a local Hash literal of the same name before
use).

test_task_searches.rb's something_else is left as a plain let_mock - it's
only ever stored as an opaque hash/array value, never has a method called
on it, so there's no usage signal to type it from.

solargraph typecheck --level strong: 0 problems across all 125 files.
RuboCop clean. Full suite: 285/285 tests, 0 failures.
…oject_timing

Continues the typed_let_mock rollout to test_timelines.rb,
internal/test_asana_event_filter.rb, internal/test_project_timing.rb.

solargraph typecheck --level strong: 0 problems across all 125 files.
RuboCop clean. Full suite: 285/285 tests, 0 failures.
Types the remaining let_mock symbols in test_projects.rb, removing 7 dead
ones along the way (workspaces, workspace_workspace, some_other_workspace,
workspace_name, all_workspaces, n, my_tasks_config) that were never
referenced by name outside their own declaration - notably `workspaces`
here is genuinely unused because this file only ever sets up
mocks[:workspaces] (the fresh, separate mock get_test_object injects into
Checkoff::Projects.new's workspaces: kwarg), never the bare let_mock
method, since `workspaces` isn't in this file's def_delegators list.

field_name and period are typed as Symbol even though their real
signatures are a Symbol/Array union (Checkoff::Projects#in_period?,
#project_ready?) - Symbol is the member exercised by every call site here
and resolves the three sg-ignores this file had for Mocha::Mock-vs-real-type
mismatches on project_by_gid/in_period?/project_ready?, which are removed.

solargraph typecheck --level strong: 0 problems across all 125 files.
RuboCop clean. Full suite: 285/285 tests, 0 failures.
Types all remaining let_mock symbols in test_tasks.rb. Removes 6 dead
ones (mock_tasks, modified_mock_tasks, tasks_by_section,
unflattened_modified_mock_tasks, asana_entity_project, dependency_1)
never referenced outside their own declaration, and collapses two
duplicate declarations: :task_name was declared separately at both the
top of the file and again 300 lines down, and :task was declared both via
the file's own typed_let_mock at the top and redundantly again via plain
let_mock further down - the later plain redeclaration was silently
overwriting the earlier typed one back to an untyped Mocha::Mock.

Removes 4 sg-ignore comments (Wrong argument type ... workspace_name/
task_name expected String, Symbol, received Mocha::Mock) that typing
workspace_name/task_name as String made unneeded.

solargraph typecheck --level strong: 0 problems across all 125 files.
RuboCop clean. Full suite: 285/285 tests, 0 failures.
Types the remaining let_mock symbols in test_sections.rb, the last file
with untyped bulk let_mock declarations. Removes 7 dead symbols never
referenced outside their own declaration (project, inactive_task_b,
user_task_list_project, workspace_one, workspace_one_gid, user_task_lists,
user_task_list - the "my tasks in workspace" resolution mocks all live in
TestProjects instead, not here) plus two entirely-unused standalone
declarations (workspace_1_gid, subtasks).

`project` looked live at a glance (many methods reference a bare
`project` identifier) but every occurrence turned out to be a same-named
method parameter shadowing the top-level mock - no call site actually
invokes the let_mock version.

Removes 7 sg-ignore comments (Unresolved call to tasks_by_section_gid /
section_1 / previous_section / section_by_gid) that typing section_1_gid,
section_1/section_2, and get_results as String/Asana::Resources::Section/
Asana::HttpClient::Response made unneeded.

This closes out the let_mock -> typed_let_mock conversion started in
#462: every bulk let_mock call site across test/ is now
either typed_let_mock or reduced to single untyped symbols with no usage
signal to type from (test_task_searches.rb's something_else).

solargraph typecheck --level strong: 0 problems across all 125 files.
Full-repo RuboCop clean. Full suite: 285/285 tests, 0 failures.
sg-ignore count (test/): 80 -> 50 across this whole pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant