Essay 01 · OpenITS · Vikasa2M

From the
cabinet up

Four repositories. One physical world. A walk through the roadside contract that OpenITS is trying to keep.

ben · 2026 02 / 10 written Set in Cormorant + DM Sans.
[The path] ten modules
[How we will learn this]

Not folder by folder.

The four GitHub repos are a cut in the code. The world they describe is older than any of them. We start at the intersection.

  1. The roadside cabinet
    written
  2. Why four repositories
    written · you are here
  3. The common language
    openits-models · YANG
  4. Events on the wire
    CloudEvents · subjects · one type per change
  5. The collector pipeline
    adapter → synth → wire → publish
  6. The hard rules
    never invent state · buffer the past
  7. The NATS geography
    leaf → regional → central → DMZ
  8. Identity and trust
    mTLS · JWT lanes · commands ≠ telemetry
  9. The laptop miniature
    vikasa-demo · three fake DOTs
  10. How the repos pin each other
    so a models change cannot silently rot the demo
path One module at a time.
[Module 01]

The cabinet is the
unit of the world.

Every later idea — YANG, adapters, JetStream, DMZs — exists because of a locked metal box at an intersection.

01 · thesis Start at the roadside.
[Field note] what lives here
[A typical cabinet]

One place. Several vendors. One outbound hop.

A city or state Department of Transportation does not run a traffic app. It runs field infrastructure. The cabinet is the place those devices share: power, a local network, and usually a single unfriendly path back to the Traffic Management Center.

  1. An actuated signal controller (ASC) — Econolite, McCain, and others, speaking NTCIP 1202 over SNMP.
  2. Cameras and traffic sensors — often a different vendor than the lights.
  3. A dynamic message sign (DMS) — NTCIP 1203 — sometimes on the same cabinet network.
  4. A roadside unit (RSU) for vehicle radio — NTCIP 1218, SAE J2735 messages.

The DOT did not buy a stack. They bought an Econolite controller in 2014, cameras in 2019, a sign in 2021. Those boxes will outlive any one software vendor.

01 · inventory Multi-vendor by history, not by design.
[Three nested truths] device · place · polity
device
a vendor, a protocol, a physical state
cabinet
several devices, one network hop off the WAN
agency
a political boundary; sharing is policy, not wiring
01 · scale Software has to keep all three true.
[Bench] stock a cabinet
[Poke this]

Install devices. Then change who owns the intersection.

Same metal box. Two ownership models. The left column is what you bought. The right column is what a consumer can actually use.

devices on the shelf

Buy

main & 5th

Cabinet

empty — click a device
what leaves

Silos

  • nothing installed

Notice: Econolite and McCain are the same kind of device. Without a vendor-neutral layer they still cannot share an ATMS.

01 · bench Same cabinet. Different contract.
[Why this is worse than IoT] three pressures
[The world pushes back]

Devices lie by omission. The WAN dies. Control is not monitoring.

  1. A poll that times out is not “the signal went dark.” It is “we do not know.” Confusing those two is how you get false all-clears.
  2. Cabinets sit behind cellular and NAT. History that happened while the link was down still happened. A command meant for 14:20 must not fire at 20:00.
  3. Changing a timing plan, reading a detector, and rebooting the Pi can share a TCP connection. They cannot share authorization.
01 · pressures The past is evidence. The future is intent.
Without a common layer

Each vendor owns the intersection

Your ATMS speaks Econolite downtown and McCain in the suburbs, plus a third dashboard for the cameras. A mode change exists only in one dialect. A neighbor has no subject to subscribe to.

  1. Two ASCs, two private languages
  2. WAN drop erases or entombs the past
  3. Sharing means joining someone else’s network
What OpenITS is for

A contract leaves the cabinet

Devices still speak their native dialects inside the box. What exits is a versioned vocabulary. Consumers subscribe. A peer DOT is allowed a slice, not a seat on the control plane.

  1. One event type for “mode changed”
  2. Local buffer keeps the past
  3. A DMZ is a political boundary
"

ITS is just IoT with traffic lights.

