astria 1.1.0: evidence you can trust — no phantom files, gates that can actually fail
1.1.0 fixes a class of quiet dishonesty in the graph. A node that exists because no file defined the name was borrowing whichever file happened to reference it first — so unresolved globals looked like real code locations. That single mistake surfaced as invented file-to-file dependencies, import "cycles" between unrelated crates, and an explain output that named a file which did not own the symbol. Install or upgrade with npm install -g @nodesify/astria.
Where the wrong file came from
When astria extracts an edge whose target it cannot resolve, it creates a speculative stub node for that name (super, path, a minified single letter) so the edge has somewhere to land. Those nodes are created from an edge, and there was only one file in scope at that moment — the file containing the edge. So the stub recorded the referencing file as its source.
Nothing warns you. Every consumer that reads source_file treats it as a real location, so on this repository a lone import rusqlite in health.rs became the file dependency health.rs -> <whichever file first mentioned rusqlite>, and astria explain console_error reported:
File: packages/astria-cli/src/__tests__/cli.test.ts
console_error is a global with 44 calling files. It does not live in that test file — or in any file.
The fix, and what it was worth
A stub or reference node is, by definition, a name with no definition, so it has no source locus. That is now enforced as a whole-graph invariant on every pipeline run rather than trusted per-edge, which also means an ordinary astria update . heals graphs built by earlier versions.
Measured on this repository, before and after:
| before | after | |
|---|---|---|
| fabricated file-to-file dependencies | 743 | 0 |
stub nodes asserting a file | 1,527 of 1,527 | 0 of 1,527 |
| reported file "cycles" | 4 (all artifacts) | 0 |
similar_to edges joining two unresolved names | 1,302 | 0 |
explain <global> | names an unrelated file | says no source locus |
All four reported "cycles" were artifacts of this bug — including a six-file cycle spanning four crates that reads convincingly and does not exist in the source. If you have ever seen a dependency cycle in astria health and gone looking for the import, there is a real chance you were looking for something this release deleted.
Two gates that could not gate
Two checks in 1.1.0 exist because the previous behaviour was worse than having no check: it reported success.
astria healthalways exited 0. It printed a score and a grade, so it read as a gate, but nothing could fail a build on it. It now takes--min-score <n>and exits non-zero below the threshold —astria health --min-score 70is a working CI check.astria merge-gatedid not look at the extraction ruleset. Age and HEAD coverage both pass for a graph whose cache predates the current extraction rules: the old results are reused, so the graph reports yesterday's facts with today's timestamps. That is exactly how this repository's own self-graph drifted five commits. The gate now checksextraction-currentand tells you to runastria update ..
Fewer false alarms from test code
is_test_file did not recognise __tests__/, .test.ts, or .spec.ts. Test helpers were therefore scored as production code, and on this repo a test-only assert() ranked as the third most connected symbol in the project with the test-hub counter reporting zero — the check that was supposed to demote it never matched the paths it was meant to catch. Hub concentration, dead-code candidacy, and cycle inputs now share the corrected matcher, and speculative nodes are excluded from the hub list, the report's "Key Files", "surprising connections", and the local embedding layer.
What this release does not claim
It does not claim better retrieval. Golden-set ranking is byte-identical with and without these changes (MRR 0.5979 both ways) — the graph now says fewer false things, and reports the same things in the same order. A patch-level quality comparison against the 1.0.8 baseline does show top-rank softening (MRR 0.6817 → 0.5979, recall@5 0.8000 → 0.7286 at identical budget, depth, and golden set; recall@10 unchanged), which lives in the earlier extraction work rather than here. It clears the CI floor, and it is written down rather than smoothed over.
The upstream comparison is narrower but clean: against a question-derived rg-plus-reads baseline on pinned Click, Express, and ripgrep, astria ranked the defining file first in 12 of 12 corpus × budget × method comparisons.