Skip to content

Add a rule + fixtures rejecting reintroduced default-bundle Lint.swift #81

Description

@coenttb

Problem

Fleet-wide removal of redundant "default-bundle" Lint.swift files (swift-institute/.github#536, programme #527) has no mechanical guard preventing reintroduction. A package-local Lint.swift whose only import and only trailing-closure content is exactly one Lint.Rule.Bundle.<layer> matching the consumer's own resolved layer — no .excluding, no inline Rule.Configuration entries — reproduces the central default bundle CI and local tooling already select when Lint.swift is absent. Nothing today rejects that shape: #536's wave-2 census confirmed no rule matching this predicate exists in swift-institute-linter-rules, swift-linter-rules, swift-primitives-linter-rules, or swift-standards-linter-rules. Without this rule, the 447-file convergence wave cannot stay converged — any future package can silently reintroduce the exact redundant file the wave removed.

Proposed outcome

A mechanical rule — implemented as an AST rule in this repository, since it must compare a package's own resolved layer (primitives/standards/institute) against the correct central bundle, which is Institute-level composition knowledge — that fails closed when a package-local Lint.swift reproduces the central default for its own layer. The rule flags (and can fix-remove) the file. It ships with fixtures proving it fires only on the exact redundant shape:

  • Positive: fixtures drawn from the shape of the 447 already-removed blobs (bare Lint.Rule.Bundle.<layer> matching the consumer's own layer, .package(url:) pointed at the matching central rules repo, zero .excluding, zero Configuration overrides, zero inline rules) — must fire.
  • Negative: the 8 currently-retained package-specific root configurations (swift-carrier-primitives, swift-standard-library-extensions, swift-linter-primitives, swift-primitives-linter-rules, swift-standards-linter-rules, swift-institute-linter-rules, swift-linter, swift-linter-rules) — must NOT fire.
  • Edge: bundle token present but wrapped in a .excluding(rules: []) no-op, or with a trailing comment only — must NOT fire (composition is still nominally the default, but the file's presence is the redundancy, not a semantic difference; edge case exists to prove the rule inspects the effective composition, not surface text, without over-firing on true no-ops — implementer to confirm exact intended behavior against #536's stated predicate).
  • Near-miss: bundle token correct but an extra disabled-rule override present — must NOT fire (this is package-specific composition, class 6 in #536, not redundant).

Alternatives considered

  • Enforce centrally in CI (swift-ci.yml / institute-continuous-integration) instead of as a linter rule. Rejected as primary path: the census in #536 already scoped this as a rule-pack concern (it searched the four *-linter-rules repos, not CI), and a linter rule composes with institute lint locally the same way every other Institute rule does, giving fix-on-save/pre-commit coverage that a CI-only check would not.
  • Do nothing / rely on code review. Rejected — this is exactly the failure mode the wave exists to close; #536 states the wave "did not — and structurally could not — reach completion" without this rule, and manual review does not survive fleet scale (447+ repos).
  • Handwritten per-package exception list. Rejected as inconsistent with #536's acceptance criterion 6 (no open-ended path exception or arbitrary local configuration admitted) and the programme's general composition discipline.

Compatibility and migration impact

  • Affects every package across swift-primitives, swift-standards, and swift-foundations that carries a root Lint.swift (currently the 8 retained configs, evaluated by the negative-control fixtures above, plus any future package).
  • No impact on packages without a root Lint.swift (the common case post-wave) — CI/local tooling's absent-file bundle selection, already shipped, is unaffected.
  • Ships as an added rule in this repository's existing rule set; consuming repos pick it up through their existing .package(url:) pin to this repo, same as any other rule addition — no separate adoption step.

Owns acceptance criterion 5 of swift-institute/.github#536 (mechanical rule + fixtures preventing Lint.swift reintroduction fleet-wide). Refs programme #527.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions