0010 - FactStore Languages
Context¶
The model.Rule struct has an AppliesTo.Languages field (declared in the
rule YAML schema since day one), but the rule engine ignores it — every rule
runs against every repo. This causes false signals: a pure Go repo gets
penalized by P3.EXP.001 for not having .env.example, even though .env
is not a Go convention.
The data needed to implement filtering already exists: RepoFacts.Languages
is a map[string]int populated by the filesystem collector. It just isn't
exposed on the FactStore interface.
Decision¶
-
Add
Languages() map[string]inttomodel.FactStore. This is a public-interface change, requiring this ADR per CLAUDE.md §9. -
The rule engine (
rule.Engine.Evaluate) skips a rule when itsAppliesTo.Languagesis non-empty and none of the listed languages appear infacts.Languages(). Skipped rules are tracked inEvalResult.SkippedRuleIDs. -
score.Computeaccepts an optionalskippedRuleIDsvariadic. Skipped rules' weights are excluded from the denominator so they cannot penalize the score for ecosystems they don't target. -
The code-generation tool (
genrules) emitsAppliesTowhen the YAML declaresapplies_to.languages.
Consequences¶
- All
FactStoreimplementations (real, test fakes) must add theLanguages()method. Test fakes returnnil. - Rules without
applies_tocontinue to run everywhere (backward compatible). - Adding language tags to a rule is a YAML-only change +
make generate. - A single-language repo no longer gets penalized by rules targeting other ecosystems.