IoT usually assumes you own the devices and pick the protocol. Here the devices are already installed, already mixed by vendor, and already legally entangled with signal timing. The software does not get to invent the world. It has to describe one.

01 · misread The world was here first.
[Self-check] answer before you peek
[Module 01 · check]

Two ASCs, one city, a neighbor on the corridor.

A city buys Econolite downtown and McCain in the suburbs, plus cameras from a third vendor. What specifically goes wrong if each vendor’s software owns “the intersection”? Which of those problems is political rather than technical?

Technical: even two signal controllers — same function — do not share a language. The ATMS is not “one extra adapter per device type.” It is one extra dialect per vendor of the same type, plus another for every camera and sign. The fix is not a single server the ATMS calls. It is a bus: a collector publishes typed events, and many consumers subscribe.

Political: a neighboring agency is not merely “off the network.” You could VPN them in. You still would not, because that would put a foreign operator on your control plane. Sharing occupancy on a corridor without sharing the ability to change a timing plan is a boundary — later, the DMZ — not a connectivity problem.

01 · check Dialects vs. borders.
[Module 02]

Four clocks.
Not four products.

The GitHub split is where the thing that changes, who may change it, and how often, actually differ. A monorepo looks tidy. Then a YANG revision waits on a cert rotation.

02 · thesis Lifecycle, not org chart.
[The cut] standard · translator · bus · miniature
[Ask of any change]

What would this force me to rebuild?

  1. openits-models — the published vocabulary. YANG is source of truth. Depends on none of the other three.
  2. vikasa-collector — the cabinet translator. Polls native dialects, publishes CloudEvents. Pins a models release. Does not own the bus.
  3. vikasa-infra — the bus factory. Streams, accounts, mTLS, JWT, leaf credentials. Does not deploy the collector. Does not know the models.
  4. vikasa-demo — a miniature of the hops, not a fifth runtime. Fake devices. Real leafnodes. Deliberately pinned behind a models rewrite.
02 · four Infra’s README is load-bearing.
[Bench] where does this change go?
[Poke this]

Pick a change. Watch which repo must move.

Must means the contract or the mapping cannot stay true without it. Smell means the split has failed.

models —
collector —
infra —
demo —

Pick a change.

02 · router Must / may / smell / leave it.
Wrong reflex

The demo is leftover

“Obsolete except as a local sandbox to POC a dashboard.” That treats Grafana as the product and the hops as scenery.

  1. Puts a new OID in the wrong repo
  2. Confuses pitch panels with the contract
  3. Lets you skip WAN-cut and the DMZ
The actual job

Fake devices. Real hops.

cabinet-sim injects CloudEvents once. Every leafnode, cross-domain source, and DMZ subject transform is the real mechanism. The demo is allowed to lie about devices. It is not allowed to lie about the transport.

  1. Three fake DOTs, one shared corridor
  2. WAN-cut still keeps the past
  3. Pinned behind cut-3a on purpose
"

Demo is the real system, shrunk.

Collector is the real translator and is not what the demo runs at the roadside. Infra is the real bus factory; the demo only borrows its renderer. Models is the real contract; the demo is one commit behind a signal-control rewrite. Treating the demo as source of truth is how you learn a frozen snapshot.

02 · misread Wrong clock, not leftover.
[Self-check] answer before you peek
[Module 02 · check]

A new OID, and the dashboard temptation.

A vendor adds a pedestrian-wait OID. Which repo must change, which may, and which changing would be a smell? Why is “just update the demo, that’s where the dashboards are” the wrong reflex?

Must: collector, always — that is who polls the OID. Models, if “pedestrian wait” is not already in the contract. May: demo, only if you are showing that event on the tour and the pin is new enough to have the type. Smell: infra. Streams and certs do not care which OID you polled.

The demo is not obsolete. It is the wrong job. Dashboards there are how you see federation and WAN-cut, not where a new roadside fact enters the system. Putting the OID in the demo teaches a frozen, faked device and never teaches an adapter.

02 · check Wrong job, not leftover.
[Next on the wall]

The common
language.

Why YANG, why many small modules, why everything else in openits-models is generated. The collector is not allowed to invent the vocabulary.

module 03 · not yet written

03 waiting YANG as source of truth.