Class: OKF::Bundle::Linter
- Inherits:
-
Object
- Object
- OKF::Bundle::Linter
- Defined in:
- lib/okf/bundle/linter.rb,
lib/okf/bundle/linter/report.rb
Overview
Lints a bundle for curation quality — the deterministic subset of the ingest → query → lint loop (overview.md): reachability, backlog, completeness, freshness, provenance, attestation, migration, and hygiene. Pure — it reads nothing from disk and works entirely on the in-memory OKF::Bundle, mirroring OKF::Bundle::Validator.
Unlike OKF::Bundle::Validator (the §11 conformance gate, which MUST NOT reject for
broken links or missing optional fields), lint never rejects a bundle: it reports
:warn and :info findings the spec marks as tolerable, and emits them as
structured data (OKF::Bundle::Linter::Report) for a human or agent to act on. Contradictions
and semantic staleness are NOT detected here — they need meaning, not structure;
the JSON report is the substrate an agent consumes for those passes.
Defined Under Namespace
Classes: Report
Constant Summary collapse
- SEVERITIES =
Severity is API: machine consumers gate edits and CI on
:warnand drop:info, so an id changing level changes its behavior for them — this map is pinned by a test, and a new gateable state gets a flag (--fail-on info), never a severity promotion. Two calls worth their one sentence:unattributed_claimwarns while its join-twinunused_sourceinforms, because a dangling footnote misattributes a claim — a correctness defect — while an uncited source is only slack. Andexpiredinforms rather than warns: astale_afterpasses on the calendar, not on a change, so a warn would fail a--fail-on warngate on a morning nobody chose. { orphan: :warn, not_in_index: :warn, disconnected_component: :info, unlinked: :info, missing_concept: :info, broken_index_entry: :warn, stub: :info, missing_title: :info, missing_description: :info, missing_generated: :info, expired: :info, stale: :warn, uncited_external: :info, broken_source: :warn, unattributed_claim: :warn, unused_source: :info, unprefixed_actor: :info, incomplete_computation: :warn, broken_attestation_ref: :warn, legacy_timestamp: :info, legacy_citations: :info, duplicate_title: :info, unused_reference_def: :info, undefined_reference: :warn, self_link: :info, log_order: :info }.freeze
- CHECKS =
All checks, in display/registry order — derived from the severity map (insertion-ordered) rather than hand-listed twice: two parallel lists of the same 25 ids needed a test just to police their sync.
--only/--exceptselect from these. SEVERITIES.keys.freeze
- COMPUTATION_HEADING =
An ATX heading naming the §10.3 computation section.
/\A\#{1,6}\s+Computation\s*\z/i.freeze
- ACTOR_FORMS =
§7's three actor forms:
<producer>/<version>,human:<id>,process:<id>. [ %r{\A\S+/\S+\z}, /\Ahuman:\S+\z/, /\Aprocess:\S+\z/ ].freeze
- DEFAULT_MIN_BODY =
50- HUB_LIMIT =
5
Class Method Summary collapse
Instance Method Summary collapse
- #call ⇒ Object
-
#initialize(bundle, min_body: DEFAULT_MIN_BODY, stale_before: nil, today: nil, only: nil, except: nil) ⇒ Linter
constructor
todayis injected for the same reasonstale_beforeis: the linter is pure and never reads the clock.
Constructor Details
#initialize(bundle, min_body: DEFAULT_MIN_BODY, stale_before: nil, today: nil, only: nil, except: nil) ⇒ Linter
today is injected for the same reason stale_before is: the linter is
pure and never reads the clock. Without it expired cannot know whether
a stale_after has passed and does not run — and confesses, in
stats, because a gate that is sometimes absent and does
not say so converts "unchecked" into "checked and fine". The CLI always
passes today; a library caller that wants the check passes today:.
65 66 67 68 69 70 71 72 73 |
# File 'lib/okf/bundle/linter.rb', line 65 def initialize(bundle, min_body: DEFAULT_MIN_BODY, stale_before: nil, today: nil, only: nil, except: nil) @bundle = bundle @min_body = min_body @stale_before = stale_before @today = coerce_today(today) @only = only @except = except @report = Report.new end |
Class Method Details
.call(bundle, **options) ⇒ Object
55 56 57 |
# File 'lib/okf/bundle/linter.rb', line 55 def self.call(bundle, **) new(bundle, **).call end |
Instance Method Details
#call ⇒ Object
75 76 77 78 79 80 |
# File 'lib/okf/bundle/linter.rb', line 75 def call prepare selected_checks.each { |check| send("check_#{check}") } fill_stats @report end |