Skip to content

ogar-vocab: mint osm_street_node (0x0F0B), the first SYNTHESIZED Geo concept - #268

Merged
AdaWorldAPI merged 2 commits into
mainfrom
claude/q2-osm-map-reencoding-56p5e2
Aug 14, 2026
Merged

AdaWorldAPI merged 2 commits into
mainfrom
claude/q2-osm-map-reencoding-56p5e2

Conversation

@AdaWorldAPI

Copy link
Copy Markdown
Owner

Draft — this is a codebook mint, so it wants a deliberate read before it lands.

What

Adds osm_street_node = 0x0F0B to ogar-vocab (and its ogar-osm re-export), plus a SYNTHESIZED list that names it explicitly.

Why a new concept id, not a new slot

Junction rows already exist and already bake — Berlin 233,053, Brandenburg 590,437 — as plain osm_node. The problem is not capacity, it is that nothing on disk distinguishes "a junction using its edge slots" from "a tagged node using its first tag slot." The reading is ambiguous, and the ambiguity is load-bearing.

osm-soa-bake's street.rs records what that cost. An earlier draft put the edge-name lane at value-local slot 2 and measured 1,084,213 false hits on real Berlin data — one per tagged node, each reinterpreting a node's first tag bytes as eight raw name ordinals. The lane survives today only by hiding at slot 1 (GEO_SLOPE_SLOT), which happens to be the last gap the ordinary tag path never writes.

That gap is now spent. Adjacency, bearing, the turn matrix and speed limits each need slots, and there is no second gap to hide in. A distinct classid makes the layout class-resolved — which is the canon's own answer to this shape of problem ("Tetris it across the slots"), not a workaround for it.

Why SYNTHESIZED

Every other Geo concept mirrors an OSM element. A junction does not: OSM has no junction element, only ways that happen to share a node. The id names something the bake derives, so the list says so in the vocabulary rather than leaving a future reader to infer it from absence. 0x0F0B is otherwise an ordinary Geo-domain concept id.

What this does not do

No consumer wired yet. heading.rs (exit direction + bending) and access.rs (access/oneway/contraflow + the 8×8 Abbiegeverbot mask) are built and unit-tested in openstreetmap-website-rs, but nothing reads them — access.rs says so in its own module docs: "wiring real slot indices from actual junction rows is pending." The slot layout is the next decision and deliberately not made here; given the 1,084,213-false-hit precedent, guessing a slot is exactly the move to avoid.

Blast radius

Additive. A new constant and a new list; no existing id changes value, no reader changes behaviour. Nothing bakes 0x0F0B yet, so no artifact on disk is affected either way.


Generated by Claude Code

…concept

A junction in the routable-way graph earns its own concept id. Not because
the Geo domain was short of ids, but because the substrate has no other way
to say which reading a row's value slots carry.

Junction rows exist today (Berlin 233,053; Brandenburg 590,437) and bake as
plain `osm_node`. That is the problem: nothing on disk distinguishes "a
junction using its edge slots" from "a tagged node using its first tag slot".
osm-soa-bake's street.rs documents what that costs — an earlier draft placed
the edge-name lane at value-local slot 2 and measured 1,084,213 FALSE HITS on
real Berlin data, one per tagged node, each reinterpreting a node's first tag
bytes as eight raw name ordinals. It survives today only by hiding at slot 1,
the last gap the tag path never writes. Adjacency, bearing, turn matrix and
speed need several more slots and there is no second gap. A distinct classid
makes the layout class-resolved, which is the canon's own answer ("Tetris it
across the slots"), and retires the workaround instead of stacking on it.

── The invariant this breaks, deliberately ──

`OSM_CONCEPTS` asserted every Geo concept has a Rails source class. That held
while the domain was a mirror of OSM's schema. It stopped holding when the
bake began SYNTHESIZING junctions: OSM has no junction element, so there is
nothing to ground against, and inventing a Rails name to keep the assertion
green would put a falsehood in the Core.

So the exemption is an explicit `SYNTHESIZED` list, not a relaxed assertion —
membership is a reviewable claim that OSM genuinely has no source element. A
paired check asserts every exempted name IS a concept, so the exemption
cannot silently cover a typo and re-open the hole it was cut for.

── Cross-repo, because the fuses said so ──

Adding a concept moved class_ids::ALL 90 -> 91 and tripped four drift guards,
one of which names its own remedy: "update this pin AND the lance-graph
mirror COUNT_FUSE in the same PR". Both pins, all_promoted_classes(), and the
lance_graph_contract::ogar_codebook mirror move together. Verified: ogar-osm
18/18, ogar-vocab 155/155, and lance-graph-ogar compiles — its COUNT_FUSE is
a compile-time assert, so a half-done mint fails the BUILD, not just tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NMeiLmtDKhomJNSo2ecbJw
@cursor

cursor Bot commented Aug 14, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_32356ff8-fc73-4bb9-bcf4-2e9f331d4de6)

…mised

CI caught the mint landing half-done: `osm_street_node` (0x0F0B) went into
`class_ids::ALL` without a matching `OgarClassView` registry entry, so both
paired invariants failed —

  every_codebook_id_appears_in_class_ids_all
    osm_street_node (0x0f0b) in class_ids::ALL but missing from registry
  known_class_ids_iterates_in_stable_codebook_order
    known_class_ids drifted from codebook order (missing 3851)

which is exactly what that test's own comment says it exists to catch: "a
CODEBOOK promotion landing in OGAR without being added here."

The failure is pointed, given what the mint is FOR. The whole argument for
0x0F0B is that a junction's value slots need a class-resolved reading rather
than a lucky gap in the tag path — and the reading IS the ClassView. An id in
the codebook with no registry entry is an address that resolves to nothing:
the precise defect the mint was meant to remove, reintroduced one layer up.

`osm_street_node()` already existed in ogar-vocab; only the lift was missing.
Added to the import list and to the registry after `osm_user`, matching the
codebook order the second test asserts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NMeiLmtDKhomJNSo2ecbJw
@AdaWorldAPI
AdaWorldAPI marked this pull request as ready for review August 14, 2026 12:53
@AdaWorldAPI
AdaWorldAPI merged commit 70296be into main Aug 14, 2026
1 check passed
@cursor

cursor Bot commented Aug 14, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_9d4c99d5-9cd6-434d-9b5e-309e5bc3aaf8)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants