lantern

oculus-path-resolution

Oculus Path Resolution

The unified addressing scheme for walking the graph. One way to address everything.

The Address Format

The Huntington House Metaphor

Think of addressing like a London townhouse:

Concept Metaphor Address
Node The building Huntington House
Section The floor/apartment Apt 202 (Second Floor)
Fence The resident River, Mr Smith, Ms Piper

Three ways to find River:

# By full address
oculus exec huntington-house:second-floor:2

# By apartment and index  
oculus exec huntington-house:second-floor.python

# By name (global lookup via address book)
oculus exec river

All three resolve to the same person at the same location.

The Isomorphism

These representations are all the same thing:

Layer How River Appears
Markdown ## Second Floor containing ```python[river]
Graph GraphNode.fences[2] with label "river"
CLI oculus exec river
Description "the fence named River at that address"
Metaphor "River lives at Huntington House, Apt 202"

πŸ‹ The Yoneda Lemon: the thing IS its transformations. All views are the same resident.

slug:section.fence_index
slug:section.type
slug:label

Everything resolves to a graph coordinate: {slug, section_index, fence_index}.

Address Components

Component Description Example
slug Node identifier alice-in-wanderland
section Header name (any level) Projects, ⏰ Doing Things
fence_index Zero-based fence position .0, .1, .2
type Fence type suffix .todo, .table, .yaml, .python
label Named alias current-project, my-config

Resolution Rules

  • Slug β†’ Node lookup in registry
  • Section β†’ Walk headers with flexible matching (see below)
  • Fence β†’ Either by index (.0) or by type filter (.todo)
  • Label β†’ Direct lookup that resolves to graph coordinates

Section Matching Strategies

For a header like ## My Tasks [my-tasks], all of these resolve to the same section:

Input Match Type
My Tasks [my-tasks] Full heading (exact)
My Tasks Section name (stripped of label)
my-tasks Label only
my-tasks Kebab-case conversion

Priority: label β†’ stripped name β†’ kebab-case β†’ full heading

Examples

# Get the first fence in "Projects" section
oculus peek alice-in-wanderland:Projects.0

# Get the todo list in "Projects" section  
oculus peek alice-in-wanderland:Projects.todo

# Get fence by label
oculus peek alice-in-wanderland:current-project

# Execute action on virtual fence
oculus exec alice-in-wanderland:Projects.todo toggle 0

All Fence Types Use Same Addressing

The homoiconic property means all fences - code, data, and virtual - share the same address space:

Fence Category Types Addressed Via
Code python, bash, sql slug:section.0 or slug:section.python
Data yaml, json slug:section.0 or slug:section.yaml
Virtual todo-list, table, badge slug:section.0 or slug:section.todo

Operations

All operations accept the same address format:

Operation Description Example
peek Read fence content peek slug:section.0
poke Write fence content poke slug:section.yaml key=value
execute Run/transform fence exec slug:section.todo toggle 0

The Fence Index

The fence index is a lookup table mapping labels to graph coordinates:

{
  "current-project": {
    "slug": "alice-in-wanderland",
    "section_index": 1,
    "fence_index": 0
  }
}

It does NOT store:

  • ❌ File line numbers
  • ❌ Token positions
  • ❌ Raw header text

It stores graph coordinates. Resolution always walks the graph.

Why Unified Addressing Matters

From [[oculus-homoiconicity]]:

"See a thing β†’ have a thing. Want a thing β†’ have a thing."

This only works if there's ONE way to see things. Virtual fences, code fences, data fences - all addressable identically.

Implementation

The unified path resolution lives in path_parser.py. All tools route through it:

  • peek β†’ path_parser.resolve() β†’ graph coordinates β†’ read
  • poke β†’ path_parser.resolve() β†’ graph coordinates β†’ write
  • execute β†’ path_parser.resolve() β†’ graph coordinates β†’ run

Lebowski Corollary

From [[lebowski-corollary]]: The rug is the source of truth. Everything else is opinion.

Applied to fences:

What Role
content The tokens in the file THE RUG 🎳
data Parsed/rendered projection Opinion

The fence index, the virtual fence detection, the rendered output - all derived from content.

When things conflict:

  • Trust content - it's the rug
  • Regenerate data - opinions can be wrong
  • Never cache the rug - always read from source

This is why unified addressing matters: one path to the rug. No parallel systems maintaining their own "truth". The graph coordinates in the fence index? They're pointers to the rug, not copies of it.

Yoneda Application

From [[yoneda-lemon]]: An object is defined by its arrows.

A fence is defined by its transformation, not its storage:

Fence Type content (at rest) β†’ arrow β†’ data (in motion)
YAML/JSON raw string parse dict/list
Code source string execute output
Prose tokens compose rendered text
Virtual tokens render structured data

You don't ask "what is this fence?" You ask "what does this fence produce?"

The unified content + data model captures this: every fence stores what it IS (content) and knows how to produce what it MEANS (data).

North

slots:
- context:
  - Path resolution enables the homoiconic property
  slug: oculus-homoiconicity
- context:
  - Fences are the addressable units
  slug: fence-architecture-pattern
- context:
  - Path resolution enables homoiconicity
  slug: oculus-homoiconicity

South

slots:
- context:
  - The code that implements unified resolution
  slug: path-parser-implementation
- context:
  - Backend interface implements storage for unified addressing scheme
  slug: fence-index-backend-interface

West

slots:
- context:
  - The fence IS its transformations - content→data is the arrow
  slug: yoneda-lemon
- context:
  - Linking path-resolution to trinity
  slug: oculus-trinity

East

slots:
- context:
  - content is the rug (truth), data is opinion (derived)
  slug: lebowski-corollary
- context:
  - Linking path-resolution to cache architecture
  slug: oculus-cache-architecture