xspec rename and xspec move — that handle all rewriting atomically and record a journal entry so that baselines remain intact.
Renaming a node ID
xspec rename rewrites the ID within the named file and cascades the change everywhere it matters:
- The section’s own
idattribute and all descendant IDs (by prefix replacement) - Every reference to the old ID:
idattributes,ddependency refs,text(...)targets in both MDX and TypeScript files - TypeScript markers that cite the ID
- An entry in the identity journal at
.xspec/journal - All derived files are regenerated
xspec impact --base <any-ref> against a baseline that predates the rename produces an empty report. The journal maps the old ID to the new one, and impact analysis follows that mapping transparently.
Moving nodes
xspec move has two forms depending on whether you are relocating a whole file or extracting a section.
File form
Section form
<id> from its origin file and inserts it at the end of the target parent (or at the top level of the target file). The command:
- Removes the subtree from the origin file
- Inserts it into the target file (creating the file if it does not exist)
- Rewrites all references between local and imported forms as needed
- Records the mapping in the journal
descendant-changed in the impact report for the parent nodes only — the moved subtree itself is journaled and invisible to impact.
The journal
The journal lives at.xspec/journal. It is a plain-text, append-only file with one mapping entry per line, written exclusively by xspec rename and xspec move.
Key properties:
- Commit it. The journal is a durable file — it is not regenerated from sources. It must be in version control alongside your spec files.
- Concurrent branches merge cleanly. Because the journal is append-only and each entry is independent, textual merge of concurrent branches works without conflicts in the common case.
xspec checkvalidates it. If the current journal is not a forward extension of the journal at a given baseline,xspec impactagainst that baseline exits with a hard error (exit code2).
Refusal conditions
Both commands exit1 without modifying anything if any of the following conditions hold:
- The workspace does not pass
xspec buildvalidation (build must be clean first) - The new ID is invalid, already in use, or structurally inconsistent with its parent
- Section move only: the operation would create an import or dependency cycle, the destination file already exists (file form), the target parent node is missing or is inside the subtree being moved, or the destination path is not a valid spec source path
xspec check after any interrupted operation to confirm the workspace is consistent.
Practical workflow
1
Keep content edits and structural changes in the same branch
You do not need to separate refactoring commits from content changes. xspec handles both in any order.
2
Use commands even for 'trivial' renames
A journal entry is cheap. Even renaming
auth.lockout to auth.lockout.v2 takes a fraction of a second and ensures zero impact noise in every baseline comparison going forward.3
Verify with impact after refactoring
After a rename or move, confirm the identity guarantee holds:A rename or move that was fully journaled produces an empty report.
Example
AUTH.mdx and placed into THROTTLING.mdx. All references are rewritten automatically, and the journal gains a second entry.