Stable Identifiers

One of Calor's most distinctive features is embedding unique identifiers directly into the language syntax. This document explains why this matters, what challenges it creates, and how Calor overcomes them.


The Problem: Code Identity is Fragile

Traditional programming relies on names and locations to identify code:

C#
// How do you reference this function?
public static int Calculate(int x) => x * 2;  // Line 42 in Calculator.cs

This creates fundamental problems:

Reference MethodFailure Mode
File + line numberBreaks when any line above changes
Function nameBreaks on rename, ambiguous with overloads
File + function nameBreaks on file moves or renames
Hash of contentChanges on any modification

For AI agents that need to track, reference, and modify code across development workflows, these fragile identities create real problems:

  • Lost context - Agent references become stale after refactoring
  • Merge conflicts - Parallel branches create identity collisions
  • Imprecise edits - "Edit the calculate function" is ambiguous
  • Broken traceability - Can't track an entity through its history

The Solution: Semantic Identity in Syntax

Calor assigns every declaration a unique ID that represents semantic identity, not name or location:

Plain Text
§F{f_01J5X7K9M2NPQRSTABWXYZ12:Calculate:pub}
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   This ID survives ANY refactoring
  §I{i32:x}
  §O{i32}
  §R (* x 2)
§/F{f_01J5X7K9M2NPQRSTABWXYZ12}

The ID f_01J5X7K9M2NPQRSTABWXYZ12:

  • Survives renaming (CalculateCompute)
  • Survives moving to a different file
  • Survives reformatting and refactoring
  • Is globally unique across all codebases (ULID)
  • Can be referenced unambiguously forever

Benefits of Language-Level IDs

1. Agent Instructions Become Precise

Without IDs:

Plain Text
"Update the validate function in the user module to check email format"
  • Which validate function? There might be multiple
  • What if it was renamed to validateUser?
  • What if the file was moved?

With IDs:

Plain Text
"Update function f_01J5X7K9M2NPQRSTABWXYZ12 to check email format"
  • Unambiguous target
  • Survives any refactoring
  • Machine-verifiable reference

2. Merge Safety Across Branches

Traditional code suffers from merge conflicts when parallel branches modify the same entities. With ULIDs:

Branch ABranch BResult
Adds f_01ABC...Adds f_01DEF...Clean merge
Modifies f_01ABC...Renames f_01ABC...Clean merge
Both add unnamed functionConflictN/A in Calor

ULID's 80-bit random component makes collisions statistically impossible (~10^-24 probability per pair).

3. Round-Trip Stability

Code generation and conversion preserve identity:

Plain Text
// Original Calor
§F{f_01ABC:Add:pub}
  §O{i32}
  §R (+ a b)
§/F{f_01ABC}
C#
// Generated C# preserves ID
[CalorId("f_01ABC")]
public static int Add(int a, int b) => a + b;
Plain Text
// Re-converted: Same ID
§F{f_01ABC:Add:pub}
  §O{i32}
  §R (+ a b)
§/F{f_01ABC}

4. Traceable History

IDs enable tracking entities through their entire lifecycle:

Plain Text
f_01J5X7... created in commit a1b2c3 (Juan, 2024-01-15)
f_01J5X7... renamed Calculate→Compute in commit d4e5f6 (AI Agent, 2024-02-20)
f_01J5X7... moved to utils.calr in commit g7h8i9 (Maria, 2024-03-10)
f_01J5X7... implementation updated in commit j0k1l2 (AI Agent, 2024-04-05)

The entity's history is continuous regardless of name or location changes.


The Challenges

Embedding IDs in code creates real challenges. Here's how Calor addresses each:

Challenge 1: ID Generation

Problem: Who generates IDs? When? How to ensure uniqueness?

Solution: ULID (Universally Unique Lexicographically Sortable Identifier)

  • Timestamp + Random: 48-bit timestamp + 80-bit random = unique without coordination
  • No central registry: Any machine can generate IDs independently
  • Sortable: IDs sort chronologically by creation time
  • CLI tooling: calor ids assign generates IDs automatically
Bash
# Generate IDs for new declarations
calor ids assign .

# Preview what would be assigned
calor ids assign . --dry-run

Challenge 2: ID Churn

Problem: Agents might accidentally change IDs during edits, breaking references.

Solution: Multi-layer protection

  1. Hook validation: Pre-write hooks detect ID modifications
  2. Agent rules: Skills explicitly forbid ID modification
  3. CI validation: calor ids check fails builds with ID issues

Challenge 3: Duplicate IDs

Problem: Copy-paste or extraction might create duplicate IDs.

Solution: Detection and automatic resolution

Bash
# Detect duplicates
calor ids check .
# Error Calor0803: Duplicate ID 'f_01ABC...'

# Fix duplicates (keep first, reassign others)
calor ids assign . --fix-duplicates

Challenge 4: Visual Noise

Problem: IDs add visual clutter to code.

Solution: IDs are for machines, not humans

  1. Agents are the primary audience: Calor optimizes for machine readability
  2. IDE support (roadmap): Future tooling can hide IDs in display
  3. Test IDs for docs: Short IDs (f001) allowed in tests/docs/examples
Plain Text
// Production code: Full ULID
§F{f_01J5X7K9M2NPQRSTABWXYZ12:Calculate:pub}

// Documentation: Readable test ID
§F{f001:Calculate:pub}

Challenge 5: New Developers

Problem: Developers unfamiliar with IDs might create invalid ones.

Solution: Omit IDs, let tooling assign them

Plain Text
// Developer writes (no ID):
§F{:NewFunction:pub}
  §O{void}
§/F{}

// After `calor ids assign`:
§F{f_01NEW...:NewFunction:pub}
  §O{void}
§/F{f_01NEW...}

The tooling handles the complexity; developers just write code.


Why This Matters for AI-First Development

Traditional languages assume humans are the primary code authors. When AI agents become primary authors, different tradeoffs make sense.

Human-FirstAI-First
Names are primary identifiersNames are documentation
Location mattersIdentity is intrinsic
Minimize syntaxMaximize precision
Trust implicit conventionsRequire explicit contracts

Calor's stable identifiers are part of a broader shift toward explicit, machine-verifiable code that agents can reliably understand, reference, and modify.


ID Format

Production IDs use ULID with kind prefix:

KindPrefixExample
Modulem_m_01J5X7K9M2NPQRSTABWXYZ12
Functionf_f_01J5X7K9M2NPQRSTABWXYZ12
Classc_c_01J5X7K9M2NPQRSTABWXYZ12
Interfacei_i_01J5X7K9M2NPQRSTABWXYZ12
Methodmt_mt_01J5X7K9M2NPQRSTABWXYZ12
Propertyp_p_01J5X7K9M2NPQRSTABWXYZ12
Constructorctor_ctor_01J5X7K9M2NPQRSTABWXYZ12
Enume_e_01J5X7K9M2NPQRSTABWXYZ12

Preservation Rules

OperationID Behavior
RenamePreserved
Move filePreserved
ReformatPreserved
Change implementationPreserved
Extract helperNew ID for helper
Copy codeNew ID required

Next