Repository navigation
Conversation
apiology
marked this pull request as draft
August 2, 2026 15:51
apiology
commented
Aug 2, 2026
This was referenced Aug 2, 2026
apiology
marked this pull request as ready for review
August 3, 2026 00:07
Contributor
Author
|
@castwide - ready for review |
apiology
added a commit
to apiology/solargraph
that referenced
this pull request
Aug 12, 2026
Re-enables `solargraph typecheck --level strong` as an enforced CI gate - removes `continue-on-error: true` from .github/workflows/typecheck.yml. Most of the diff is @sg-ignore comments documenting type gaps strong mode can't resolve on its own (flow-sensitive-typing limits, the nil-vs-NilClass representation mismatch, guard-then-fetch patterns that don't narrow, RBS overload/ type-alias gaps). A handful of real fixes are included (missing/wrong @return/@PARAM tags). This branch's own lib/ tree has diverged substantially from castwide#1240's target (39+ merged PRs' worth of independent work), so merging this required a full annotation sweep on top of the mechanical merge to actually make the newly-hard CI gate pass - see below. Conflicts (20 files) fell into two categories: 1. Genuine competing logic, where incoming's branch (based directly on castwide/master) predated work already merged into this branch. Kept this branch's side throughout: doc_map.rb's entire in-memory pin-cache architecture (superseded by the PinCache instance-based rewrite from castwide#1252, same pattern already identified during the castwide#1239 investigation earlier this session), rbs_translator.rb's compound-type-as-ComplexType-graph architecture (from castwide#1281, predates incoming's tag-string type_to_tag reintroduction), flow-sensitive-typing/node_chainer additions (rhs_never_returns tracking from castwide#1259), base_variable.rb's definite/narrowed_return_type naming (from castwide#1282), node_methods.rb's ENSURE handling (from castwide#1285), chain.rb/call.rb's receiver_path threading, and workspace.rb/pin_cache.rb duplicate method definitions incoming reintroduced that already exist elsewhere in this branch's own `class << self` blocks. 2. Pure annotation differences (add/adjust an @sg-ignore comment) where kept whichever side matched this branch's actual code structure. 2. Annotation sweep: after resolving conflicts, this branch's strong typecheck still reported 289 problems (down from 547 pre-merge, since castwide#1240's own annotations covered about half). 194 were "Unneeded @sg-ignore comment" (incoming's own ignore comments, correct on castwide#1240's target tree, landing on lines this branch's independent fixes already resolve) - removed mechanically by scanning upward from each flagged line for its comment. The remaining 95 were genuine new gaps on this branch's own code paths (mostly not exercised by castwide#1240's target tree at all) - added one @sg-ignore per flagged line, matching the established message-as-comment convention used throughout this codebase (@sg-ignore matches by string presence, not exact message, so one comment per line suffices even where a line has multiple flagged sub-expressions). Spot-checked the ones that looked most like real bugs rather than static-analysis gaps (BigDecimal-typed values in Integer-declared contexts, an Array#push type mismatch) against already-documented, already-tracked false-positive patterns in this codebase (the known BigDecimal-contamination artifact from earlier PR work, and a known is_a?-narrowing gap) - none were new bugs. Also fixed one new Style/Next rubocop offense the sweep introduced. Verified: full local `bundle exec rspec` (1826 examples, 0 failures, 51 pending - the only local-environment-dependent example, 'ignores undefined method calls from external sources', a pre-existing order-dependent kramdown-parser-gfm gem-cache flake already confirmed unrelated to this session's work, passed in this run), `solargraph typecheck --level strong` (0 problems, confirming the now-hard-gated CI job will pass), and `rubocop lib/` (13 offenses, matching this branch's pre-existing baseline exactly - none newly introduced by this merge).
apiology
added a commit
to apiology/solargraph
that referenced
this pull request
Aug 12, 2026
#49 CI (commit c53789b) failed two checks after castwide#1240 turned Solargraph/strong from advisory into a hard gate: - Solargraph/strong: this job runs Ruby 4.0 with the `vernier` gem installed (appended to .Gemfile in the workflow itself) and a freshly-installed RBS collection, none of which match this session's local verification environment (Ruby 3.2.6, no vernier). Three `# @sg-ignore Unresolved constant Vernier` comments in shell.rb and one `# @sg-ignore Declared return type ::Integer does not match inferred type ::BigDecimal` in source_chainer.rb (the known BigDecimal-contamination artifact from earlier PR work) were "Unneeded" there since Vernier resolves and the BigDecimal gap doesn't reproduce on Ruby 4.0 - removed. A new gap CI's fresh RBS install surfaces that this session's local environment didn't - `Unresolved constant Gem::StubSpecification` in workspace/gemspecs.rb - added. Since this job runs a single fixed Ruby/RBS combination (not a matrix) and is now the actual enforced gate, resolved these in favor of matching CI's environment exactly rather than this session's local one - local `solargraph typecheck --level strong` now shows the mirror-image gaps (Vernier unresolved x3, BigDecimal x1, since local lacks vernier and has the BigDecimal artifact), which is expected and matches this project's established pattern for environment-dependent typecheck gaps. - rubocop (reviewdog, filter_mode: added): flags any rubocop offense falling within the diff's changed hunks, not just genuinely new ones. Removing the 3 Vernier ignore-comment lines from inside Shell#profile touched that method's hunk, pulling its pre-existing (already at 110.1/110 before this session touched it) Metrics/AbcSize offense into scope. Added lib/solargraph/shell.rb to .rubocop_todo.yml's existing Metrics/AbcSize exclusion list, matching the pattern already used for api_map/source_to_yard.rb/node_chainer.rb/source_chainer.rb/clip.rb/ mapper.rb. Verified: spec/shell_spec.rb, spec/source/source_chainer_spec.rb, spec/workspace/gemspecs_resolve_require_spec.rb, spec/workspace/gemspecs_fetch_dependencies_spec.rb (87 examples, 0 failures), and `rubocop lib/solargraph/shell.rb` (0 offenses, previously 1).
apiology
added a commit
to apiology/solargraph
that referenced
this pull request
Aug 12, 2026
… stub A class defined in a gem and re-opened elsewhere via @!parse to add @Generic tags produced two pins for the same namespace/method path. ApiMap picked whichever pin loaded first - a gem's own pins load before workspace pins, so the annotation's @Generic declaration and overridden return types were silently ignored regardless of file naming/order. - ApiMap#namespace_pin_for_generics prefers the pin that actually declares generics over an arbitrary .first, used at the three call sites that resolve generic type parameters (get_methods, inner_get_methods, inner_get_methods_from_reference). - ApiMap::Store#get_methods combines same-path method pins into one, so a @!parse override's return type isn't shadowed by the plain, undocumented definition. Aliases are excluded from this combination: combining a MethodAlias pin with a non-alias pin at the same path produced a :combined pin that #resolve_method_alias couldn't trace back to its target, raising under SOLARGRAPH_ASSERTS=on. Fixes castwide#1286 Conflict in spec/source_map/clip_spec.rb: both sides independently added a new spec adjacent to the same insertion point - no real overlap, kept both. Verified: spec/source_map/clip_spec.rb, spec/api_map/store_spec.rb, spec/api_map_spec.rb, spec/api_map_method_spec.rb (284 examples, 0 failures, 11 pending), SOLARGRAPH_ASSERTS=on solargraph typecheck --level strong (4 problems, all in lib/solargraph/shell.rb and lib/solargraph/workspace/gemspecs.rb - the same Vernier-gem/ Gem::StubSpecification local-vs-CI environment split already established during the castwide#1240 merge, not new here), and a broader safety net - spec/type_checker, spec/source, spec/pin (612 examples, 0 failures, 18 pending).
apiology
added a commit
to apiology/solargraph
that referenced
this pull request
Aug 12, 2026
…wide#1281 fix #49 CI (commit a6942fc, merge of latest castwide#1281 - resolve type alias names against RBS core) failed Solargraph/strong: 9 "Unneeded @sg-ignore comment" problems, all wrapping FileUtils.rm_rf/rm_f/mkdir_p calls in Rakefile, lib/solargraph/pin_cache.rb, and lib/solargraph/shell.rb. Each ignore was covering "Wrong argument type for FileUtils.*: list expected FileUtils::path, ..., received String" - exactly the FileUtils::path alias-resolution gap the just-merged fix closes, so on CI's Ruby 4.0 + fresh RBS collection environment these calls now typecheck cleanly without the ignore. Confirmed genuinely environment-dependent, not a stale local cache: cleared ~/.cache/solargraph/ruby-3.2.6/rbs-4.1.2/solargraph-* and reran - 4 of the 9 removed comments (3 in pin_cache.rb, 1 in shell.rb) are still needed on this local environment (Ruby 3.2.6, RBS 4.1.2). Matches the same Ruby/RBS-version-dependent FileUtils::path resolution pattern already established for the Vernier-gem and Gem::StubSpecification gaps during the castwide#1240 merge - kept the removal as-is to match CI (the actual enforced gate) rather than restoring for local parity. Verified: spec/pin_cache_spec.rb, spec/shell_spec.rb (44 examples, 0 failures), and `rubocop lib/solargraph/pin_cache.rb lib/solargraph/shell.rb Rakefile` (0 offenses).
apiology
added a commit
to apiology/solargraph
that referenced
this pull request
Aug 19, 2026
apiology
added a commit
to apiology/solargraph
that referenced
this pull request
Aug 26, 2026
# Conflicts: # lib/solargraph/workspace/gemspecs.rb
apiology
force-pushed
the
consolidate-type-annotation-cleanup
branch
from
September 16, 2026 23:56
ed70026 to
44c0203
Compare
This branch carries annotations and the CI flags; code changes belong on extract-1240-code-changes, so the [] fallback in Repo#build_from_directory goes back as it was and Repo#bundled? is marked with the PR that fixes it. Strong typecheck stays at 9 problems, all of them Metagem#initialize's keywords.
The plugin-workflow typecheck jobs (Ruby 3.4/4.0, newer rbs, vernier installed via .Gemfile) reported 7 problems the local 3.2.6/rbs 4.1.3 run cannot see, and the rubocop job flagged 2 offenses in added lines. - Drop the three shell.rb vernier @sg-ignore markers and the metagem.rb kwargs marker: every CI typecheck environment installs vernier and resolves the call, so the markers fail the unneeded- ignore check there. Removing the metagem.rb marker exposes a local-only "version expected String, received String, Gem::Version" finding; the Metagem version type decision is still open. - Guard the nilable Array#last before JSON.parse in repo.rb and require_paths.rb. - rubocop_helpers.rb: use version.to_s so the call resolves whether the receiver is typed Gem::Version or String across environments, and switch to backslash continuation (Style/LineEndConcatenation). - Extract Shell#profile_test_file to bring Shell#profile back under the Metrics/AbcSize limit (110.1 -> under 110). - Merge the duplicate, misnamed @PARAM tags on Shell#cache.
…pe-annotation-cleanup # Conflicts: # lib/solargraph/type_checker/rules.rb
`solargraph typecheck --level strong` reports all four as "Unneeded @sg-ignore comment". All four were removed in one edit and the typecheck re-run: the problem count fell from 12 to 8 with no new problem at any of the four sites, so none of them was suppressing anything. The three in the Rakefile covered `command_name`, `coverage_dir` and `formatter` inside a `SimpleCov.collate` block. They resolve once the RBS collection is installed, which CI does via `rbs collection install` in every job that typechecks. A worktree without `rbs_collection.lock.yaml` still reports those three calls unresolved, which is why the markers looked load-bearing. The one in metagem.rb claimed a wrong-argument-type error for the `version:` keyword of `Metagem.new`. No such error is raised, with or without the RBS collection. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011YRhTKhBfJqqfV1eN9vbbb
castwide#1389 rewrote the `suggestions.each` call in Hover#process into `suggestions&.each`, changing the node from :send to :csend. NodeChainer#generate_links passes passed_block(n) for :send but omits it for :csend, so the block is dropped and the block parameter `pin` is left with no type. Every call on it is then unresolved: link_documentation and text_documentation on the first line, detail and is_a? on the second, documentation on the third -- eight problems in all. That gap has its own fix in #139, so each marker is that URL. No rules.rb slug applies; dropping a block on :csend is not one of the catalogued limitations. Three markers is the minimum. A marker covers only the line directly below it, and the eight unresolved calls occupy exactly three lines.
castwide#1391 rewrites node.children[N] to fetch/drop at 61 of the 67 sites carrying the "node.children[] relies on grammar-guaranteed arity" marker. Per repo convention, a marker whose fix has a PR names only that PR's URL. The 6 remaining markers sit on code castwide#1391 leaves unchanged: flow_sensitive_typing.rb (4), class_methods.rb (1), send_node.rb process_attribute (1). Marker text only; no code lines change. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YAm8uhPDwH4Vst3uzZtHU6
The generic label misstated the cause at most sites. Sites that castwide#1392 rewrites to fetch(0)/fetch(-1), leaving nothing to suppress, now cite that PR. Sites where castwide#1392 still leaves a nil error at the same line, or where no non-empty invariant holds, now read "Need to add nil check here". Seven markers whose correct catalog string is undecided keep the old label. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YAm8uhPDwH4Vst3uzZtHU6
The comment lines master added to rbs_translator.rb plus the type list from this branch bring RbsTranslator to 143 lines, over the 141 this branch set (master allows 195). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LTpguFhKz2V87XqntgzKGe
Typecheck collapses the Integer#+ overloads into a BigDecimal parameter on these two lines; castwide#1356 fixes it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LTpguFhKz2V87XqntgzKGe
CI's strong typecheck reports both markers as unneeded: the BigDecimal problem they hid appears only in a local Ruby 4.0.6 environment.
Castwide PR 1223 closed unmerged. On the integration branch its sg-ignores were each traced to the open PR verified to clear them. Relabel the sg-ignores covering the same code here to match: 1461, 1463, 1338, 1415, 1417, 1458 and apiology 175, plus the existing Array#[] and Array#first/#last labels for three sites. Remove the constants.rb sg-ignore on the complex_resolve call, which typecheck reports as unneeded; removing it adds no problem. Update the label counts in rules.rb. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This was referenced Oct 28, 2026
apiology/solargraph PR 386 stops typing block calls as the blockless overload Enumerator, which clears the Unresolved call to zero? on the find_index/with_index chain. Point the sg-ignore at that PR. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Literal#value only ever holds an Integer or Symbol from int and sym nodes, true, false, or nil; it never holds a String. explicit_return_values_from_compound_statement receives nil for an empty block body and already returns [] for non-nodes, so its parent param allows nil. Flow-sensitive typing does not narrow parent past the unless is_a? guard, so parent.children and nodes.each need new sg-ignores. With nodes untyped, nothing inside the loop is checked, which makes the four castwide/solargraph 1418/1416 sg-ignores in the loop unneeded; those findings return once unless is_a? narrows. The ensure_body call site keeps its if is_a? sg-ignore on this branch: the argument is still typed wider than Parser::AST::Node, nil there. (cherry picked from commit 834fead)
The two sg-ignores on VisibilityDirective#no_empty_lines? are labelled "probably nil false alarm", and the @buffer_lines lookup in CommentRipper#on_comment is labelled "Use fetch to suppress false alarm"; none needs a nil check. The three sg-ignores on CommentRipper#on_embdoc_beg, #on_embdoc and #on_embdoc_end cite castwide#1364, which strong typecheck reports makes them unneeded, instead of castwide#1104. Parameter#param_tag drops the continuation line about narrow-pure-rbs-calls: castwide#1258 alone clears it. Update the label counts in rules.rb. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The three sg-ignores on Pin::Base#choose_pin_attr around [val1, val2].compact.max_by clear only with both #385 (array literal element types) and castwide#1458 (compact removes nil), so each cites both. The three $stdout.flush sg-ignores in the Rakefile cite castwide#1439, which clears them, instead of #229. Four sg-ignores cited castwide#1231, which none of its replacement PRs clears. The $LOAD_PATH calls in the gemspec and RubocopHelpers fail on the RBS intersection Array[String] & _LoadPathAPI; the block params in RbsCollection#best_key and Index#pins_by_class come from destructured yielded tuples. Each now carries the existing label for its mechanism. Update the label counts in rules.rb. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
SclassNode#process and SendNode#process had no @return tag, so they inherited Base#process's [Boolean, void] and needed sg-ignores (labelled castwide 1231, which never covered them). Declare @return [void] like the sibling processors instead. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Parser.parse returns nil for source with no expression, such as the "#c" and "." strings NodeChainer.load_string passes it, and NodeChainer then builds a valid empty chain because generate_links returns [] for anything that is not an AST node. Declare that nil in Parser.parse's @return and in the NodeChainer#initialize and #generate_links node params, replacing the sg-ignore that hid it. The wider param makes every use of n after the is_a? guard in generate_links, and of @node after is_ast_node? in #chain, look possibly nil. castwide#1418 makes Solargraph narrow those guards, so each new sg-ignore cites it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Strong typecheck on an integration branch that includes castwide#1461 reports these three sg-ignores Unneeded, so cite the PR that clears them instead of the generic labels. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The @@logger read in Solargraph::Logging's module body is unresolved because Chain::ClassVariable looks class variables up in the namespace pin's own context. #201 resolves them with full_context; overlaying it clears this site at strong (verified). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Overlaying castwide#1245 (runtime shape checks on the parsed rbs_collection lockfile and Page#render) on this branch makes eight "Library method has no usable type" sg-ignores in rbs_collection.rb and page.rb Unneeded at strong (verified). Strong CI on an integration branch with castwide#1266 reports the two "Need better generic inference here" sg-ignores in conversions.rb Unneeded. Cite those PRs instead. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
apiology
marked this pull request as ready for review
October 29, 2026 01:18
The castwide master merge (plugin architecture and related PRs) brought 58 strong-level problems into the plugin, rspec and rails checks. Add the missing @param/@return tags in Plugin, Plugin::Panel, Plugin::ActiveSupport, Plugin::Base#panel, External, SourceMap and Source::NodeMap. Correct three wrong tags: SourceMap#pin_class_hash keys are Class<Pin::Base>, NodeMethods.convert_hash returns Source::Chain values (bare Chain is unresolvable there), and NodeMap#initialize and ActiveSupport#method_pins accept what callers pass (nil node; Symbol names). Type method_names with @type. New sg-ignores per label: 3 Need a downcast here 1 Need to add nil check here 1 Array#first/#last relies on non-empty invariant 1 Range.from_node result assumed always present 1 Yielded tuples are not destructured into block params 1 Need better generic inference here 1 castwide#1259 1 Unresolved call to name 1 ...ActiveSupport#classmethod_pins return type could not be inferred 1 ...ActiveSupport#attribute_pins return type could not be inferred The last three come from def_delegators to @panel resolving to undefined; no open PR covers it. Cite castwide#1466 instead of #201 in logging.rb; it is the same fix upstream. Update the label counts in rules.rb. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LTpguHqALFufF4QdNagq1C
apiology
marked this pull request as draft
October 29, 2026 15:00
sg-ignore labels cite an open castwide/solargraph PR or name the defect, never an apiology PR. None of #112, #175, #178, #190, #193, #198, #385 or #386 has a castwide counterpart, so the 14 sg-ignores citing them now name the defect, reusing the existing Array#first/#last, MatchData, Array literal and Hash#[] labels where they fit. Update the label counts in rules.rb. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LTpguHqALFufF4QdNagq1C
This reverts commit 606ced8.
apiology
marked this pull request as ready for review
October 29, 2026 15:37
Each label now names the PR whose overlay makes the sg-ignore Unneeded: #108 for the five backtrace joins, castwide#1461 for callable.rb and castwide#1467 for constants.rb (with castwide#1415). index.rb keeps its text label: it needs castwide#1326, castwide#1461 and #60 together. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LTpguHqALFufF4QdNagq1C
Merging castwide#1463 makes this sg-ignore Unneeded. Its text label had no row in rules.rb, so the counts are unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LTpguHqALFufF4QdNagq1C
The 2026-10-19 merge of castwide#1461 removed both as Unneeded. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LTpguHqALFufF4QdNagq1C
Master moved lib/solargraph/convention/struct_definition.rb to lib/solargraph/parser/parser_gem/node_processors/. Point the Metrics/MethodLength exclusion at the new path so the moved #process method stays excluded as it was before the move. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LTpguFfufaaEmy3yWcWsUi
apiology
added a commit
to apiology/solargraph
that referenced
this pull request
Oct 30, 2026
Revert 9f4efb3, which guards Repo and RequirePaths against blank subprocess output. It has nothing to do with Class.new block receivers; the same commit lives in castwide#1288. The restored JSON.parse lines carry the same sg-ignore markers as castwide#1240, citing castwide#1245, for the typecheck problem master already has there. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LTpguFfufaaEmy3yWcWsUi
Each PR, applied to this branch, makes its sg-ignores unneeded. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LTpguHqALFufF4QdNagq1C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR was written by Claude Code on behalf of @apiology.
Problem
CI passes even when strong typechecking finds problems:
Type errors in Solargraph's own code merge unnoticed.
Solution
Re-enables
solargraph typecheck --level strongas an enforced CI gate in all four places it runs, and marks each remaining problem with an@sg-ignorecomment naming its cause, with no changes to Ruby code.Depends on
With asserts on, the check still crashes inside Solargraph. These PRs fix those crashes and must merge first:
class << self@!attributedirective pins (after [regression fix] Stop closure asserts on methods in class << self and Struct.new blocks #1433)module_functionmethodsNil-safety fixes are deferred to #1245; markers citing it name the deferred fix.