rigortype 0.4.3 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +5 -5
- data/data/core_overlay/ostruct.rbs +40 -0
- data/docs/handbook/11-sig-gen.md +104 -15
- data/docs/manual/02-cli-reference.md +43 -12
- data/docs/manual/03-configuration.md +20 -7
- data/docs/manual/04-diagnostics.md +56 -3
- data/docs/manual/05-inspecting-types.md +2 -2
- data/docs/manual/06-baseline.md +1 -1
- data/docs/manual/07-plugins.md +3 -2
- data/docs/manual/08-skills.md +7 -0
- data/docs/manual/10-mcp-server.md +40 -4
- data/docs/manual/18-removing-dead-code.md +23 -2
- data/docs/manual/plugins/rigor-rails-routes.md +2 -2
- data/docs/manual/plugins/rigor-rspec.md +101 -1
- data/docs/manual/plugins/rigor-shoulda-matchers.md +4 -1
- data/exe/rigor +12 -17
- data/lib/rigor/analysis/check_rules/clause_coverage.rb +134 -0
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +111 -7
- data/lib/rigor/analysis/check_rules/rbs_receiver_surface.rb +190 -0
- data/lib/rigor/analysis/check_rules/rule_ids.rb +60 -1
- data/lib/rigor/analysis/check_rules/source_arity.rb +32 -3
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +13 -4
- data/lib/rigor/analysis/check_rules.rb +274 -51
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +2 -1
- data/lib/rigor/analysis/incremental.rb +61 -0
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +36 -18
- data/lib/rigor/analysis/incremental_session.rb +270 -28
- data/lib/rigor/analysis/path_expansion.rb +3 -1
- data/lib/rigor/analysis/reachability/graph.rb +111 -14
- data/lib/rigor/analysis/reachability/scan.rb +305 -23
- data/lib/rigor/analysis/rule_catalog.rb +22 -4
- data/lib/rigor/analysis/run_cache_key.rb +31 -7
- data/lib/rigor/analysis/run_cache_probe.rb +5 -3
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +48 -12
- data/lib/rigor/analysis/runner/pool_coordinator.rb +179 -31
- data/lib/rigor/analysis/runner/project_pre_passes.rb +29 -4
- data/lib/rigor/analysis/runner.rb +102 -72
- data/lib/rigor/analysis/severity_stamp.rb +45 -1
- data/lib/rigor/analysis/worker_session.rb +69 -2
- data/lib/rigor/cache/descriptor.rb +79 -12
- data/lib/rigor/cache/engine_source.rb +3 -2
- data/lib/rigor/cache/incremental_snapshot.rb +39 -5
- data/lib/rigor/cache/rbs_descriptor.rb +2 -1
- data/lib/rigor/cache/store.rb +4 -3
- data/lib/rigor/cli/command.rb +3 -1
- data/lib/rigor/cli/docs_command.rb +3 -2
- data/lib/rigor/cli/doctor_command.rb +1 -1
- data/lib/rigor/cli/explain_command.rb +3 -2
- data/lib/rigor/cli/mcp_command.rb +1 -1
- data/lib/rigor/cli/plugin_command.rb +2 -1
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/sig_gen_command.rb +32 -11
- data/lib/rigor/cli/skill_command.rb +2 -1
- data/lib/rigor/cli/skill_describe.rb +3 -2
- data/lib/rigor/cli/unused_command.rb +10 -7
- data/lib/rigor/cli.rb +3 -2
- data/lib/rigor/config_audit.rb +163 -22
- data/lib/rigor/configuration/dependencies.rb +19 -11
- data/lib/rigor/configuration/severity_profile.rb +20 -2
- data/lib/rigor/configuration.rb +29 -3
- data/lib/rigor/effects/signature_sources.rb +3 -1
- data/lib/rigor/environment/bundle_sig_discovery.rb +3 -2
- data/lib/rigor/environment/gated_signature_guard.rb +2 -1
- data/lib/rigor/environment/gated_signature_plan.rb +2 -1
- data/lib/rigor/environment/installed_gem_set.rb +2 -1
- data/lib/rigor/environment/missing_gem_constant_index.rb +4 -3
- data/lib/rigor/environment/rbs_loader.rb +67 -11
- data/lib/rigor/inference/block_call_timing.rb +12 -1
- data/lib/rigor/inference/builtins/method_catalog.rb +2 -1
- data/lib/rigor/inference/captured_locals.rb +67 -13
- data/lib/rigor/inference/clause_widening.rb +90 -0
- data/lib/rigor/inference/definer_resolution.rb +101 -25
- data/lib/rigor/inference/expression_typer.rb +94 -9
- data/lib/rigor/inference/guard_rebinding.rb +7 -2
- data/lib/rigor/inference/intervening_ivar_reset.rb +303 -0
- data/lib/rigor/inference/last_line/self_evidence.rb +1 -1
- data/lib/rigor/inference/macro_block_self_type.rb +20 -6
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +170 -35
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +50 -2
- data/lib/rigor/inference/method_dispatcher.rb +67 -3
- data/lib/rigor/inference/module_function_state.rb +213 -51
- data/lib/rigor/inference/narrowing.rb +235 -75
- data/lib/rigor/inference/parameter_inference_collector.rb +4 -26
- data/lib/rigor/inference/project_patched_methods.rb +168 -4
- data/lib/rigor/inference/project_patched_mixins.rb +162 -0
- data/lib/rigor/inference/project_patched_scanner.rb +51 -12
- data/lib/rigor/inference/project_patched_visibility.rb +214 -0
- data/lib/rigor/inference/project_seed_tables.rb +120 -0
- data/lib/rigor/inference/refined_dispatch/constructed_class.rb +113 -0
- data/lib/rigor/inference/refined_dispatch/own_method.rb +41 -12
- data/lib/rigor/inference/reflective_ivar_write.rb +116 -0
- data/lib/rigor/inference/repeated_or_writes.rb +414 -1
- data/lib/rigor/inference/return_barrier.rb +16 -0
- data/lib/rigor/inference/scope_indexer.rb +1061 -122
- data/lib/rigor/inference/self_call_ivar_writes.rb +346 -0
- data/lib/rigor/inference/singleton_external_ahead.rb +64 -0
- data/lib/rigor/inference/singleton_hook_decline.rb +7 -0
- data/lib/rigor/inference/statement_evaluator.rb +512 -150
- data/lib/rigor/inference/unthreaded_rebinds.rb +3 -1
- data/lib/rigor/lens/anchor.rb +3 -3
- data/lib/rigor/lens/contract_reader.rb +60 -2
- data/lib/rigor/lens/document.rb +4 -3
- data/lib/rigor/lens/file_reader.rb +452 -73
- data/lib/rigor/lens/members.rb +81 -17
- data/lib/rigor/lens/run.rb +73 -4
- data/lib/rigor/lens.rb +2 -1
- data/lib/rigor/mcp/server.rb +63 -22
- data/lib/rigor/plugin/base.rb +3 -2
- data/lib/rigor/plugin/box_probe.rb +154 -7
- data/lib/rigor/plugin/io_boundary.rb +42 -6
- data/lib/rigor/plugin/isolation.rb +4 -3
- data/lib/rigor/project_environment.rb +6 -3
- data/lib/rigor/protection/discovery_seed.rb +9 -36
- data/lib/rigor/protection/mutation_cache.rb +8 -2
- data/lib/rigor/rooted_glob.rb +27 -0
- data/lib/rigor/scope/discovery_index.rb +5 -0
- data/lib/rigor/scope/resolution_chain/relevance.rb +14 -0
- data/lib/rigor/scope/resolution_chain.rb +40 -5
- data/lib/rigor/scope.rb +56 -8
- data/lib/rigor/sig_gen/alias_index.rb +2 -1
- data/lib/rigor/sig_gen/classification.rb +4 -1
- data/lib/rigor/sig_gen/generator.rb +167 -22
- data/lib/rigor/sig_gen/layout_index.rb +40 -1
- data/lib/rigor/sig_gen/method_candidate.rb +8 -0
- data/lib/rigor/sig_gen/observation_collector.rb +137 -11
- data/lib/rigor/sig_gen/path_mapper.rb +18 -2
- data/lib/rigor/sig_gen/renderer.rb +13 -155
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +11 -0
- data/lib/rigor/sig_gen/write_reporter.rb +203 -0
- data/lib/rigor/sig_gen/write_result.rb +3 -1
- data/lib/rigor/sig_gen/writer.rb +50 -35
- data/lib/rigor/signature_path_audit.rb +4 -2
- data/lib/rigor/type/constant.rb +10 -1
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +1 -1
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/render_locals.rb +6 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +1 -1
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_discoverer.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +4 -3
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +1 -1
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +1 -1
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +1 -1
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_discoverer.rb +1 -1
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +5 -1
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +1 -1
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +5 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +1 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/discoverer.rb +57 -6
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/target_detector.rb +1 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +1 -1
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +5 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +1 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +1 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +7 -2
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +5 -5
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +18 -17
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +155 -12
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +10 -8
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +1 -1
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +4 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +2 -2
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +2 -2
- data/sig/rigor/plugin/io_boundary.rbs +5 -2
- data/sig/rigor/rooted_glob.rbs +7 -0
- data/sig/rigor/scope.rbs +4 -3
- data/skills/rigor-doctor/references/01-checks.md +23 -11
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +2 -1
- metadata +16 -1
|
@@ -94,7 +94,17 @@ module Rigor
|
|
|
94
94
|
does_not_fire_when: [
|
|
95
95
|
"Implicit-self calls (no receiver) — too noisy without per-method RBS for every helper.",
|
|
96
96
|
"Receiver is `Dynamic[T]` / `Top` / `Union` — by definition the method set isn't enumerable.",
|
|
97
|
-
"Receiver class is in the loader but its RBS definition cannot be built (constant aliases)."
|
|
97
|
+
"Receiver class is in the loader but its RBS definition cannot be built (constant aliases).",
|
|
98
|
+
"Receiver class answers beyond any signature: a plugin-declared open receiver (ADR-26), or one " \
|
|
99
|
+
"Rigor's bundled overlays name (`OpenStruct`, whose fields are per-instance singleton methods; " \
|
|
100
|
+
"`ActiveSupport::Duration` and `ActiveSupport::Concern` when their gem overlay loads). Both sides " \
|
|
101
|
+
"of the class are open, and an inherited Object / Kernel signature no longer decides " \
|
|
102
|
+
"`call.wrong-arity` or `call.argument-type-mismatch` on it.",
|
|
103
|
+
"The program may answer the call another way (#1722): a `method_missing` on the receiver's class or an " \
|
|
104
|
+
"ancestor; a module mixed into either that defines the method (`Integer.include(Ext)` counts wherever " \
|
|
105
|
+
"it is written); singleton methods given to the receiver local (`s.extend(M)`, " \
|
|
106
|
+
"`define_singleton_method`, `class << s`); or, for a receiver typed by its class's name rather than a " \
|
|
107
|
+
"literal, a project subclass that defines the method."
|
|
98
108
|
],
|
|
99
109
|
suppression: "`# rigor:disable call.undefined-method` on the call line, " \
|
|
100
110
|
"or `disable: [\"call.undefined-method\"]` in `.rigor.yml`.",
|
|
@@ -556,14 +566,22 @@ module Rigor
|
|
|
556
566
|
summary: "Explicit-receiver call to a method declared `private` in source.",
|
|
557
567
|
fires_when: [
|
|
558
568
|
"Call is `receiver.method(...)` with explicit non-self receiver.",
|
|
559
|
-
"Receiver type resolves to `Type::Nominal[X]`.",
|
|
560
|
-
"X is a user-defined class whose source carries the method under `private
|
|
569
|
+
"Receiver type resolves to `Type::Nominal[X]`, or to the class object `singleton(X)`.",
|
|
570
|
+
"X is a user-defined class whose source carries the method under `private`; for a class object, " \
|
|
571
|
+
"the singleton method the call reaches is private (`private_class_method`, `class << self` with " \
|
|
572
|
+
"`private`, or a private method of a module X extends)."
|
|
561
573
|
],
|
|
562
574
|
does_not_fire_when: [
|
|
563
575
|
"Implicit-self call (no receiver) — always allowed for private.",
|
|
564
576
|
"Receiver is `self` (Ruby 2.7+ permits `self.private_method`).",
|
|
565
577
|
"Receiver class is RBS-known but not user-source-defined (RBS-side visibility is deferred).",
|
|
566
|
-
"Method is `:protected` (subclass tracking is deferred)."
|
|
578
|
+
"Method is `:protected` (subclass tracking is deferred).",
|
|
579
|
+
"A `method_missing` or `respond_to_missing?` on the receiver's chain, on the side the call reaches, " \
|
|
580
|
+
"may answer the call (Ruby sends a private call to `method_missing`).",
|
|
581
|
+
"The visibility rests on a statement that may not run, or on files that disagree about it.",
|
|
582
|
+
"On a class object: the receiver is not a constant (`self.class.x` may be a subclass that " \
|
|
583
|
+
"re-publicises the name), or the call is not inside a `def` (load-time code may run before the " \
|
|
584
|
+
"method is made private)."
|
|
567
585
|
],
|
|
568
586
|
suppression: "`# rigor:disable method-visibility-mismatch`.",
|
|
569
587
|
severity_authored: :error,
|
|
@@ -70,13 +70,14 @@ module Rigor
|
|
|
70
70
|
RUN_EFFECTS_TABLE_PRODUCER_ID = "analysis.run-effects-table"
|
|
71
71
|
|
|
72
72
|
# The run-result producer's declared compaction budget (`Cache::Store#evict!` pass 2). Whole-project,
|
|
73
|
-
# but unlike the `rbs.*` producers several generations can be live at once: the `paths`
|
|
74
|
-
# one entry per analyzed-path SET
|
|
75
|
-
# single file are three separate live generations
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
#
|
|
79
|
-
#
|
|
73
|
+
# but unlike the `rbs.*` producers several generations can be live at once: the `paths` and `roots` key
|
|
74
|
+
# slots mean one entry per analyzed-path SET x root list as written (#1559), so `rigor check` over the
|
|
75
|
+
# whole project, over `lib`, and over a single file are three separate live generations, and `rigor
|
|
76
|
+
# check` and `rigor check lib` are two even when `lib` is the configured `paths:`. 16 is a judgement call
|
|
77
|
+
# sized for that churn; it is a cap on GENERATIONS, not on correctness — over-evicting here costs a
|
|
78
|
+
# recompute, never a wrong answer. Measured 2026-07-25 against a real project's `.rigor/cache`: the cap
|
|
79
|
+
# does bind (60 distinct path-set generations observed, differing in the `paths` slot alone), with no
|
|
80
|
+
# evidence yet on how often an evicted generation is asked for again — see issue #151.
|
|
80
81
|
GENERATION_CAP = 16
|
|
81
82
|
|
|
82
83
|
# The effects sidecar's own compaction budget. One generation per (path set × effects identity), and
|
|
@@ -109,6 +110,29 @@ module Rigor
|
|
|
109
110
|
nil
|
|
110
111
|
end
|
|
111
112
|
|
|
113
|
+
# #1559 — the run-result key's analysis ROOTS, as the run was given them. The `paths` slot holds only the
|
|
114
|
+
# files the roots expand to, so `check lib extra` with `extra` missing and `check lib` shared a key while
|
|
115
|
+
# only the first prints `extra:1:1: warning: no such file or directory (skipped)`, which changes the exit
|
|
116
|
+
# code under `--fail-on=warning`. The roots are kept in the order and spelling written, not normalised: a
|
|
117
|
+
# missing root is reported as written (`./extra` is not `extra`), and the order of the roots is the order
|
|
118
|
+
# the diagnostics come out in, so two runs that differ only in either are two slots (a forgone hit, never a
|
|
119
|
+
# wrong one).
|
|
120
|
+
#
|
|
121
|
+
# Added to the DIAGNOSTICS key only. The ADR-103 effects sidecar derives its identity from {#descriptor}
|
|
122
|
+
# without it: the effect table is a function of the analysed files, and no path-error row reaches it.
|
|
123
|
+
# The `--incremental` slot builds its own, normalised, roots entry ({IncrementalRunSlot}).
|
|
124
|
+
#
|
|
125
|
+
# @param descriptor — a {#descriptor} result (nil passes through, so a disabled cache stays disabled).
|
|
126
|
+
def with_roots(descriptor, roots)
|
|
127
|
+
return nil if descriptor.nil?
|
|
128
|
+
|
|
129
|
+
entry = config_entry("roots", Marshal.dump(Array(roots).map(&:to_s)))
|
|
130
|
+
Cache::Descriptor.new(
|
|
131
|
+
gems: descriptor.gems, dependencies: descriptor.dependencies, plugins: descriptor.plugins,
|
|
132
|
+
configs: descriptor.configs + [entry]
|
|
133
|
+
)
|
|
134
|
+
end
|
|
135
|
+
|
|
112
136
|
# Issue #285 — the `engine` slot above pins the engine by VERSION, which identifies the source only
|
|
113
137
|
# for a released gem. A checkout (a contributor's, or a `bundle add rigor, github:` clone) gets one
|
|
114
138
|
# extra slot carrying a digest of the engine's own source, so editing `lib/rigor/inference/*.rb` no
|
|
@@ -65,9 +65,11 @@ module Rigor
|
|
|
65
65
|
# probe must never turn a servable run into a crash.
|
|
66
66
|
def serve(paths)
|
|
67
67
|
files = PathExpansion.ruby_files(paths, @configuration.exclude_patterns, base: @configuration.exclude_base)
|
|
68
|
-
key = RunCacheKey.
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
key = RunCacheKey.with_roots(
|
|
69
|
+
RunCacheKey.descriptor(
|
|
70
|
+
configuration: @configuration, files: files, explain: @explain,
|
|
71
|
+
rbs_config_entries: RunCacheKey.libraries_config_entries(@configuration)
|
|
72
|
+
), paths
|
|
71
73
|
)
|
|
72
74
|
return nil if key.nil?
|
|
73
75
|
|
|
@@ -57,7 +57,8 @@ module Rigor
|
|
|
57
57
|
quarantined_signatures_snapshot:, env_build_failure_snapshot:,
|
|
58
58
|
definition_build_failures_snapshot:, hkt_scan_failure_snapshot:,
|
|
59
59
|
conformance_results_snapshot:, signature_standdowns_snapshot: -> { [] },
|
|
60
|
-
vendored_standdowns_snapshot: -> { [] }, pooled_run_disclosures: -> { [] }
|
|
60
|
+
vendored_standdowns_snapshot: -> { [] }, pooled_run_disclosures: -> { [] },
|
|
61
|
+
pooled_trust_refusals: -> { [] })
|
|
61
62
|
@configuration = configuration
|
|
62
63
|
@rbs_extended_reporter = rbs_extended_reporter
|
|
63
64
|
@boundary_cross_reporter = boundary_cross_reporter
|
|
@@ -78,6 +79,9 @@ module Rigor
|
|
|
78
79
|
# Issue #1051 — reader for the pool coordinator's de-duplicated run-scoped disclosure table.
|
|
79
80
|
# Empty on a sequential run, where `plugin_registry`'s own instances are the ones that registered.
|
|
80
81
|
@pooled_run_disclosures_reader = pooled_run_disclosures
|
|
82
|
+
# Issue #1900 — reader for the pool coordinator's summed trust-refusal table. Empty on a
|
|
83
|
+
# sequential run, where `plugin_registry`'s own boundaries made every read.
|
|
84
|
+
@pooled_trust_refusals_reader = pooled_trust_refusals
|
|
81
85
|
end
|
|
82
86
|
|
|
83
87
|
# Pre-file diagnostic streams that fire once per run rather than per analyzed file: plugin load /
|
|
@@ -613,9 +617,18 @@ module Rigor
|
|
|
613
617
|
# culprit and reads the same on a cache hit, where every `RBS::Location` has been dumped to a
|
|
614
618
|
# sentinel. The error class is attributed to that first failure explicitly rather than to all of
|
|
615
619
|
# them: the per-class memo keeps only the first reason, and one run can mix error classes.
|
|
620
|
+
#
|
|
621
|
+
# Issue #1902 — "first" is first by CLASS NAME, not first recorded. The snapshot arrives in demand
|
|
622
|
+
# order, and that order is a property of the invocation, not of the project: an `--incremental`
|
|
623
|
+
# recheck records the classes its closure demanded before it unions in the replayed set, and a worker
|
|
624
|
+
# pool unions per-worker lists in drain order. So the classes are sorted by name and the files
|
|
625
|
+
# sorted and deduplicated here. Which tuple each class carries is fixed upstream
|
|
626
|
+
# ({Environment::RbsLoader.definition_build_detail_order}), not here.
|
|
616
627
|
def build_rbs_definition_build_failed_diagnostic(failures)
|
|
628
|
+
failures = failures.sort_by { |failure| failure.first.to_s }
|
|
617
629
|
sample_size = 5
|
|
618
|
-
files = failures.flat_map { |failure| Array(failure[3]) }
|
|
630
|
+
files = failures.flat_map { |failure| Array(failure[3]) }
|
|
631
|
+
.map { |name| relative_signature_path(name) }.uniq.sort
|
|
619
632
|
Diagnostic.new(
|
|
620
633
|
path: ".rigor.yml",
|
|
621
634
|
line: 1,
|
|
@@ -1084,16 +1097,22 @@ module Rigor
|
|
|
1084
1097
|
# cache"). It is also never routed through `IncrementalSession`'s per-file cache (`#788`): that cache
|
|
1085
1098
|
# holds only `Runner#per_file_diagnostics`, and this row is not part of that stream.
|
|
1086
1099
|
#
|
|
1087
|
-
#
|
|
1088
|
-
#
|
|
1089
|
-
#
|
|
1090
|
-
#
|
|
1091
|
-
#
|
|
1092
|
-
#
|
|
1100
|
+
# Two sources (issue #1900), summed per plugin: the coordinator-side registry's own boundaries — where
|
|
1101
|
+
# a sequential run, and the pool's no-worker fallback, made every read — and `pooled_trust_refusals`,
|
|
1102
|
+
# what a pooled run drained from its pre-fork parent session and every worker
|
|
1103
|
+
# ({Runner::PoolCoordinator#merge_trust_refusals}). The count is per refused ATTEMPT, as
|
|
1104
|
+
# `--workers 0` always counted it; the pool drains the parent's `#prepare` refusals before forking and
|
|
1105
|
+
# each worker reports only what it added, so the workers, which inherit the parent's boundaries, do
|
|
1106
|
+
# not count them again. Rows follow registry
|
|
1107
|
+
# (plugin load) order, which every mode shares.
|
|
1093
1108
|
def plugin_trust_refusal_diagnostics
|
|
1094
1109
|
return [] if plugin_registry.empty?
|
|
1095
1110
|
|
|
1096
|
-
|
|
1111
|
+
pooled = Array(pooled_trust_refusals).to_h { |record| [record[:plugin_id], record] }
|
|
1112
|
+
plugin_registry.plugins.filter_map do |plugin|
|
|
1113
|
+
summary = combined_refusal_summary(pooled[disclosure_plugin_id(plugin)], plugin)
|
|
1114
|
+
plugin_trust_refusal_diagnostic(plugin, summary) if summary
|
|
1115
|
+
end
|
|
1097
1116
|
end
|
|
1098
1117
|
|
|
1099
1118
|
# Issue #1051 — the run-scoped plugin disclosures ({Plugin::Base#disclose_once}), the run's
|
|
@@ -1193,10 +1212,23 @@ module Rigor
|
|
|
1193
1212
|
plugin.class.to_s
|
|
1194
1213
|
end
|
|
1195
1214
|
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1215
|
+
# The coordinator's own record first when it has one: on a pooled run it holds the `#init` reads
|
|
1216
|
+
# (every registry runs `#init`; the workers' drains start after it), which `--workers 0` makes before
|
|
1217
|
+
# `#prepare` and before any file, so its first path is the one a sequential run names. Not so after a
|
|
1218
|
+
# Ractor-backend degrade, where this record also holds the re-analysed files' refusals and is named
|
|
1219
|
+
# ahead of a worker's `#prepare` path; the count is right either way.
|
|
1220
|
+
def combined_refusal_summary(pooled, plugin)
|
|
1221
|
+
local = begin
|
|
1222
|
+
plugin.io_boundary.refusal_summary
|
|
1223
|
+
rescue StandardError
|
|
1224
|
+
nil
|
|
1225
|
+
end
|
|
1226
|
+
return local || pooled if pooled.nil? || local.nil?
|
|
1227
|
+
|
|
1228
|
+
local.merge(count: local[:count] + pooled[:count])
|
|
1229
|
+
end
|
|
1199
1230
|
|
|
1231
|
+
def plugin_trust_refusal_diagnostic(plugin, summary)
|
|
1200
1232
|
plugin_id = plugin.manifest.id
|
|
1201
1233
|
Diagnostic.new(
|
|
1202
1234
|
path: ".rigor.yml", line: 1, column: 1,
|
|
@@ -1283,6 +1315,10 @@ module Rigor
|
|
|
1283
1315
|
@pooled_run_disclosures_reader.call
|
|
1284
1316
|
end
|
|
1285
1317
|
|
|
1318
|
+
def pooled_trust_refusals
|
|
1319
|
+
@pooled_trust_refusals_reader.call
|
|
1320
|
+
end
|
|
1321
|
+
|
|
1286
1322
|
def pre_eval_diagnostics_from_scanner
|
|
1287
1323
|
@pre_eval_diagnostics_from_scanner_reader.call
|
|
1288
1324
|
end
|