WDP Part 9a: Catalog Format Specification
Defines the catalog file format for WDP. Specifies how diagnostic metadata is structured in JSON format for efficient distribution and client-side expansion.
Abstract#
This document defines the catalog file format for the Waddling Diagnostic Protocol (WDP). It specifies how diagnostic metadata is structured in JSON format for efficient distribution and client-side expansion. Catalogs map compact IDs to diagnostic metadata for all severity types (E, W, C, I, H).
Key Points:
- Two catalog types: Single-namespace (default) and Aggregated (multi-namespace)
- Three format variants per type: Full (development), Compact (production), Minimal (specialized)
- Hash algorithm fixed to xxHash64 with seed "wdp-v1" (no algorithm field needed)
- Field placeholders use double braces
{{field}}syntax - Namespace fields enable multi-service aggregation with collision-free IDs
- Catalogs are versioned, cacheable, and distributable via CDN
Conformance
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.
1. Introduction#
1.1 Purpose
WDP catalogs are JSON files that map compact IDs to diagnostic metadata. They enable:
- Efficient transmission - Send compact IDs instead of full messages
- Offline capability - Clients cache catalogs locally
- Multi-language support - Same compact IDs, different language catalogs
- Fast lookups - O(1) hash-based retrieval for both single and aggregated catalogs
- Namespace support - Collision-free aggregation of multiple services/libraries
1.2 Architecture
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Build Time โ
โ โโโโโโโโโโโโโโโโโโ โ
โ โ Error Registry โ โ
โ โ (Source Code) โ โ
โ โโโโโโโโโโฌโโโโโโโโ โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโ โ
โ โ Generate โ โ
โ โ Catalog JSON โ โ
โ โโโโโโโโโโฌโโโโโโโโ โ
โโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Distribution โ
โ โโโโโโโโโโโโโโโโโโ โ
โ โ catalog.json โ โ
โ โ (50KB) โ โ
โ โโโโโโโโโโฌโโโโโโโโ โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ CDN / Static File Server โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ1.3 Design Goals
- Minimal overhead: Keep catalog file size small
- Fast parsing: Simple JSON structure
- Flexible formats: Multiple formats for different use cases
- Versioned: Support catalog evolution
- Language-agnostic: Pure JSON, no language-specific features
2. Catalog Purpose and Use Cases#
2.1 Primary Use Cases
Use Case 1: IoT Devices
Problem: Constrained bandwidth, battery, storage
Solution:
Sensor โ {"xY9Kp":{"f":{"temp":"45.2"}}} โ Gateway
Gateway expands using catalog:
"Temperature 45.2ยฐC exceeds threshold"Benefits: Efficient transmission, minimal battery usage, local catalog caching on gateway
Use Case 2: Mobile Applications
Problem: Slow/expensive mobile networks, offline scenarios
Solution:
1. App downloads catalog once (cached locally)
2. API returns compact diagnostics
3. App expands diagnostics locally (works offline)Benefits: Fast API responses, works offline, supports multiple languages
Use Case 3: Microservices Architecture
Problem: High-volume logging across distributed services
Solution:
Service A logs: [xY9Kp] Auth failure
Service B logs: [xY9Kp] Auth failure
Service C logs: [xY9Kp] Auth failure
Centralized logging searches by compact ID
Aggregates all instances of same errorBenefits: Compact log entries, easy aggregation, centralized analysis
Use Case 4: Multi-Language Applications
Problem: Supporting multiple languages efficiently
Solution:
Backend โ {"xY9Kp":{"f":{"timestamp":"2024-01-15"}}}
English client: "Token expired at 2024-01-15"
Spanish client: "Token expirรณ el 2024-01-15"
Japanese client: "ใใผใฏใณใฎๆๅนๆ้ใๅใใพใใ 2024-01-15"Benefits: Same compact ID for all languages, clients download appropriate catalog
2.2 Non-Goals
WDP catalogs are NOT intended for:
- Authentication/Authorization - Compact IDs are not cryptographic tokens
- Real-time catalog updates - Catalogs are versioned artifacts, not live config
- Custom business logic - Catalogs store metadata, not executable code
- Large binary data - Catalogs should be small (< 500KB recommended)
3. Catalog Types#
WDP defines two catalog types based on scope. Each type can use any of the three format variants (Full, Compact, Minimal).
3.1 Single-Namespace Catalog
Purpose: Default catalog type for most clients
Characteristics:
- Keys in
diagsMUST be CompactID format (5 alphanumeric characters) - Represents errors from a single service, library, or application
- MAY include optional
namespaceandnamespace_hashfields - MUST NOT include
namespacesindex field - MUST NOT use CombinedID format in keys
When to use:
- Mobile applications (single backend)
- Web applications (single API)
- Individual microservices
- IoT devices (most cases)
- Single library/SDK
Basic Structure:
{
"version": "1.0.0",
"diags": {
"81E9g": { ... },
"xY9Kp": { ... }
}
}With Optional Namespace Metadata:
{
"version": "1.0.0",
"namespace": "auth_service",
"namespace_hash": "h4tYw2",
"diags": {
"81E9g": { ... },
"xY9Kp": { ... }
}
}Key Format: ^[A-Za-z0-9]{5}$
3.2 Aggregated Catalog
Purpose: Catalog combining multiple namespaces
Characteristics:
- Keys in
diagsMUST be CombinedID format (<NamespaceHash>-<CompactID>) - Represents errors from multiple services, libraries, or sources
- MAY include
namespacesindex mapping names to hashes - MUST NOT include top-level
namespaceornamespace_hashfields
When to use:
- Monitoring dashboards (multiple services)
- Edge gateways (multiple devices)
- Log aggregators (multiple sources)
- SDK bundles (library + dependencies)
- API gateways/BFFs
Basic Structure (Privacy-Preserving):
{
"version": "1.0.0",
"diags": {
"h4tYw2-81E9g": { ... },
"k9Px3a-xY9Kp": { ... }
}
}With Namespaces Index (Human-Readable):
{
"version": "1.0.0",
"namespaces": {
"auth_service": "h4tYw2",
"payment_service": "k9Px3a"
},
"diags": {
"h4tYw2-81E9g": { ... },
"k9Px3a-xY9Kp": { ... }
}
}Key Format: ^[A-Za-z0-9]{5}-[A-Za-z0-9]{5}$
3.3 Choosing Catalog Type
Decision Tree:
Does client receive errors from multiple services/libraries?
โโ NO โ Use Single-Namespace Catalog
โโ YES โ Use Aggregated Catalog
โโ Need human-readable names? โ Include namespaces index
โโ Privacy-sensitive? โ Omit namespaces index3.4 Design Rationale: Flat Structure
Why use CombinedID keys instead of nested namespace objects?
The flat structure with CombinedID keys was chosen over nested structures for these critical reasons:
Performance
- O(1) lookup: Direct key access without parsing or navigation
- No nested iteration: Single hash map lookup regardless of namespace count
- Minimal overhead: Only 6 additional characters per key
Implementation Simplicity
- Uniform lookup pattern: Both catalog types use identical access:
catalog.diags[id] - Consistent client code: Same lookup logic regardless of catalog type
- Easy validation: Single key format check across all entries
Aggregation Benefits
- Trivial merging: Concatenate
diagsobjects directly - No restructuring: Source catalogs preserve structure
- Build-time efficiency: Simple key transformation
4. Catalog Format Variants#
Each catalog type (Single-Namespace or Aggregated) can use any of three format variants.
4.1 Full Format
Purpose: Development, debugging, documentation
Characteristics:
- All metadata fields included
- Human-readable field names
- Complete documentation
When to use: Development environments, API documentation, error reference guides
{
"version": "1.0.0",
"generated": "2024-01-15T10:30:00Z",
"diags": {
"xY9Kp": {
"code": "E.AUTH.TOKEN.EXPIRED",
"severity": "E",
"message": "Token expired at {{timestamp}}",
"description": "The JWT token has exceeded its time-to-live (TTL).",
"hints": [
"Use /auth/refresh endpoint with refresh token",
"Check token expiration time (exp claim)"
],
"tags": ["auth", "security", "jwt"],
"fields": ["timestamp"]
}
}
}4.2 Compact Format
Purpose: Production, network transmission
Characteristics:
- Abbreviated field names (1-2 chars)
- Essential fields only
- Optimized for network transmission
When to use: Production web applications, mobile apps, API responses
Field Mapping:
vโversiongโgeneratedwdโdiagscโcodesโseveritymโmessagedโdescriptionhโhintstโtagsfโfields
{
"v": "1.0.0",
"g": "2024-01-15T10:30:00Z",
"wd": {
"xY9Kp": {
"c": "E.AUTH.TOKEN.EXPIRED",
"s": "E",
"m": "Token expired at {{timestamp}}",
"d": "The JWT token has exceeded its TTL.",
"h": ["Use /auth/refresh endpoint"],
"t": ["auth", "jwt"],
"f": ["timestamp"]
}
}
}4.3 Minimal Format
Purpose: Extremely constrained environments (IoT, embedded)
Characteristics:
- Array-based, no field names
- Only code and message
- Minimalist structure
When to use: IoT devices with storage constraints, embedded systems
{
"jGKFp": ["E.AUTH.TOKEN.001", "Token missing from Authorization header"],
"xY9Kp": ["E.AUTH.TOKEN.EXPIRED", "Token expired at {{timestamp}}"],
"mN3Yr": ["W.DATABASE.CONNECTION.027", "Database pool near capacity ({{current}}/{{max}})"]
}Array Order: [0] = code (REQUIRED), [1] = message (REQUIRED)
4.4 Format Selection Guide
Recommendation: Start with Compact format for most production applications. Use Full format for documentation and development. Reserve Minimal for truly constrained environments.
5. Field Specifications#
5.1 Top-Level Fields
Note: The hash algorithm for compact IDs is fixed to xxHash64 with seed "wdp-v1" as specified in Part 5. This is immutable for WDP v1 and does not need to be included in catalog files.
5.2 Namespace Fields
These fields enable single-namespace documentation and multi-namespace aggregation.
namespace (OPTIONAL)
- Type: String
- Pattern:
^[a-z][a-z0-9_]{0,31}$ - Example:
"auth_service","payment_lib" - Purpose: Human-readable namespace name for single-namespace catalogs
Requirements:
- MAY be included in single-namespace catalogs for documentation
- MUST NOT be included in aggregated catalogs
- MUST start with lowercase letter
- MUST be 1-32 characters long
namespace_hash (OPTIONAL)
- Type: String
- Pattern:
^[A-Za-z0-9]{5}$ - Example:
"h4tYw2","k9Px3a" - Purpose: Stable hash for verification and cross-reference
Requirements:
- MAY be included alongside
namespace - MUST NOT be included in aggregated catalogs
- Hash MUST be generated using xxHash64 with seed "wdp-ns-v1"
namespaces (OPTIONAL)
- Type: Object (hash map)
- Keys: Namespace strings
- Values: 5-character Base62 namespace hashes
- Example:
{"auth_service": "h4tYw2", "payment_lib": "k9Px3a"} - Purpose: Human-readable index for aggregated catalogs
5.3 Core Catalog Fields
version (REQUIRED)
- Type: String
- Format: Semantic version (MAJOR.MINOR.PATCH)
- Example:
"1.0.0","2.3.1" - Purpose: Catalog version for change tracking and cache invalidation
generated (OPTIONAL)
- Type: String
- Format: ISO 8601 timestamp
- Example:
"2024-01-15T10:30:00Z" - Purpose: When catalog was generated
diags (REQUIRED)
- Type: Object (hash map)
- Keys: CompactID or CombinedID (depends on catalog type)
- Values: Diagnostic metadata objects
- Purpose: Main catalog data structure containing all diagnostics
Key Format Rules:
- Single-Namespace: Keys MUST be CompactID format (
^[A-Za-z0-9]{5}$) - Aggregated: Keys MUST be CombinedID format (
^[A-Za-z0-9]{5}-[A-Za-z0-9]{5}$) - MUST NOT mix formats within same catalog
5.4 Diagnostic Metadata Fields
severity (REQUIRED)
5.5 Field Requirements by Format
6. Validation#
Catalogs MUST be validated to ensure they conform to either single-namespace or aggregated patterns.
6.1 Rule 1: Key Format Consistency
MUST NOT mix CompactID and CombinedID formats:
def validate_key_consistency(diags):
has_hyphen = any('-' in key for key in diags.keys())
no_hyphen = all('-' not in key for key in diags.keys())
if not (has_hyphen or no_hyphen):
raise ValidationError("Cannot mix CompactID and CombinedID formats")
if has_hyphen:
# All keys must be CombinedID (11 chars with hyphen)
for key in diags.keys():
if not re.match(r'^[A-Za-z0-9]{5}-[A-Za-z0-9]{5}$', key):
raise ValidationError(f"Invalid CombinedID format: {key}")
else:
# All keys must be CompactID (5 chars)
for key in diags.keys():
if not re.match(r'^[A-Za-z0-9]{5}$', key):
raise ValidationError(f"Invalid CompactID format: {key}")Examples:
// โ
Valid: All CompactID
{
"diags": {
"81E9g": {...},
"xY9Kp": {...}
}
}
// โ
Valid: All CombinedID
{
"diags": {
"h4tYw2-81E9g": {...},
"k9Px3a-xY9Kp": {...}
}
}
// โ Invalid: Mixed formats
{
"diags": {
"81E9g": {...}, // CompactID
"h4tYw2-xY9Kp": {...} // CombinedID - ERROR!
}
}6.2 Rule 2: Namespace Field Constraints
Single-Namespace Catalogs (CompactID keys):
- MAY include
namespacefield - MAY include
namespace_hashfield - MUST NOT include
namespacesfield
Aggregated Catalogs (CombinedID keys):
- MUST NOT include
namespacefield - MUST NOT include
namespace_hashfield - MAY include
namespacesfield
6.3 Structural Validation
Valid JSON
Top-level is object
Required fields present (version, diags)
Compact IDs match expected format (5 or 11 chars)
Diagnostic entries have required fields
Namespace fields follow constraints6.4 Semantic Validation
Version follows semver
CompactIDs are Base62 (5 chars)
CombinedIDs are Base62-Base62 (11 chars with hyphen)
Codes match WDP format
Severity matches code prefix
Field placeholders match fields list
Namespace fields consistent with key format6.5 Compatibility Checking
function isCompatible(catalogVersion, clientVersion) {
const catMajor = parseInt(catalogVersion.split('.')[0]);
const catMinor = parseInt(catalogVersion.split('.')[1]);
const cliMajor = parseInt(clientVersion.split('.')[0]);
const cliMinor = parseInt(clientVersion.split('.')[1]);
// Major versions must match
if (catMajor !== cliMajor) return false;
// Client minor must be >= catalog minor
return cliMinor >= catMinor;
}
// Examples:
isCompatible("1.2.0", "1.3.0") // true
isCompatible("1.3.0", "1.2.0") // false: client too old
isCompatible("2.0.0", "1.9.0") // false: major mismatch7. Catalog Distribution#
7.1 Distribution Strategies
Strategy 1: Static File Hosting (RECOMMENDED)
Host catalog as static file on CDN:
https://cdn.example.com/catalogs/v1.0.0/catalog.json
https://cdn.example.com/catalogs/v1.0.0/catalog-compact.json
https://cdn.example.com/catalogs/v1.0.0/catalog-minimal.jsonBenefits: Fast global distribution, built-in caching, high availability, low cost
Best Practices:
- Use versioned URLs
- Set long cache headers (365 days)
- Enable gzip/brotli compression
- Use HTTPS
- Enable CORS for browser clients
HTTP Headers:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Cache-Control: public, max-age=31536000, immutable
Content-Encoding: gzip
Access-Control-Allow-Origin: *
ETag: "abc123"Strategy 2: API Endpoint
Serve catalog via versioned API:
GET /api/v1/catalog
GET /api/v1/catalog?format=compact
GET /api/v1/catalog?version=1.2.0Strategy 3: Bundled with Application
Bundle catalog directly in application:
/assets/catalog.json
/public/catalog.jsonWhen to use: Small catalogs (< 50KB), infrequent changes, offline-first apps
7.2 Versioning Strategy
Use semantic versioning for catalogs:
MAJOR.MINOR.PATCH
1.0.0 โ Initial release
1.0.1 โ Fix typo in message
1.1.0 โ Add new errors
2.0.0 โ Breaking change (remove errors, change format)Rules:
- PATCH: Bug fixes, typo corrections, no new errors
- MINOR: New errors added, backward compatible
- MAJOR: Breaking changes (removed errors, format changes)
7.3 Caching Recommendations
Client-Side Caching
// Service worker caching
cache.put('catalog.json', response);
// LocalStorage for metadata
localStorage.setItem('catalog_version', '1.0.0');
localStorage.setItem('catalog_updated', Date.now());Update Strategy:
1. Check current version
2. Fetch latest version metadata
3. If newer:
a. Download in background
b. Validate catalog
c. Swap atomically
4. If same:
a. Continue using cached7.4 Compression
Recommended Compression:
Gzip: 50-60% size reduction
Brotli: 55-65% size reduction (better)Example Sizes:
catalog.json 150 KB
catalog.json.gz 60 KB (60% reduction)
catalog.json.br 50 KB (67% reduction)7.5 Aggregation Strategies
Strategy 1: Build-Time Aggregation
def aggregate_catalogs(catalogs_list):
aggregated = {
"version": "1.0.0",
"namespaces": {},
"diags": {}
}
for catalog in catalogs_list:
namespace = catalog.get('namespace', 'unknown')
namespace_hash = catalog.get('namespace_hash')
if not namespace_hash:
namespace_hash = generate_namespace_hash(namespace)
# Add to namespaces index
aggregated['namespaces'][namespace] = namespace_hash
# Transform keys from CompactID to CombinedID
for compact_id, diag in catalog['diags'].items():
combined_id = f"{namespace_hash}-{compact_id}"
aggregated['diags'][combined_id] = diag
return aggregatedStrategy 2: Runtime Aggregation
class CatalogAggregator {
private catalogs: Map<string, Catalog> = new Map();
async loadCatalog(namespace: string, url: string) {
const catalog = await fetch(url).then(r => r.json());
this.catalogs.set(namespace, catalog);
}
lookup(combinedId: string): DiagEntry | null {
const [nsHash, compactId] = combinedId.split('-');
for (const [ns, catalog] of this.catalogs) {
if (catalog.namespace_hash === nsHash) {
return catalog.diags[compactId];
}
}
return null;
}
}Strategy 3: Manifest-Based
{
"version": "1.0.0",
"catalogs": [
{
"namespace": "auth_service",
"namespace_hash": "h4tYw2",
"url": "/catalogs/auth_service-v1.0.0.json"
},
{
"namespace": "payment_service",
"namespace_hash": "k9Px3a",
"url": "/catalogs/payment_service-v1.0.0.json"
}
]
}Appendix A: Complete Examples#
A.1 Full Format Example
{
"version": "1.0.0",
"generated": "2024-01-15T10:30:00Z",
"diags": {
"jGKFp": {
"code": "E.AUTH.TOKEN.001",
"severity": "E",
"message": "Token missing from Authorization header",
"description": "The JWT token was not provided in the request.",
"hints": [
"Include header: Authorization: Bearer <token>",
"Obtain token from /auth/login endpoint"
],
"tags": ["auth", "security", "http"],
"fields": []
},
"xY9Kp": {
"code": "E.AUTH.TOKEN.EXPIRED",
"severity": "E",
"message": "Token expired at {{timestamp}}",
"description": "The JWT token has exceeded its TTL.",
"hints": [
"Use /auth/refresh endpoint with refresh token",
"Check token expiration time (exp claim)"
],
"tags": ["auth", "security", "jwt"],
"fields": ["timestamp"]
},
"mN3Yr": {
"code": "W.DATABASE.CONNECTION.027",
"severity": "W",
"message": "Database connection pool near capacity ({{current}}/{{max}})",
"description": "The connection pool is at 80% capacity.",
"hints": ["Monitor connection pool metrics", "Consider increasing pool size"],
"tags": ["database", "performance", "monitoring"],
"fields": ["current", "max"]
},
"cP9Wm": {
"code": "C.DISK.SPACE.CRITICAL",
"severity": "C",
"message": "Critical: Disk usage at {{usage}}% on {{mount_point}}",
"description": "Disk space is critically low.",
"hints": ["Free up disk space immediately", "Check for large log files"],
"tags": ["disk", "critical", "infrastructure"],
"fields": ["usage", "mount_point"]
},
"hK3Qn": {
"code": "H.API.RATE.LIMIT",
"severity": "H",
"message": "Rate limit: {{remaining}} requests remaining",
"description": "You are approaching your rate limit.",
"hints": ["Implement exponential backoff", "Cache responses when possible"],
"tags": ["api", "rate-limit", "help"],
"fields": ["remaining"]
}
}
}A.2 Compact Format Example
{
"v": "1.0.0",
"g": "2024-01-15T10:30:00Z",
"wd": {
"jGKFp": {
"c": "E.AUTH.TOKEN.001",
"s": "E",
"m": "Token missing from Authorization header",
"d": "The JWT token was not provided in the request.",
"h": ["Include header: Authorization: Bearer <token>"],
"t": ["auth", "security"],
"f": []
},
"xY9Kp": {
"c": "E.AUTH.TOKEN.EXPIRED",
"s": "E",
"m": "Token expired at {{timestamp}}",
"d": "The JWT token has exceeded its TTL.",
"h": ["Use /auth/refresh endpoint"],
"t": ["auth", "jwt"],
"f": ["timestamp"]
}
}
}A.3 Minimal Format Example
{
"jGKFp": ["E.AUTH.TOKEN.001", "Token missing from Authorization header"],
"xY9Kp": ["E.AUTH.TOKEN.EXPIRED", "Token expired at {{timestamp}}"],
"mN3Yr": ["W.DATABASE.CONNECTION.027", "Database pool near capacity ({{current}}/{{max}})"],
"cP9Wm": ["C.DISK.SPACE.CRITICAL", "Critical: Disk at {{usage}}% on {{mount_point}}"],
"hK3Qn": ["H.API.RATE.LIMIT", "Rate limit: {{remaining}} requests remaining"]
}Appendix B: JSON Schema#
B.1 Full Format Schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://waddling.dev/schemas/catalog-full.json",
"title": "WDP Full Catalog Format",
"type": "object",
"required": ["version", "diags"],
"additionalProperties": false,
"properties": {
"version": {
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+$"
},
"generated": {
"type": "string",
"format": "date-time"
},
"diags": {
"type": "object",
"patternProperties": {
"^[0-9A-Za-z]{5}$": {
"$ref": "#/definitions/diagEntry"
}
}
}
},
"definitions": {
"diagEntry": {
"type": "object",
"required": ["code", "severity", "message"],
"properties": {
"code": {
"type": "string",
"pattern": "^[EWCIH]\\.[A-Z]"
},
"severity": {
"type": "string",
"enum": ["E", "W", "C", "I", "H"]
},
"message": { "type": "string" },
"description": { "type": "string" },
"hints": { "type": "array", "items": { "type": "string" } },
"tags": { "type": "array", "items": { "type": "string" } },
"fields": { "type": "array", "items": { "type": "string" } }
}
}
}
}References#
- JSON - JavaScript Object Notation
- RFC 8259 - JSON specification
- ISO 8601 - Date/time format
- Semantic Versioning - Version numbering (semver.org)
- RFC 2119 - Requirement keywords
Related Specifications:
- Part 9b: Wire Protocol - Transmission format
- Part 9c: Implementation - Code examples
- Part 5: Compact IDs - Hash generation
- Part 7: Namespaces - Namespace hashing