class CorrectedRootDocSchemaRepair
A repair tool that fixes corrupted size entries in reMarkable cloud's root.docSchema file by recalculating correct document sizes from their component schemas.
/tf/active/vicechatdev/e-ink-llm/cloudtest/corrected_repair.py
19 - 274
complex
Purpose
This class provides functionality to diagnose and repair corrupted entries in the reMarkable cloud storage's root.docSchema file. It identifies documents with suspicious size values (2247, 2246, 2715 bytes), recalculates their correct sizes by summing component sizes from individual document schemas, and uploads the corrected root.docSchema back to the reMarkable cloud. The tool preserves the original version number and maintains all folder and special entries unchanged while fixing only corrupted document entries.
Source Code
class CorrectedRootDocSchemaRepair:
"""Corrected version of the repair tool"""
def __init__(self):
# Load auth session
from auth import RemarkableAuth
auth = RemarkableAuth()
self.session = auth.get_authenticated_session()
if not self.session:
raise RuntimeError("Failed to authenticate with reMarkable")
self.base_dir = Path(__file__).parent
self.backup_dir = self.base_dir / "docschema_repair"
self.backup_dir.mkdir(exist_ok=True)
print("š§ CORRECTED reMarkable Root DocSchema Repair Tool")
def get_current_root_content(self) -> Tuple[str, str, Dict]:
"""Get current root.docSchema content and metadata"""
# Get root info
root_response = self.session.get("https://eu.tectonic.remarkable.com/sync/v4/root")
root_response.raise_for_status()
root_data = root_response.json()
# Get content
root_content_response = self.session.get(f"https://eu.tectonic.remarkable.com/sync/v3/files/{root_data['hash']}")
root_content_response.raise_for_status()
root_content = root_content_response.text
return root_content, root_data['hash'], root_data
def identify_corrupted_entries(self, root_content: str) -> Dict[str, List]:
"""Identify which entries need size correction"""
lines = root_content.strip().split('\n')
original_version = lines[0] # KEEP ORIGINAL VERSION!
entries = lines[1:]
print(f"š Original version: {original_version} (will preserve this)")
print(f"š Total entries: {len(entries)}")
# Suspicious sizes that indicate corruption
suspicious_sizes = {'2247', '2246', '2715'}
categorized = {
'original_version': original_version,
'good_entries': [], # Entries with reasonable sizes
'corrupted_entries': [], # Entries with suspicious small sizes
'folders': [], # All folder types (type 1 and 2)
'special': [] # Other special entries
}
for i, line in enumerate(entries):
if ':' in line:
parts = line.split(':')
if len(parts) >= 5:
entry = {
'line_number': i + 1,
'hash': parts[0],
'uuid': parts[2],
'type': parts[3],
'size': parts[4],
'full_line': line
}
# Categorize by type and size
if entry['type'] in ['1', '2']: # Folders (both types)
categorized['folders'].append(entry)
print(f"š Folder (type {entry['type']}): {entry['uuid'][:8]}... size {entry['size']}")
elif entry['type'] in ['4', '5']: # Documents (PDF/Notebook)
if entry['size'] in suspicious_sizes:
categorized['corrupted_entries'].append(entry)
print(f"š§ CORRUPTED document: {entry['uuid'][:8]}... size {entry['size']} (needs fixing)")
else:
categorized['good_entries'].append(entry)
print(f"ā
Good document: {entry['uuid'][:8]}... size {entry['size']}")
else:
categorized['special'].append(entry)
print(f"ā Special entry type {entry['type']}: {entry['uuid'][:8]}... size {entry['size']}")
print(f"\nš Classification Summary:")
print(f" š Folders: {len(categorized['folders'])}")
print(f" ā
Good documents: {len(categorized['good_entries'])}")
print(f" š§ Corrupted documents: {len(categorized['corrupted_entries'])}")
print(f" ā Special entries: {len(categorized['special'])}")
return categorized
def fix_corrupted_document(self, entry: Dict) -> str:
"""Fix a single corrupted document by recalculating its correct size"""
doc_hash = entry['hash']
doc_uuid = entry['uuid']
print(f"\nš§ Fixing document {doc_uuid[:8]}...")
print(f" Current size: {entry['size']}")
try:
# Fetch document's docSchema
doc_response = self.session.get(f"https://eu.tectonic.remarkable.com/sync/v3/files/{doc_hash}")
doc_response.raise_for_status()
doc_content = doc_response.text
# Parse components and sum their sizes
lines = doc_content.strip().split('\n')
if len(lines) < 2:
print(f" ā Invalid docSchema - keeping original")
return entry['full_line']
total_component_size = 0
component_count = 0
for line in lines[1:]: # Skip version header
if ':' in line:
parts = line.split(':')
if len(parts) >= 5:
comp_size = int(parts[4])
total_component_size += comp_size
component_count += 1
# The correct size is the sum of all component sizes
correct_size = total_component_size
print(f" š¦ Components: {component_count}")
print(f" š Correct size: {correct_size}")
# Rebuild the line with correct size
parts = entry['full_line'].split(':')
parts[4] = str(correct_size) # Replace size field
fixed_line = ':'.join(parts)
print(f" ā
Fixed: {entry['size']} ā {correct_size}")
return fixed_line
except Exception as e:
print(f" ā Error fixing document: {e}")
print(f" ā ļø Keeping original line")
return entry['full_line']
def rebuild_corrected_root(self, categorized: Dict) -> str:
"""Rebuild root.docSchema with all entries (fixed sizes where needed)"""
print(f"\nšļø Rebuilding root.docSchema...")
# Start with ORIGINAL version (not "43"!)
lines = [categorized['original_version']]
# Add folders (unchanged)
for folder in categorized['folders']:
lines.append(folder['full_line'])
# Add good documents (unchanged)
for doc in categorized['good_entries']:
lines.append(doc['full_line'])
# Add fixed corrupted documents
for corrupted_doc in categorized['corrupted_entries']:
fixed_line = self.fix_corrupted_document(corrupted_doc)
lines.append(fixed_line)
# Add special entries (unchanged)
for special in categorized['special']:
lines.append(special['full_line'])
new_content = '\n'.join(lines)
print(f"\nā
Rebuilt root.docSchema:")
print(f" š Version: {categorized['original_version']} (preserved)")
print(f" š Total entries: {len(lines) - 1}")
print(f" š Folders: {len(categorized['folders'])}")
print(f" ā
Good documents: {len(categorized['good_entries'])}")
print(f" š§ Fixed documents: {len(categorized['corrupted_entries'])}")
print(f" ā Special entries: {len(categorized['special'])}")
print(f" š Content size: {len(new_content)} bytes")
return new_content
def preview_changes(self, dry_run: bool = True) -> bool:
"""Preview what changes will be made"""
print(f"\nš {'DRY RUN' if dry_run else 'LIVE RUN'} - Root DocSchema Repair")
print("=" * 60)
try:
# Get current state
root_content, current_hash, root_data = self.get_current_root_content()
print(f"š Current root.docSchema:")
print(f" Hash: {current_hash}")
print(f" Size: {len(root_content)} bytes")
# Identify corrupted entries
categorized = self.identify_corrupted_entries(root_content)
if len(categorized['corrupted_entries']) == 0:
print(f"\nā
No corrupted entries found - no changes needed!")
return True
# Build corrected version
corrected_content = self.rebuild_corrected_root(categorized)
# Save preview
preview_file = self.backup_dir / f"corrected_preview_{int(time.time())}.txt"
with open(preview_file, 'w') as f:
f.write(corrected_content)
print(f"š Preview saved to: {preview_file}")
if dry_run:
print(f"\nš DRY RUN COMPLETE - No changes made to server")
return True
# Upload corrected version
return self.upload_corrected_root(corrected_content)
except Exception as e:
print(f"ā Repair failed: {e}")
return False
def upload_corrected_root(self, corrected_content: str) -> bool:
"""Upload the corrected root.docSchema"""
print(f"\nā¬ļø Uploading corrected root.docSchema...")
try:
# Calculate new hash
new_hash = hashlib.sha256(corrected_content.encode()).hexdigest()
print(f" š New hash: {new_hash}")
# Upload content
upload_response = self.session.put(
f"https://eu.tectonic.remarkable.com/sync/v3/files/{new_hash}",
data=corrected_content.encode(),
headers={'Content-Type': 'text/plain'}
)
if upload_response.status_code in [200, 202]:
print(f" ā
Content uploaded ({upload_response.status_code})")
# Update root pointer
root_update_response = self.session.put(
"https://eu.tectonic.remarkable.com/sync/v4/root",
json={'hash': new_hash}
)
if root_update_response.status_code in [200, 202]:
print(f" ā
Root updated ({root_update_response.status_code})")
print(f" š REPAIR COMPLETED SUCCESSFULLY!")
return True
else:
print(f" ā Root update failed: {root_update_response.status_code}")
return False
else:
print(f" ā Content upload failed: {upload_response.status_code}")
return False
except Exception as e:
print(f" ā Upload failed: {e}")
return False
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
bases |
- | - |
Parameter Details
__init__: No parameters required. The constructor automatically authenticates with reMarkable cloud services, creates a backup directory for repair operations, and initializes the session for API communication.
Return Value
Instantiation returns a CorrectedRootDocSchemaRepair object with an authenticated session ready to perform repair operations. Key method returns: get_current_root_content() returns tuple of (content_string, hash_string, metadata_dict); identify_corrupted_entries() returns dict with categorized entries; fix_corrupted_document() returns corrected line string; rebuild_corrected_root() returns complete corrected content string; preview_changes() and upload_corrected_root() return boolean success status.
Class Interface
Methods
__init__(self) -> None
Purpose: Initialize the repair tool with authenticated session and setup backup directory
Returns: None - initializes instance with session, base_dir, and backup_dir attributes
get_current_root_content(self) -> Tuple[str, str, Dict]
Purpose: Fetch the current root.docSchema content and metadata from reMarkable cloud
Returns: Tuple containing (root_content_string, hash_string, root_metadata_dict) where content is the full docSchema text, hash is the current content hash, and metadata contains version and other root information
identify_corrupted_entries(self, root_content: str) -> Dict[str, List]
Purpose: Parse root.docSchema content and categorize entries into good, corrupted, folders, and special types based on size and type fields
Parameters:
root_content: The full text content of root.docSchema file with newline-separated entries
Returns: Dictionary with keys 'original_version', 'good_entries', 'corrupted_entries', 'folders', 'special' containing categorized entry dictionaries with fields: line_number, hash, uuid, type, size, full_line
fix_corrupted_document(self, entry: Dict) -> str
Purpose: Recalculate correct size for a corrupted document by fetching its docSchema and summing component sizes
Parameters:
entry: Dictionary containing document entry fields including 'hash', 'uuid', 'size', and 'full_line'
Returns: Corrected docSchema line string with recalculated size, or original line if repair fails
rebuild_corrected_root(self, categorized: Dict) -> str
Purpose: Reconstruct complete root.docSchema content with fixed sizes for corrupted entries while preserving all other entries
Parameters:
categorized: Dictionary from identify_corrupted_entries containing categorized entries and original version
Returns: Complete corrected root.docSchema content as newline-separated string with version header and all entries
preview_changes(self, dry_run: bool = True) -> bool
Purpose: Preview or execute the repair process, showing what changes will be made and optionally applying them
Parameters:
dry_run: If True, only preview changes without uploading; if False, apply changes to server
Returns: Boolean indicating success (True) or failure (False) of the preview/repair operation
upload_corrected_root(self, corrected_content: str) -> bool
Purpose: Upload the corrected root.docSchema content to reMarkable cloud and update the root pointer
Parameters:
corrected_content: The complete corrected root.docSchema content string to upload
Returns: Boolean indicating success (True) or failure (False) of the upload and root update operations
Attributes
| Name | Type | Description | Scope |
|---|---|---|---|
session |
requests.Session | Authenticated HTTP session for making API requests to reMarkable cloud services | instance |
base_dir |
Path | Path object pointing to the parent directory of the script file | instance |
backup_dir |
Path | Path object pointing to 'docschema_repair' subdirectory where backup and preview files are stored | instance |
Dependencies
requestspathlibtypingjsontimehashlib
Required Imports
import json
import time
import hashlib
from pathlib import Path
from typing import Dict, List, Tuple, Any
import requests
Conditional/Optional Imports
These imports are only needed under specific conditions:
from auth import RemarkableAuth
Condition: Required during __init__ to authenticate with reMarkable cloud services
Required (conditional)Usage Example
# Basic usage with dry run
repair_tool = CorrectedRootDocSchemaRepair()
# Preview changes without modifying server
success = repair_tool.preview_changes(dry_run=True)
# If preview looks good, apply changes
if success:
success = repair_tool.preview_changes(dry_run=False)
if success:
print('Repair completed successfully')
# Advanced usage: manual inspection
content, hash_val, metadata = repair_tool.get_current_root_content()
categorized = repair_tool.identify_corrupted_entries(content)
print(f'Found {len(categorized["corrupted_entries"])} corrupted entries')
# Build corrected version without uploading
corrected = repair_tool.rebuild_corrected_root(categorized)
Best Practices
- Always run preview_changes(dry_run=True) before applying actual changes to inspect what will be modified
- The tool automatically creates backups in the 'docschema_repair' directory - review these before and after repairs
- Ensure stable network connection as the tool makes multiple API calls to reMarkable cloud services
- The class preserves the original version number from root.docSchema - do not manually modify this
- Only documents with suspicious sizes (2247, 2246, 2715) are modified; folders and other entries remain unchanged
- If authentication fails during __init__, a RuntimeError is raised - handle this appropriately
- The repair process fetches individual document schemas to recalculate sizes - this may take time for many corrupted entries
- Review console output carefully as it provides detailed logging of each operation and categorization
- The tool uses SHA256 hashing to generate new content hashes - ensure hashlib is available
- Backup files are timestamped and stored locally for recovery if needed
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
class RootDocSchemaRepair 93.1% similar
-
function main_v64 74.4% similar
-
function repair_system 70.1% similar
-
class RootCleaner 67.7% similar
-
function main_v79 62.6% similar