# Lace-110 · Coordinates and Indexes
Tags: addressing, index, dx

Coordinates are a developer-facing way to name record sets by application
surface. They sit above the record/fact/interlace core: a coordinate is useful
input to `get`, `list`, `store`, selector DSLs, indexes, command-line tools, and
UI displays, but it is not the source of truth. Lace truth remains validated
record bytes, record hashes, record facts, Datalog policy, exchange plans, and
store-machine boundaries.

This document defines coordinate syntax and the raw local index ordering used
before application policy chooses selected versions.

## Defines

Hash addresses, coordinates, surfaces, version selectors, and raw tip ordering.

## URCs have two address forms

A Unified Resource Coordinate (URC) can name an immutable record by hash or name
a coordinate in an application surface:

```text
hash-address = "////" hash-text
coordinate   = "//" group-path "//" app-path "//" name-path [version-selector]
```

Implementations MUST parse hash addresses before coordinate addresses because
`////<hash>` also starts with `//`.

- Hash address: `////<hash>`.
- Coordinate: `//<group-path>//<app-path>//<name-path>`.

Hash addresses are immutable record identifiers. Coordinates resolve through a
local index of validated record facts and may identify many candidate versions.
Applications that need selected truth apply lacegram, exchange-policy, or
application evaluation after candidate discovery.

## Coordinates are not direct store authority

Coordinates may appear in developer APIs such as:

```text
get(target, "//u//ding//links/server-one")
list(target, "//u//ding//links/")
store(target, records, options)
```

Those APIs must still operate through Lace's normal authority boundaries:

- local candidates come from validated record facts exposed by a store machine;
- remote candidates are discovered and transferred through interlace;
- incoming record bytes become local facts only after validation and a typed
  `Record` store operation;
- trusted/direct local routes may use indexes for speed, but still preserve
  store-machine read/load/store boundaries.

A public coordinate API MUST NOT become raw store inspection or mutation. A
runtime or store MAY maintain coordinate indexes internally to answer bounded
store reads and porcelain operations, but applications should receive records
through interlace event streams or operation results, not through unrestricted
store iteration.

## Coordinates identify apps and names

Coordinate terms:

- `group-path`: community, namespace, device, or local scope path, written
  root-to-leaf.
- `app-path`: application or app-defined contract path inside the group.
- `name-path`: app-local hierarchical name.
- `app coordinate`: `//<group-path>//<app-path>//`.
- `coordinate`: `//<group-path>//<app-path>//<name-path>`.

The two `//` field delimiters separate Group from App and App from Name. These
field delimiters are coordinate syntax and are not stored in record `Group`,
`App`, or `Name` headers. Single `/` bytes inside each field are segment
delimiters for that field's path.

A record indexed at a coordinate has record facts whose `Group`, `App`, and `Name`
fields match that coordinate. The index does not make the coordinate authoritative;
it is a materialized view over validated record facts.

## Coordinate syntax is segment-based

Rules:

- `group-path` MUST be one or more slash-separated Group segments as defined by
  010;
- `app-path` MUST be one or more slash-separated App segments as defined by 010;
- `name-path` MUST be one or more slash-separated Name segments as defined by 010;
- a coordinate MUST contain exactly two `//` field delimiters after the leading
  `//` coordinate marker;
- no coordinate field may be empty, start or end with `/`, or contain an empty
  segment;
- `|` is forbidden in Group, App, and Name segments, so `/|/` unambiguously starts
  version selection after the Name path.

Examples:

| Coordinate | Group | App | Name |
|---|---|---|---|
| `//u//docs//index.html` | `u` | `docs` | `index.html` |
| `//u//ding//links/server-one` | `u` | `ding` | `links/server-one` |
| `//eu/lab//chat/message//room-7/1` | `eu/lab` | `chat/message` | `room-7/1` |
| `//eu/lab//chat//message/room-7/1` | `eu/lab` | `chat` | `message/room-7/1` |
| `//eu/lab/research//forum//post/2026/06/14/1` | `eu/lab/research` | `forum` | `post/2026/06/14/1` |

Malformed examples:

- `//g////key` has empty App.
- `//g//api//` has empty Name.
- `//g//api//key//extra` has an extra field delimiter inside Name.
- `//g//bad//api//key` has too many field delimiters.
- `//g/..//api//key` has an invalid Group segment.

## Prefixes are selector input, not record addresses

Developer surfaces often need a coordinate prefix, such as all record names under
`//u//ding//links/`. A prefix is not an exact coordinate and not a record address.
It is selector input that compiles to policy over `Field(P,'Group',...)`,
`Field(P,'App',...)`, and `Field(P,'Name',...)` facts, possibly with string-shape
or path-prefix predicates.

For example, a first-follow style selector for `//u//ding//links/` becomes policy
that selects records with:

```text
Field(P, 'Group', _, 'u')
Field(P, 'App',   _, 'ding')
Field(P, 'Name',   _, K)
TextShape(K, 'links/', '', '')
```

The exact lowered lacegram is an implementation detail of the selector DSL, but
it must preserve the same query-view and store-machine boundaries as a
hand-written policy.

## Version selectors choose record versions

A top coordinate has no version selector and resolves to the raw coordinate tip
when a raw tip is needed. A version-selector coordinate includes `/|/...` and may
select a narrower version set or one exact record.

Common forms:

| Coordinate form | Meaning |
|---|---|
| `//g//a//k` | raw coordinate tip candidate |
| `//g//a//k/|/plex/<tai>/<hash>` | exact Plex record version |
| `//g//a//k/|/seal/<verifier>/<tai>/<hash>` | exact Seal record version |

The raw local index tip is highest `TAI`, then highest hash. This raw tip rule is
only deterministic candidate ordering. It does not replace lacegram, exchange
policy, query-view rules, signature/application authority, or interlace
convergence.

## Coordinates in event streams and porcelain

Interlace event streams are record/lifecycle streams. They report records,
record hashes, completion, fixed points, closure, and errors. They should not
report coordinate-index internals as normal events.

Porcelain may accept coordinates or prefixes as friendly inputs and may include
the requested coordinate in an operation result for correlation. The operation's
observable record results must still be records selected by policy and persisted
through store machines. A duplicate save, policy-refused or invalid input record,
stale scope, or incomplete result is reported as an operation outcome, not as a
coordinate-index mutation event.

## Direction

Coordinates make Lace easier to use, search, display, and debug. They remain a
layer above core truth. When in doubt, expose coordinates as inputs to policy and
porcelain, keep raw indexes store/runtime-internal, and let interlace event
streams expose record/lifecycle outcomes.
