A graph can accurately report that it is stale while still containing a declaration that no longer exists in the source. In our small Astria experiment, renaming a TypeScript function produced exactly that state. Refreshing the graph replaced the stored declaration, but it did not make the query return useful nodes on this fixture.
We build Astria. This is a disclosed investigation of our own tool using one synthetic file, not a comparison with other products or evidence of production-scale accuracy. Download the observations and reproduction notes and PowerShell reproduction script. Raw output is included in the evidence archive.
Change One Declaration
We used the installed Astria CLI, version 1.2.0, on Windows. The fixture contained only invoice.ts, initially defining:
export function calculateTotal(amount: number): number {
return amount;
}
After building the structural graph, we replaced that source with:
export function calculateNetTotal(amount: number, discount: number): number {
return amount - discount;
}
We captured status, query output, and a projection of the stored nodes and edges before the change, after the change, and after astria update .. The run used no semantic backend or embedding option. Queries requested a 1,000-token output budget and used explicit declaration seeds in the saved final run.
The source snapshots and exact command records are in the archive. The projection retains node identifiers, labels, signatures, line numbers, and edge relationships. It omits local absolute paths and unrelated graph metadata.
Observe Freshness Separately From Stored Content
| Observation | Initial graph | Source changed, graph not refreshed | After refresh |
|---|---|---|---|
| Reported freshness | Fresh | Stale | Fresh |
| Modified source files reported | 0 | 1 | 0 |
| Stored function label | calculateTotal() |
calculateTotal() |
calculateNetTotal() |
| Stored function signature | One parameter | One parameter | Two parameters |
| Nodes returned by the corresponding query | 0 | 0 | 0 |
The stale graph still held the old function and its one-parameter signature. That is a property of the saved snapshot, not proof that Astria returned an incorrect answer to an agent. The query returned no nodes, and its JSON explicitly reported the stale state with one modified file.
The distinction matters. A consumer should not interpret the presence of a graph, a successful process exit, or a plausible symbol suggestion as evidence that its contents match the current checkout. In this run, the stale status command exited successfully. A script that wants to reject stale data must inspect the reported status rather than relying only on the exit code.
Keep the Retrieval Failure in the Report
Our initial unseeded query returned no nodes even before the rename. A second exploratory run added explicit declaration seeds and still returned no nodes. We retained those observations and recorded a final run with graph snapshots to distinguish extraction from retrieval.
In the final run, the fresh query suggested calculateTotal() while returning no matching nodes. After refresh, the new-name query suggested calculateNetTotal() with the same empty result. Querying the old name after refresh also returned no nodes and suggested the new name.
The updated graph snapshot establishes that extraction recorded the new declaration. It does not establish that the query interface retrieved it successfully. We did not determine the cause of the empty retrieval in this article, and we have not measured generated-answer correctness. A larger benchmark would need to retain this kind of failure in its denominator.
Our retrieval evaluation article explains why locating a file, retrieving a declaration, and completing an agent task need separate measurements. Our phantom-dependency investigation examines another independent concern: whether graph relationships are structurally correct.
What the Timings Do and Do Not Show
In the saved final run, the initial build took 876 ms and refresh took 590 ms, measured around each CLI invocation. These include process startup and output capture. They are individual observations on a one-file fixture after exploratory runs, not cold-start measurements, stable averages, or evidence that refresh is generally faster by a particular percentage.
The archive includes every command duration for that run. A useful scaling study would vary repository size and changed-file count, repeat observations, describe cache conditions, and measure both refresh and query costs. This experiment answers a smaller question: what remains stored between a source change and a refresh?
Reproduce the Observation
Install the same Astria version and make its astria command available in PowerShell. Download and inspect the script, then choose an output directory that does not already exist:
./reproduce.ps1 -OutputDirectory ./staleness-observation
The script creates its own fixture and refuses to overwrite an existing output directory. It writes command records, source snapshots, graph projections, and status/query output. It leaves the fixture available for inspection. Use a clean environment and record the installed version if reproducing with a newer release. Results may differ.
For day-to-day work, inspect the freshness metadata before following graph evidence, refresh after relevant edits, and verify the returned declaration against source. Freshness is necessary for using a snapshot confidently, but this observation shows why it is not a substitute for retrieval or correctness checks.
For teams evaluating a code intelligence workflow, bring the source revision, exact question, returned evidence, and expected declaration to an architecture review. Those artifacts make failures reproducible and help identify what the tool actually needs to improve.
Use freshness as one part of the decision
| Observed state | Safe next action |
|---|---|
| Fresh snapshot, useful result | Verify the exact declaration and evidence before editing |
| Stale snapshot, nonempty result | Refresh the affected source and rerun; a plausible answer can still be old |
| Fresh snapshot, empty result | Search/read source and investigate retrieval coverage; do not conclude the symbol is absent |
| Incomplete extraction or failed update | Inspect diagnostics and preserve the failure in the report; do not mark the graph complete |
This table is operating guidance derived from the distinction examined here, not a claim that the historical retrieval failure has since been fixed. A hook is useful only when the team notices its failures. Assign an owner to inspect exit status, refresh metadata and a known changed declaration after a merge.
Frequently asked questions
Can we ignore a nonzero refresh exit because queries still work?
No. Queries may read an older successful snapshot. Inspect what completed and what did not, then verify the declaration you intend to use.
Does installing a hook remove manual checks?
No. Confirm the hook actually ran for the change and document the fallback when it fails. For a team trial, record the expected declaration, observed result and retry decision in the delivery acceptance record.




