447c578b6c
/ crosscheck (push) Successful in 1s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DDwfd6Ki8UfG4hK6W5YpJz
56 lines
3.1 KiB
Markdown
56 lines
3.1 KiB
Markdown
---
|
|
type: reference
|
|
---
|
|
# Crosscheck
|
|
|
|
Part of **Project Yukart**, making an old 2008 Mitsubishi Z27AG a bit smarter with modern technologies.
|
|
|
|
Mechanical consistency checks across every yukart repository. A fact stated in
|
|
more than one repo (a decision's status, a topic, a service list, a path in
|
|
another repo's docs) is checked against the one place that owns it. No model,
|
|
no network: plain Python over the tracked files.
|
|
|
|
| Check | Source of truth | Catches |
|
|
|---|---|---|
|
|
| `decision` | project-yukart `docs/ARCHITECTURE.md`, decisions table | a decision number that does not exist; a line calling an Accepted decision proposed |
|
|
| `topic` | contracts `schema/topics.json`, `schema/signals.json` | a `yukart/...` topic matching no pattern; a vehicle, host, gnss or imu signal that is not registered, or has the wrong source |
|
|
| `docref` | the repos' own trees | ``<repo> `FILE.md` `` naming a file that does not exist; relative markdown links that do not resolve |
|
|
| `binaries` | each repo's `Cargo.toml` and `deploy/*.service` | project-yukart `REPOS.md` missing a deployed binary; `ORIN-RUNTIME.md` missing a deployed service |
|
|
| `frontmatter` | the docs convention | a `docs/**/*.md` without front matter, or with an unknown `type` |
|
|
| `copy` | contracts | a file under `assets/contracts/<path>` that is not byte-identical to contracts' `<path>` (or has no source there) |
|
|
|
|
## Run it
|
|
|
|
```bash
|
|
python3 crosscheck.py ~/dev/yukart # the directory holding the repos side by side
|
|
```
|
|
|
|
Findings print as `repo/path:line: [check] message`; exit status 1 if any.
|
|
|
|
## In CI: every repo, on every push
|
|
|
|
`.gitea/workflows/crosscheck.yml` is a reusable workflow. Each yukart repo carries
|
|
[`caller/crosscheck.yml`](caller/crosscheck.yml) as its own
|
|
`.gitea/workflows/crosscheck.yml`. On a push it clones every repo of the org at
|
|
`master`, puts the pushed repo at the pushed commit, and runs the script. A finding
|
|
fails that push's run: the commit that made two repos disagree is the one marked.
|
|
|
|
A new repo is checked as soon as it exists in the org; it needs the caller only to
|
|
trigger checks on its own pushes.
|
|
|
|
- ⚠ **The caller must say `runs-on: halogen`** (the yukart org's runner, `halogen-yukart`). Gitea hands a reusable-workflow
|
|
call to a runner chosen by the *caller's* `runs-on`; the called workflow's own is not
|
|
consulted for that. Without it, the instance-wide `pi5-runner` on the Gitea host takes
|
|
the job, and its jobs see the server as `http://gitea:3000`, which does not resolve.
|
|
- All yukart repos are public, so cloning needs no token. A private one would need a
|
|
read-only org secret `YUKART_READ_TOKEN`, which the workflow already uses if set.
|
|
|
|
## Adding to it
|
|
|
|
- **A false positive** is fixed in the rule, not silenced per line. Shapes that look
|
|
like topics but are not (Flutter channel names, systemd directories) are listed in
|
|
`NOT_TOPIC`; test-only topic roots in `IGNORED_TOPIC_ROOTS`.
|
|
- **A new check** reads a source of truth that already exists in some repo. If the
|
|
fact has no single owner yet, give it one first; a check between two copies only
|
|
says that they differ, not which is right.
|