| name | color-envelope-preserving |
| description | GF(3) color envelope preservation across navigator compositions |
| source | Gay.jl, SplitMix64 determinism, color topology |
| license | MIT |
| trit | 1 |
| gf3_triad | möbius-path-filtering (-1) ⊗ specter-navigator-gadget (0) ⊗ color-envelope-preserving (+1) |
| status | Production Ready |
Color Envelope Preserving
Core Concept
Every navigation path carries a color envelope - a GF(3) ternary assignment that propagates through the path composition. This skill ensures that composed Navigators maintain color conservation (the envelope sums to 0 mod 3) across all compositions.
GF(3) Color Trits:
- -1 (Red/MINUS) - Conservative/filtering paths
- 0 (Green/ERGODIC) - Neutral/structural paths
- +1 (Blue/PLUS) - Generative/enriching paths
The envelope invariant: Any valid Navigator composition must have trits that sum to 0 (mod 3).
Why Color Envelopes?
Determinism Through Color
Every navigation operation is seeded with a color value. Same color seed → same traversal order → same results every time.
# With SplitMix64 seeding from color
nav = @late_nav([ALL, pred(iseven)])
↓ (color=-1)
deterministic traversal order
Conservation Law
When two Navigators compose:
nav1 = @late_nav([ALL, pred(f)]) # trit = -1
nav2 = @late_nav([keypath("x")]) # trit = 0
nav_composed = compose_navigators(nav1, nav2)
# Check: (-1) + 0 = -1 ≠ 0
# => INVALID! Cannot compose these Navigators.
A valid composition requires a third Navigator to balance:
nav3 = @late_nav([keypath("y")]) # trit = +1
# Check: (-1) + 0 + (+1) = 0 ✓
# => VALID! Complete GF(3) triad.
Architecture
Color Assignment Algorithm
Each Navigator's trit is determined by its semantic role:
| Path Type | Trit | Justification |
|---|---|---|
[ALL] |
-1 | Expands cardinality (conservative gate) |
[pred(f)] |
-1 | Filters/restricts domain |
[keypath(k)] |
0 | Neutral structural access |
[INDEX(i)] |
0 | Direct indexing (no change) |
[APPEND(x)] |
+1 | Adds value (generative) |
[TRANSFORM(f)] |
+1 | Enriches/generates new form |
| Composition of above | Sum of trits | Trits compose additively |
Color Propagation
Input structure (color = c_in)
↓
Apply Navigator with trit = t_nav
↓
Output structure (color = c_in + t_nav mod 3)
↓
Apply next Navigator with trit = t_nav2
↓
Final color = c_in + t_nav + t_nav2 mod 3
Envelope Invariant Checker
function verify_envelope(navigator_chain::Vector{Navigator})
total_trit = sum(nav.trit for nav in navigator_chain) % 3
return total_trit == 0 # Valid if sums to 0 mod 3
end
API
Color Assignment
assign_trit(navigator::Navigator) :: Int
Determines the GF(3) trit for a Navigator.
nav = @late_nav([ALL, pred(f)])
trit = assign_trit(nav) # => -1 (filtering/expansion)
nav = @late_nav([keypath("x")])
trit = assign_trit(nav) # => 0 (structural)
nav = @late_nav([APPEND(value)])
trit = assign_trit(nav) # => +1 (generative)
color_seed(navigator::Navigator) :: UInt64
Generates a deterministic SplitMix64 seed from the Navigator's trit and structure.
nav = @late_nav([ALL, pred(iseven)])
seed = color_seed(nav) # => UInt64 derived from trit=-1, hash(path)
# Same Navigator always produces same seed
seed2 = color_seed(nav)
@assert seed == seed2 # ✓
Envelope Verification
verify_envelope(navs::Vector{Navigator}) :: Bool
Checks if a chain of Navigators maintains color conservation.
nav1 = @late_nav([ALL, pred(f)]) # trit = -1
nav2 = @late_nav([keypath("x")]) # trit = 0
nav3 = @late_nav([TRANSFORM(g)]) # trit = +1
verify_envelope([nav1, nav2, nav3]) # => true ((-1) + 0 + (+1) = 0 ✓)
verify_envelope([nav1, nav2]) # => false ((-1) + 0 = -1 ≠ 0)
complete_triad(nav1, nav2) :: Navigator
Given two Navigators, generates the third Navigator that completes the GF(3) triad.
nav1 = @late_nav([ALL, pred(f)]) # trit = -1
nav2 = @late_nav([keypath("x")]) # trit = 0
nav3 = complete_triad(nav1, nav2)
# => Navigator with trit = +1 (auto-generated)
verify_envelope([nav1, nav2, nav3]) # => true ✓
Deterministic Seeding
deterministic_select(nav, structure) :: Vector
Performs nav_select with color-seeded determinism guarantee.
nav = @late_nav([ALL, pred(iseven)])
results1 = deterministic_select(nav, [1,2,3,4,5,6])
results2 = deterministic_select(nav, [1,2,3,4,5,6])
@assert results1 == results2 # Always identical ✓
with_color_context(nav, color::Int) :: Function
Executes a Navigator selection with explicit color context.
nav = @late_nav([ALL, pred(iseven)])
# Force execution with color = +1
results = with_color_context(nav, +1) do
nav_select(nav, [1,2,3,4,5,6], x -> [x])
end
Integration with Inline Caching
The cache key for a Navigator includes both the path expression AND the color envelope:
cache_key = hash((path_expr, trit))
# => Different cache entries for nav with trit=-1 vs trit=+1
This ensures:
- Same path, different color → different cached Navigators
- Different behavior per color context → deterministic separation
- No color-mixing bugs → invalid color compositions are caught early
Composition Guarantees
When Navigators compose:
function compose_navigators(nav1, nav2)
# Check envelope conservation
combined_trit = (nav1.trit + nav2.trit) % 3
if combined_trit != 0
throw(EnvelopeViolationError(
"Cannot compose: $(nav1.trit) + $(nav2.trit) = $combined_trit ≠ 0"
))
end
# Composition is valid only if a third Navigator exists
return compose_with_witness(nav1, nav2) # Uses complete_triad internally
end
Color as First-Class Data
Colors are not metadata - they're part of the Navigator's identity:
nav_minus = @late_nav([ALL, pred(f)]) # trit = -1
nav_zero = @late_nav([keypath("x")]) # trit = 0
nav_plus = @late_nav([TRANSFORM(g)]) # trit = +1
# These are three distinct Navigators despite similar paths
@assert nav_minus.id != nav_zero.id
@assert nav_zero.id != nav_plus.id
Practical Example: Complex Transformation
# Step 1: Filter (trit = -1)
nav_filter = @late_nav([ALL, pred(x -> x > 5)])
# Step 2: Navigate structure (trit = 0)
nav_nav = @late_nav([keypath("results")])
# Step 3: Enrich with metadata (trit = +1)
nav_enrich = @late_nav([APPEND_CONTEXT(timestamp, hash)])
# Verify composition
@assert (-1) + 0 + (+1) == 0 % 3 # ✓
# Execute with guaranteed determinism
data = Dict("results" => [1,3,5,7,9])
result = compose_navigators(nav_filter, nav_nav, nav_enrich)
|> x -> nav_select(x, data, process)
Performance
| Operation | Complexity | Notes |
|---|---|---|
assign_trit() |
O(1) | Trit precomputed during parsing |
verify_envelope() |
O(n) | n = number of Navigators in chain |
color_seed() |
O(1) | Hash-based seed generation |
| No runtime overhead | - | All checks happen at compile-time/caching |
Related Skills
- specter-navigator-gadget - Uses color envelopes for determinism
- möbius-path-filtering - Works alongside color constraints
- gay-mcp - Provides underlying SplitMix64 color generation
- spi-parallel-verify - Verifies color conservation under parallelism
Envelope Violation Examples
# ❌ INVALID: Composing two -1 trits
nav1 = @late_nav([ALL, pred(f)]) # -1
nav2 = @late_nav([ALL, pred(g)]) # -1
compose_navigators(nav1, nav2)
# => EnvelopeViolationError("(-1) + (-1) = -2 ≠ 0 mod 3")
# ❌ INVALID: Composing +1 and +1
nav3 = @late_nav([APPEND(x)]) # +1
nav4 = @late_nav([APPEND(y)]) # +1
compose_navigators(nav3, nav4)
# => EnvelopeViolationError("(+1) + (+1) = 2 ≠ 0 mod 3")
# ✓ VALID: Balanced triad
nav_minus = @late_nav([ALL, pred(f)]) # -1
nav_zero = @late_nav([keypath("x")]) # 0
nav_plus = @late_nav([APPEND(z)]) # +1
compose_navigators(nav_minus, nav_zero, nav_plus) # ✓
References
- Gay.jl deterministic coloring: https://github.com/bmorphism/Gay.jl
- SplitMix64 seeding: "SplitMix64: A 64-Bit PRNG" - Steele et al.
- GF(3) group theory: "Finite Fields" - Lidl & Niederreiter
- Color topology: music-topos
.ruler/COLOR_TOPOLOGY_FRAMEWORK_MASTER.md