book/tools/scripts/docs/SECTION_ID_SYSTEM.md
The section ID management system provides automated tools for managing unique, consistent section IDs in Quarto/Markdown book projects. The system uses a hierarchy-based approach to generate stable, meaningful section IDs that reflect the actual document structure and ensures global uniqueness across the entire book project.
The hash is generated from:
{file_path}|{chapter_title}|{section_title}|{parent_hierarchy}
Where:
file_path: The file path (ensures global uniqueness across different files)chapter_title: The chapter titlesection_title: The section titleparent_hierarchy: A pipe-separated list of all parent sections (e.g., parent1|parent2|parent3)The inclusion of the file path in the hash generation ensures that sections with identical names and hierarchies in different files will have different IDs. This prevents conflicts when:
# File: contents/chapter1.qmd
# Getting Started
## Introduction {#sec-getting-started-introduction-d212}
# File: contents/chapter2.qmd
# Getting Started
## Introduction {#sec-getting-started-introduction-8435}
Hash inputs:
"contents/chapter1.qmd|Getting Started|Introduction|" → hash: d212"contents/chapter2.qmd|Getting Started|Introduction|" → hash: 8435Result: Different 4-character hashes ensure unique IDs across the entire book.
The system maintains a stack of parent sections as it processes the document:
section_hierarchy = [] # Stack of parent sections
# For each header level, update the hierarchy
while len(section_hierarchy) >= header_level - 1:
section_hierarchy.pop()
section_hierarchy.append(title.strip())
# Get parent sections for current section
parent_sections = section_hierarchy[:-1] if len(section_hierarchy) > 1 else []
# Build hierarchy string from parent sections
hierarchy = ""
if parent_sections:
hierarchy_parts = []
for parent in parent_sections:
hierarchy_parts.append(simple_slugify(parent))
hierarchy = "|".join(hierarchy_parts)
# Generate hash with file path for global uniqueness
hash_input = f"{file_path}|{chapter_title}|{title}|{hierarchy}".encode('utf-8')
hash_suffix = hashlib.sha1(hash_input).hexdigest()[:4]
Consider a document with this structure:
# Introduction
## AI Evolution
### Symbolic AI Era
#### Data Considerations
### Expert Systems Era
#### Data Considerations
### Deep Learning Era
#### Data Considerations
The three "Data Considerations" sections will get different IDs:
sec-introduction-data-considerations-d32a (under Symbolic AI Era)sec-introduction-data-considerations-8ae1 (under Expert Systems Era)sec-introduction-data-considerations-fdab (under Deep Learning Era)| Aspect | Counter-Based | Hierarchy-Based |
|---|---|---|
| Stability | Changes when sections reordered | Stable unless hierarchy changes |
| Meaning | Arbitrary position-based | Reflects document structure |
| Duplicates | Requires manual counter management | Handled naturally by context |
| Maintenance | Fragile to document changes | Robust and self-maintaining |
| Global Uniqueness | May conflict across files | Guaranteed by file path inclusion |
# Add missing IDs
python section_id_manager.py -d contents/
# Repair existing IDs to new format
python section_id_manager.py -d contents/ --repair --backup
# Verify all IDs
python section_id_manager.py -d contents/ --verify
# List all IDs
python section_id_manager.py -d contents/ --list
--backup creates timestamped backups--dry-run previews changes without modifying files--force automatically accepts all changesIf you have existing counter-based IDs, the system will automatically migrate them:
python section_id_manager.py -d contents/ --repair --backup--backup when making bulk changes--verify to ensure ID integrity--dry-run to see what will changedef generate_section_id(title, file_path, chapter_title, section_counter, parent_sections=None):
title: The section titlefile_path: The file path (included in hash for global uniqueness)chapter_title: The chapter titlesection_counter: Counter for this section (not used in hash)parent_sections: List of parent section titles (included in hash)parent_sections is a list of strings representing the full hierarchysimple_slugify() to remove stopwords| separator in the hash input--repair to update all references--list to see all current IDs--verify to check for missing or malformed IDs