Corpus Behavioral¶
The package's position in the corpus, or its deviation from a corpus
baseline. These are Class D and Class E: they run once per metadata cycle
in trustsight full-aur, after the per-package loop, and each returns one
finding per cluster with the members in params.members.
They are silent without a prior snapshot, which is enforced rather than
assumed: the calibration gate is fire_rate(no_baseline) == 0. R112 and
R107/R111 are prioritisation rather than accusation; they say what a
compromise would reach, not that anything is wrong.
See the rule system reference for the field table, the severity weights and the reserved identifier ranges.
R073: Accelerated Release Cadence¶
- Target: programmatic (git commit graph)
- Severity: metadata field, never a scored finding
- Category:
temporal-metadata - Condition: The HEAD commit has 3+ ancestors within the last 24 hours (rapid-fire pushes).
Why it does not score: Bursts of commits are overwhelmingly benign
activity - a maintainer fixing a bad checksum, then a typo, then a rebuild
bump. This is precisely the "measuring activity, not risk" failure the
accuracy work's CI gate (|pearson(score, diff_lines)| < 0.3) exists to
catch. At any non-zero weight it becomes a census on active maintainers.
R073 is therefore metadata only: recorded as a boolean on the
PackageFact (recent_commit_burst: bool). It is not appended to
triggered_rules and contributes nothing to the score. If future corpus
analysis shows that burst cadence pairs with other signals (burst +
maintainer takeover + verification removal), the burst multiplier can be
applied to those signals alone - never as a standalone finding.
Origin: pnpm's minimumReleaseAge (24-hour cooldown on new versions) and
uv's exclude-newer (reject packages published within a configurable window).
Both tools impose a registry-side cooldown: do not install a version until
it has existed long enough for the community to vet it. R073 takes the
opposite perspective - instead of blocking recent versions, it notes that
multiple commits landed in a short window, recording the cadence as context
for other signals to use.
R093: Orphan/Adoption Dependency¶
- Severity: MEDIUM (weight 15)
- Category:
dependency - Condition: A package depends directly on a package orphaned or adopted in this cycle.
R107: Transitive Exposure¶
- Severity: INFO (weight 0)
- Category:
dependency - Condition: A package's transitive closure, at least
[thresholds] r107.min_hops(default 2) hops away, reaches a package adopted out of the orphan state this cycle. Context only, never additive.
R111: Transitive Orphan Exposure¶
- Severity: INFO (weight 0)
- Category:
dependency - Condition: A package's transitive closure includes a currently orphaned package. Context only, never additive.
R112: Dependency Centrality¶
- Severity: INFO (weight 0)
- Category:
dependency - Condition: A package is depended on by at least
[thresholds] r112.min_dependents(default 50) AUR packages. Prioritisation only: it says what a compromise would reach, not that anything is wrong.
R125: Introduction Rate Deviation¶
- Severity: MEDIUM (weight 15)
- Category:
adoption - Condition: The corpus-wide introduction rate for a cycle deviates from the baseline mean by at least
[thresholds] r125.z_score(default 3.0), once at leastr125.min_history_cycles(default 3) cycles of history exist. An immature history is quiet.
R106: Known Indicator of Compromise¶
- Severity: tiered by the indicator's confidence:
confirmedis FATAL,highis CRITICAL,mediumis HIGH, an untiered entry is MEDIUM - Category:
ioc - Condition: A declared surface exactly matches an entry in
iocs.toml.
Four surfaces are read: the package's own name; names added to
depends/makedepends/optdepends/checkdepends/provides/replaces; the
host of any URL and any bare host token; and any hex digest of digest length.
R106 also reads the current PKGBUILD, not only the diff, so a dependency on a
package later published as malware is reported on every review rather than only
on the one that introduced it.
Matching is exact. Normalisation is limited to what is not part of the identity: case, a trailing root dot, IDNA spelling, surrounding quotes. A host is never stripped of a subdomain and a name is never stemmed, because that would turn equality into resemblance. A malformed entry is dropped with a warning rather than coerced.
The shipped list is empty. TrustSight does not invent indicators, so a fresh
install cannot fire R106 at all, and a miss is uninformative. trustsight corpus
pivot <indicator> inverts the rule: given one indicator, it lists every corpus
package referencing it, reading only stored material and never the network.
A confirmed indicator cannot be suppressed through overrides.json.