# Rename-Proof Identity *Rename a function. Keep its history.* Renaming is the most common refactor in software. Every codebase accumulates bad names: `doIt`, `processData`, `handleThing`. Every developer sooner or later improves one. In a sane tool, renaming should be frictionless: change the name, and everything that referenced the old name now references the new name. History follows. Callers update. Tests still pass. Git makes renaming a minor ordeal. The rename itself is fine — your editor does the text substitution in a second — but Git's history does not follow. `git log` on the renamed function shows only the commits since the rename. To see earlier history, you reach for `git log --follow`, which applies heuristics, which are fragile, which break across cross-file renames, which break entirely across rename chains. Aura makes renaming a non-event. The function's [content hash](/content-addressed-logic) does not include its own name. Renaming does not change the function's identity. History is continuous. References are updated. Nothing is lost. > A rename is a relabeling, not a deletion. ## The Git experience, concretely Start with a function in a file: ```rust // src/auth.rs pub fn login(user: &str, pass: &str) -> Result { // 200 lines of careful logic } ``` A year later, the team decides `login` is too narrow — the function actually authenticates, not just logs in. Rename it to `authenticate`. Update callers. Commit. ```rust // src/auth.rs pub fn authenticate(user: &str, pass: &str) -> Result { // same 200 lines } ``` Now you want to understand the history of this function. You run: ```bash git log -- src/auth.rs ``` Works, shows every commit that touched the file. But you want only the function, not the file. You open `git blame`. It tells you that the current implementation was authored "yesterday, in commit 7c9f21" — the rename commit. The year of work behind the function is invisible. You try `git log --follow`. It helps for some cases. It breaks when: - The function moved to a different file in the same commit as the rename. - The rename happened alongside substantial edits, so Git cannot heuristically match the old and new bodies. - The function was renamed more than once. `--follow` sometimes stops at the first rename. - The rename crossed a merge commit. The practical experience is that serious history spelunking after a rename is hard. Developers respond by avoiding renames. Bad names persist because renaming feels risky. ## The Aura experience Rename the function. Commit. ```bash aura_log_intent "Renamed login to authenticate — function actually does full auth, not just login" git commit -am "rename login to authenticate" ``` The pre-commit hook sees: - Function with content hash `fn:7c9f21...` previously named `login`. - Function with content hash `fn:7c9f21...` now named `authenticate`. - Body unchanged. It records a **rename operation** on the [shadow branch](/shadow-branches): ```json { "op": "rename", "kind": "function", "identity": "fn:7c9f21...", "from": "login", "to": "authenticate" } ``` The function's identity is unchanged. Its shadow history still contains every prior commit. Every caller is automatically updated (or flagged if the rename is in a library crate and callers live in downstream consumers). Every review comment pinned to the function still resolves. Six months later, you ask "show me the history of `authenticate`." Aura walks the shadow by identity, finds every version, and shows you a timeline that includes the year of commits before the rename. The fact that the function was once called `login` is a note in the metadata, not a barrier to history. ## Comparison table | Operation | Git behavior | Aura behavior | |---|---|---| | `log` shows full history after rename | Only post-rename, unless `--follow` | Full history, by identity | | `blame` attributes old logic | To rename commit | To original author | | Cross-file rename | `--follow` fragile | Transparent | | Multiple renames over time | `--follow` may truncate | Full chain preserved | | Rename during merge | Often lost | Preserved | | Review comment pinned to function | Breaks on rename | Follows identity | | `rewind` to pre-rename version | N/A | Works; identity resolves pre-rename | | CI / deploy tooling | Unchanged (Git unchanged) | Unchanged (Git unchanged) | ## How the matching works The question "is the function called `authenticate` today the same as the function called `login` yesterday?" is answered by comparing content hashes. If the body did not change (or changed only in the parameter name that also changed), the content hash is unchanged. Aura matches the two and records a rename. When the rename coincides with a body edit — you renamed *and* changed a line — the content hash differs. Aura uses structural similarity: parameters, return type, neighboring code, the fact that one function disappeared and a new one appeared in the same commit. When similarity is high, Aura records a rename-with-edit. When similarity is low, Aura records a delete-plus-add. The line between these is configurable; the default is conservative. In ambiguous cases, the [intent log](/intent-tracking) resolves things. If your intent says "renamed login to authenticate," Aura is confident the rename matching is correct even when the body also changed substantially. Intent is a hint the matcher uses — not a requirement, but a powerful signal. ## Cross-file renames Renames often cross files. You rename `login` to `authenticate`, and in the same commit you move the function from `src/auth.rs` to `src/security/tokens.rs`. Git's `--follow` handles this poorly. Aura handles it with the same machinery. The function's identity does not include its file. Moving the function is another operation — a `move` — recorded on the shadow. Rename + move in the same commit produces two operations on the same identity: rename, move. Both preserve history. ```json { "op": "rename", "identity": "fn:7c9f21...", "from": "login", "to": "authenticate" } { "op": "move", "identity": "fn:7c9f21...", "from": "src/auth.rs", "to": "src/security/tokens.rs" } ``` The function is now known as `authenticate` in `src/security/tokens.rs`. Its history is exactly what it was the day before. ## References update automatically When a function is renamed, every call site needs to change. Aura rewrites them as part of the rename operation — not at the text level, but at the AST level. It walks the logic graph, finds every reference to the renamed identity, and updates the identifier. This is: - More reliable than find-and-replace (which can match strings in comments, strings, or unrelated functions with the same name). - Faster than an IDE rename in some languages (because it skips language-server roundtrips once the graph is populated). - Consistent across the repo (because the graph knows every reference). If a reference cannot be updated automatically — say, the reference is in a dependent crate not in this repo — Aura surfaces it. You see a list of external references that need attention. ## Rename and the pre-commit hook The [pre-commit hook](/pre-commit-hook-explained) sees rename operations explicitly. It does not flag a rename as "function deleted, function added" and then agonize over whether this matches the intent. It flags it as "function renamed," matches it against your stated intent, and moves on. If your intent says "added authentication module" but the diff is a rename, the hook asks whether the intent and the delta agree. If your intent says "renamed login to authenticate," consistency is trivial. This is the general pattern: treating rename as a first-class operation makes every downstream tool work better. [Review](/intent-tracking) sees renames cleanly. [Merge](/ast-merge) resolves them without conflicts. [Rewind](/snapshot-vs-commit) targets them unambiguously. ## The deeper point Renames are a special case of a general principle: the *label* for a thing is not the thing. When a tool conflates label with identity, every label change becomes an identity change. When a tool keeps them separate, the label is free to evolve. Git conflates label with identity because it has to — it has no semantic layer beneath the text. It sees `login` and `authenticate` as different tokens because, from Git's perspective, they are. Aura has the semantic layer, so it can distinguish. The function is a persistent object; the name is an attribute of that object that can change without the object changing. Once you have this distinction, you get more than rename-proofing. You get: - **Move-proofing**: the file path is also an attribute. Changing it doesn't change the function. - **Reformat-proofing**: formatting is an attribute of presentation, not identity. - **Local-rename-proofing**: the names of local variables are attributes, not identity. - **Reorder-proofing**: position in a file is an attribute, not identity. All of these fall out of the same principle. The function is a thing. Its name, its file, its formatting, its position are labels and coordinates we attach to it. Aura tracks the thing; Git tracks the labels. ## Historical note This is, in a narrow sense, what every programming language runtime already does. A function in memory has an address; its name is a symbol that resolves to that address. Renaming in source does not change the address; it changes the symbol table. Aura brings this distinction to version control. The reason Git does not have it is not a flaw in Git — it is a consequence of Git predating the availability of fast, reliable, language-agnostic parsers. In 2005, parsing every file on every commit in every supported language was out of the question. In 2026, with tree-sitter, it is routine. ## Related Rename-proofing is a direct consequence of [function-level identity](/function-level-identity) and [content-addressed logic](/content-addressed-logic). It is recorded as a first-class operation in [semantic diff](/semantic-diff) and handled by [AST merge](/ast-merge).