Skip to main content
Renaming a node ID or relocating a section across files are common maintenance tasks, but hand-editing IDs breaks impact analysis, invalidates review sessions, and leaves dangling references across your codebase. xspec provides two commands — 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 id attribute and all descendant IDs (by prefix replacement)
  • Every reference to the old ID: id attributes, d dependency 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
The result is an identity guarantee: running 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.
Type-only TypeScript references (e.g., a type alias that names the old ID) are not rewritten by xspec rename. These will surface as TypeScript compiler errors, which is intentional — they require a deliberate human decision about the type shape.

Moving nodes

xspec move has two forms depending on whether you are relocating a whole file or extracting a section.

File form

Relocates the entire source file to a new path. All node IDs stay unchanged. Because no IDs change and the journal records the file-level mapping, this is a pure operation: no hash changes, no impact report noise, no invalidated review items.

Section form

Extracts the subtree rooted at <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
The parent nodes of both the origin and the target will reflect a 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.
Never edit or delete the journal. It is the source of truth for identity continuity. Hand-editing it will corrupt baseline comparisons and may cause xspec check to report errors. If the journal is damaged, restore it from version control.
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 check validates it. If the current journal is not a forward extension of the journal at a given baseline, xspec impact against that baseline exits with a hard error (exit code 2).

Refusal conditions

Both commands exit 1 without modifying anything if any of the following conditions hold:
  • The workspace does not pass xspec build validation (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
Because refused operations modify nothing, you can safely retry after correcting the issue. Run 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

The section is extracted from AUTH.mdx and placed into THROTTLING.mdx. All references are rewritten automatically, and the journal gains a second entry.