f49af26898
Two units with different jobs: one builds and runs CI, the other is the deployment target. Building on the target architecture makes the glibc constraint structural rather than configured. The remaining risk is version parity between the two units, not architecture. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013kj58Jugkic783b8ZrtTVZ
330 lines
13 KiB
Markdown
330 lines
13 KiB
Markdown
---
|
|
type: reference
|
|
---
|
|
# Repositories
|
|
|
|
## Splitting rule
|
|
|
|
- **`project-yukart`** — overview, roadmap, cross-cutting design. No code, ever.
|
|
- **`orin-nano-env-setup`** — the host: kernel modules, drivers, OS packages,
|
|
device permissions, systemd plumbing. Anything that must be true *before* an
|
|
application starts.
|
|
- **One repo per application or application cluster.** A cluster is a set of
|
|
services that are developed, versioned and deployed together.
|
|
- **Helper/deployment repos** stand alone when they are reusable outside Yukart.
|
|
|
|
Anything cross-repo — topic names, payload schemas, the DBC — belongs in the
|
|
contracts repo, not copied into each consumer.
|
|
|
|
## Current
|
|
|
|
| Repository | Role |
|
|
|---|---|
|
|
| [project-yukart](gitea:yukart/project-yukart) | Hub: overview, roadmap, architecture |
|
|
| [orin-nano-env-setup](gitea:yukart/orin-nano-env-setup) | Jetson host bring-up |
|
|
| [app-flutter](gitea:yukart/app-flutter) | Flutter display client |
|
|
| [contracts](gitea:yukart/contracts) | Topic namespace, payload schemas, signal registry |
|
|
| [svc-gw](gitea:yukart/svc-gw) | Telemetry gateway — aggregation and the HTTP surface |
|
|
| [svc-nav](gitea:yukart/svc-nav) | Navigation service — routing and guidance |
|
|
| [tool-mapmint](gitea:yukart/tool-mapmint) | Map artifact minting, workstation-side |
|
|
| [tool-mock](gitea:yukart/tool-mock) | Mocks and fixtures — a fake car on a workstation |
|
|
|
|
## Planned
|
|
|
|
| Repository | Role | Why separate |
|
|
|---|---|---|
|
|
| `svc-core` | Acquisition + processing cluster: `can-bridge`, `obd-poller`, `gnss`, `decoder`, `recorder` | Developed and deployed as one unit on the Orin |
|
|
| `app-esp32` | ESP32 RLCD/e-ink display firmware (Class B) | Embedded toolchain, flashed not deployed |
|
|
| `tool-analysis` | Offline session analysis, reverse-engineering notebooks | Runs off-car, no runtime coupling |
|
|
|
|
Create these lazily — when there is something to put in them, not before.
|
|
|
|
## Naming
|
|
|
|
Repositories are named `<group>-<thing>`, with **no project prefix**. The `yukart`
|
|
Gitea org already namespaces everything, so a `yukart-` prefix would be a constant
|
|
occupying the most significant characters of every name — pure noise in a sorted
|
|
index, and the reason the earlier scheme scattered.
|
|
|
|
| Group | Meaning |
|
|
|---|---|
|
|
| `svc-` | A service running on the Orin |
|
|
| `app-` | A display client, running off the Orin |
|
|
| `tool-` | Off-car tooling; never deployed to the car |
|
|
|
|
The goal is that **lexical order equals semantic grouping**: opening the org
|
|
listing puts every service together, every client together, every tool together.
|
|
The group segment does that work because it is the first thing that varies.
|
|
|
|
Ungrouped singletons — `contracts` — are fine where a category has exactly one
|
|
member and always will.
|
|
|
|
`project-yukart` and `orin-nano-env-setup` predate this and keep their names
|
|
rather than paying a rename for two repos that are stable and easy to find.
|
|
|
|
### Reusability
|
|
|
|
Nothing in a name marks a repo as reusable. A component that turns out to be
|
|
genuinely reusable outside Yukart **leaves the org** rather than being renamed —
|
|
location says it, not spelling.
|
|
|
|
## Helper and deployment repos
|
|
|
|
Arduino and ESP32 work implies flashing, build and deployment scaffolding that
|
|
is likely to be reused. Keep those generic and outside the org — e.g. an ESP32
|
|
project skeleton with the toolchain, flashing scripts and CI already wired up.
|
|
|
|
### Gitea template repositories
|
|
|
|
Gitea supports these: repo **Settings → Repository → Template**, after which the
|
|
repo offers **"Use this template"** to create new repos from it.
|
|
|
|
Use a template repo for **scaffolding** — a new ESP32 or Arduino project that
|
|
should start with the toolchain, directory layout and flashing scripts in place.
|
|
|
|
Do **not** use one for code you intend to keep updating in one place. Template
|
|
instantiation is a fork-at-create: the copy has no link back, so improvements to
|
|
the template never reach repos already created from it. For genuinely shared
|
|
code, use a git submodule or publish a package instead.
|
|
|
|
Rule of thumb: *template for the starting shape, submodule/package for living
|
|
code.*
|
|
|
|
## Linking convention
|
|
|
|
Cross-repo links use the `gitea:owner/repo` scheme, as established in the hub
|
|
README — e.g. `[Environment setup](gitea:yukart/orin-nano-env-setup)`.
|
|
|
|
## Per-repo document layout
|
|
|
|
Following the convention already set by `orin-nano-env-setup`:
|
|
|
|
```
|
|
README.md minimal portal, points everywhere else
|
|
docs/
|
|
GUIDELINES.md implementation practice for this repo
|
|
BOM.md hardware, where the repo owns hardware
|
|
impl/
|
|
plans/ what is intended
|
|
reports/ what actually happened, and why
|
|
```
|
|
|
|
The `impl/plans` ÷ `impl/reports` split is worth keeping: plans go stale,
|
|
reports do not. A report like `PCAN-SETUP.md` stays valuable precisely because
|
|
it records the investigation and the dead ends, not just the final commands.
|
|
|
|
### Scaffolding conventions
|
|
|
|
Component repos are scaffolded by hand. A template repo is for carrying a real
|
|
toolchain, which is the ESP32 case above.
|
|
|
|
Every component repo carries:
|
|
|
|
```
|
|
README.md the shared blurb, "What this repo is about", then
|
|
links to guidelines and impl/
|
|
docs/GUIDELINES.md numbered sections, ends "## N. To be added"
|
|
docs/impl/plans/ at least INITIAL.md
|
|
docs/impl/reports/
|
|
docs/BOM.md only where the repo owns hardware
|
|
```
|
|
|
|
### Languages
|
|
|
|
| Where | Language | Why it is there |
|
|
|---|---|---|
|
|
| `svc-*` — on the Orin | **Rust** | No GC, low resident memory on a shared 8 GB pool, and fast start for the tier-1 capture services |
|
|
| `tool-*` — off-car | **Python** | Batch work where development speed is the only constraint that binds |
|
|
| `app-flutter` | **Dart** | Flutter |
|
|
|
|
Python floors at **3.10**, the Orin's version, for anything that might run there.
|
|
The workstation has 3.14; do not rely on it.
|
|
|
|
`Cargo.lock` and `pubspec.lock` are committed — these are applications, not
|
|
libraries.
|
|
|
|
#### Building for the Orin
|
|
|
|
Services build **natively on the development Orin**. The sysroot is then the
|
|
target's own, so a binary cannot reference a symbol the car unit lacks — the
|
|
guarantee is structural rather than configured.
|
|
|
|
Two Orin Nanos, and they have different jobs:
|
|
|
|
| Unit | Role |
|
|
|---|---|
|
|
| Development Orin | Build, CI runner, bench testing. Always powered, on the LAN |
|
|
| Car Orin | Deployment target only |
|
|
|
|
⚠ **The guarantee is version parity, not architecture.** An aarch64 binary built
|
|
on a newer userland still fails to load on an older one. A JetPack or Ubuntu
|
|
upgrade applied to one unit and not the other reintroduces the problem, silently
|
|
and only at runtime. **Upgrade both, or neither.**
|
|
|
|
The check that catches drift between them:
|
|
|
|
```bash
|
|
objdump -T <binary> | grep -o 'GLIBC_[0-9.]*' | sort -Vu | tail -1
|
|
```
|
|
|
|
It detects, it does not fix — its job is to fail the build rather than let a bad
|
|
binary reach the car, and to name the symbol that caused it.
|
|
|
|
##### Cross-compiling from the workstation
|
|
|
|
Available as a fallback. Each service repo's `.cargo/config.toml` points at
|
|
`aarch64-linux-gnu-gcc`, from the `gcc-aarch64-linux-gnu` package:
|
|
|
|
```bash
|
|
cargo build --release --target aarch64-unknown-linux-gnu
|
|
```
|
|
|
|
⚠ **The linker binds each symbol to the newest version present in the sysroot**,
|
|
so the workstation's glibc 2.43 sets the floor — not the toolchain, which targets
|
|
2.17. Currently the highest referenced version is 2.34, below the Orin's 2.35,
|
|
because everything above 2.30 comes from one event: glibc 2.34 merged
|
|
`libpthread` and `libdl` into `libc` and re-versioned the moved symbols. Stable,
|
|
but not guaranteed the way a native build is.
|
|
|
|
### Writing style
|
|
|
|
Documents describe **what is and what will be**. They are not changelogs — git
|
|
holds the sequence.
|
|
|
|
| Instead of | Write |
|
|
|---|---|
|
|
| "X was dropped because Y" | what the design **is** |
|
|
| "this was a risk, now resolved" | what runs, and the measurements |
|
|
| "the earlier decision assumed Z" | the current constraint |
|
|
| "X was rejected in favour of Y" | Y, stated as the rule |
|
|
|
|
⚠ **A sentence justifying a current state by a current reason becomes false when
|
|
the reason changes, and nothing announces it** — it stays, confident and
|
|
well-written, and reads as fact.
|
|
|
|
Two things survive the cut, because they stay true when their subject is gone:
|
|
|
|
- **A mechanism that can bite again.** Not "we picked the wrong extract once", but
|
|
"driving side is a country-level property, so a clipped extract routes mirrored".
|
|
- **A condition that would change the decision**, stated generally — "a
|
|
permanently installed, car-powered panel" rather than a story about a panel that
|
|
was considered.
|
|
|
|
Reports under `impl/reports/` are the exception and the place for all of it: the
|
|
investigation, the dead ends, what was measured and found wrong.
|
|
|
|
### Front matter
|
|
|
|
Every markdown document carries front matter, with **no exceptions for the hub or
|
|
for any particular repo**. The `type` discriminates:
|
|
|
|
| `type` | Applies to | Extra fields |
|
|
|---|---|---|
|
|
| `reference` | READMEs, OVERVIEW, ARCHITECTURE, BOM — things that describe what is | — |
|
|
| `guidelines` | `GUIDELINES.md` | — |
|
|
| `plan` | anything under `impl/plans/`, plus `ROADMAP.md` | `status`, `updated` |
|
|
| `report` | anything under `impl/reports/` | `date` |
|
|
|
|
`status` is one of `active`, `superseded` or `done`.
|
|
|
|
`status` and `updated` make a plan's staleness visible — plans go stale and
|
|
reports do not, and without them a plan from months ago reads identically to one
|
|
written this morning. `date` on a report records the moment it describes.
|
|
|
|
## Naming
|
|
|
|
Repositories are named `<group>-<thing>`, with **no project prefix**. The `yukart`
|
|
Gitea org already namespaces everything, so a `yukart-` prefix would be a constant
|
|
occupying the most significant characters of every name — pure noise in a sorted
|
|
index, and the reason the earlier scheme scattered.
|
|
|
|
| Group | Meaning |
|
|
|---|---|
|
|
| `svc-` | A service running on the Orin |
|
|
| `app-` | A display client, running off the Orin |
|
|
| `tool-` | Off-car tooling; never deployed to the car |
|
|
|
|
The goal is that **lexical order equals semantic grouping**: opening the org
|
|
listing puts every service together, every client together, every tool together.
|
|
The group segment does that work because it is the first thing that varies.
|
|
|
|
Ungrouped singletons — `contracts` — are fine where a category has exactly one
|
|
member and always will.
|
|
|
|
`project-yukart` and `orin-nano-env-setup` predate this and keep their names
|
|
rather than paying a rename for two repos that are stable and easy to find.
|
|
|
|
### Reusability
|
|
|
|
Nothing in a name marks a repo as reusable. A component that turns out to be
|
|
genuinely reusable outside Yukart **leaves the org** rather than being renamed —
|
|
location says it, not spelling.
|
|
|
|
## Helper and deployment repos
|
|
|
|
Arduino and ESP32 work implies flashing, build and deployment scaffolding that
|
|
is likely to be reused. Keep those generic and outside the org — e.g. an ESP32
|
|
project skeleton with the toolchain, flashing scripts and CI already wired up.
|
|
|
|
### Gitea template repositories
|
|
|
|
Gitea supports these: repo **Settings → Repository → Template**, after which the
|
|
repo offers **"Use this template"** to create new repos from it.
|
|
|
|
Use a template repo for **scaffolding** — a new ESP32 or Arduino project that
|
|
should start with the toolchain, directory layout and flashing scripts in place.
|
|
|
|
Do **not** use one for code you intend to keep updating in one place. Template
|
|
instantiation is a fork-at-create: the copy has no link back, so improvements to
|
|
the template never reach repos already created from it. For genuinely shared
|
|
code, use a git submodule or publish a package instead.
|
|
|
|
Rule of thumb: *template for the starting shape, submodule/package for living
|
|
code.*
|
|
|
|
## Linking convention
|
|
|
|
Cross-repo links use the `gitea:owner/repo` scheme, as established in the hub
|
|
README — e.g. `[Environment setup](gitea:yukart/orin-nano-env-setup)`.
|
|
|
|
## Per-repo document layout
|
|
|
|
Following the convention already set by `orin-nano-env-setup`:
|
|
|
|
```
|
|
README.md minimal portal, points everywhere else
|
|
docs/
|
|
GUIDELINES.md implementation practice for this repo
|
|
BOM.md hardware, where the repo owns hardware
|
|
impl/
|
|
plans/ what is intended
|
|
reports/ what actually happened, and why
|
|
```
|
|
|
|
The `impl/plans` ÷ `impl/reports` split is worth keeping: plans go stale,
|
|
reports do not. A report like `PCAN-SETUP.md` stays valuable precisely because
|
|
it records the investigation and the dead ends, not just the final commands.
|
|
|
|
### Scaffolding conventions
|
|
|
|
No template repository for this. Template instantiation is fork-at-create, so it
|
|
could not reach the repos that already exist, and the scaffolding is three
|
|
markdown files — lighter than the machinery to manage it. A template earns its
|
|
place where there is a real toolchain to carry, which is the ESP32 case above.
|
|
|
|
What every component repo has instead:
|
|
|
|
```
|
|
README.md frontmatter, the shared blurb, "What this repo is
|
|
about", then links to guidelines and impl/
|
|
docs/GUIDELINES.md frontmatter, numbered sections, ends "## N. To be added"
|
|
docs/impl/plans/ at least INITIAL.md
|
|
docs/impl/reports/
|
|
docs/BOM.md only where the repo owns hardware
|
|
```
|
|
|
|
**Frontmatter follows the document's nature, not its location:** living documents
|
|
carry `type: default`; historical records do not. So README, GUIDELINES, BOM and
|
|
plans have it, and reports do not. The hub carries none at all, being the portal
|
|
rather than a component.
|